ARTLUNG
personal website: joe crawford. code. occasional comics. toy robots. bodysurfing. san diego. california. say hi.
since 1998

Quote of the Day, on Martin Luther King

from Tony Pierce

mlk makes me think you can do everything you can and it still wont change some people.

which is a good thing to realize quickly.

that way you dont waste your time doing things to change people.

instead you should do things

because theyre awesome,

and maybe youre the best person to do them.

Drawing with CSS: Cube Cat

I have seen extraordinary things made with HTML and CSS. I remember in 2003 seeing the CSS Zen Garden (though it was hosted on mezzoblue at the time). Nearly 20 years later and CSS remains an incredible tool, only more extraordinarily powerful with each passing week, each new spec, each new browser release.

For several years I took note of incredible projects where people used CSS to draw. Looking at the markup, I was daunted. So much code! So many elements! I wanted do do it myself but never took the time to do so.

I started making computer graphics on a TI-99/4a in the 1980s by drawing on graph paper and turning those shapes into code. At the time it was grids of pixels 8×8, each representing a custom character. Add enough of those characters up and I could make a drawing. Pixel by pixel, displayed on a 12″ black and white cathode ray tube television. I wrote about this in 2019 in my post CALL CHAR().

If kid Joe can do it, adult Joe can too. I was thinking of using my character Cube Cat–of whom I’ve been sketching and making comics about for several years.

I started with drawings. First rough:

And then on graph paper:

This past week, off and on, I’ve been learning how to do it, one piece at a time. Many fits and starts. I learned about tools like the CSS property clip-path which can take a polygon as a value. This is a triangle: polygon(26% 0, 0% 100%, 100% 100%);, and here’s an oval: ellipse(50% 28% at 50% 50%);. I used the Clippy tool to learn about that. It is a simple and useful tool to explore the available shapes. A complicated polygon is how I made Cube’s cowlick, which has 12 points. I tried a lot of things that didn’t work out. To do the “freckles” (more like whiskers but Cube Cat, as an anthropomorphized creature has some odd anatomy). I tried to use display: flex to organize those dots but ultimately it was easier to place them with position: absolute. I have avoided CSS variables (aka CSS custom properties) but I used some here. Codepen lets me used SASS and I could have done that, but what’s a learning exercise if you don’t try new things? I knew I’d be using border-radius and box-shadow, which worked well. And I used z-index more than I expected to maybe. I thought I’d rotate squares to create the collar but alignment became somewhat difficult using CSS rotate() function, in the end, that also ended up a polygon. I considered doing my signature with a polygon but I did end up using an image for that, altering the opacity just a bit with CSS.

All along I used MDN’s CSS documents as well as canIUse, which documents browser support for this custom stuff.

Frank Zappa, when a piece of music was unfinished, talked about “putting the eyebrows on it.” That is, creating the final textures that for good or bad, make the piece done. And so, here’s the final result:

I am even more impressed by folks who do this kind of painstaking creative work in CSS now that I’ve created one myself. I can see why they do it though, it’s a lot of fun!

View it, and even edit it, on codepen

Spielberg’s Films by year of release vs year set

The other day, over on twitter, Todd Vaziri sent a lazyweb request that piqued my interest:

free cinema chart idea

chart the films of steven spielberg and graph the release date minus the year the film takes place

you know, for fun

How does one do timelines these days anyway? I had a vague memory that Google had a tool in their charting APIs.

And they do: Timelines are a feature of Google Charts! Not too hard to set up, really. But I needed the data first. So I started a spreadsheet and started searching Wikipedia and IMDB. I added year of release, and my best guesses as to the year of setting. I also made a distinction for movies set in one period but with an epilogue or prologue in another year (e.g. Schindler’s List and Saving Private Ryan). I didn’t end up using that distinction as it didn’t have much effect on the chart.

I decided the end points would quite naturally be the average year of the setting year of the film and the year of the film’s release. Start point would be whichever was sooner. For colors I chose a shade of red (#b94e48) and for science fiction I chose a green (#8bbe1b)

I rather like the result:

My “client” responded to it favorably:

WOW!

The essence of my question was ‘how many period pictures has SS done’ and it looks like A LOT!

To work it out I used the estimable Codepen, which is terrific for working out small or medium sized web tasks. You can play with it yourself at codepen.io/artlung/pen/JjrmEgP

var futureColor = "#8bbe1b";
var pastColor = "#b94e48";
var nowColor = "#000000";
var epilogueColor = "#cccccc";

google.charts.load("current", { packages: ["timeline"] });
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
	var container = document.getElementById("spielberg-timeline");
	var chart = new google.visualization.Timeline(container);
	var dataTable = new google.visualization.DataTable();

	var rawdata = [
		[1964, 1964, 1964, false, "Firelight"],
		[1971, 1971, 1971, false, "Duel"],
		[1973, 1922, 1922, false, "Ace Eli and Rodger of the Skies"],
		[1974, 1964, 1964, false, "The Sugarland Express"],
		[1975, 1975, 1975, false, "Jaws"],
		[1977, 1977, 1977, false, "Close Encounters of the Third Kind"],
		[1979, 1941, 1941, false, "1941"],
		[1981, 1936, 1936, false, "Raiders of the Lost Ark"],
		[1982, 1982, 1982, false, "E.T. the Extra-Terrestrial"],
		[1982, 1982, 1982, false, "Poltergeist"],
		[1983, 1983, 1983, false, "Twilight Zone: The Movie"],
		[1984, 1935, 1935, false, "Indiana Jones and the Temple of Doom"],
		[1985, 1900, 1916, false, "The Color Purple"],
		[1985, 1985, 1985, false, "The Goonies"],
		[1987, 1941, 1945, false, "Empire of the Sun"],
		[1989, 1912, 1938, false, "Indiana Jones and the Last Crusade"],
		[1989, 1989, 1989, false, "Always"],
		[1991, 1991, 1991, false, "Hook"],
		[1993, 1993, 1993, false, "Jurassic Park"],
		[1993, 1939, 1945, 1993, "Schindler's List"],
		[1997, 1997, 1997, false, "The Lost World: Jurassic Park"],
		[1997, 1839, 1841, false, "Amistad"],
		[1998, 1944, 1944, 1999, "Saving Private Ryan"],
		[2001, 2150, 4150, false, "A.I. Artificial Intelligence"],
		[2002, 2054, 2054, false, "Minority Report"],
		[2002, 1963, 1967, false, "Catch Me If You Can"],
		[2004, 2004, 2005, false, "The Terminal"],
		[2005, 2005, 2005, false, "War of the Worlds"],
		[2005, 1972, 1975, false, "Munich"],
		[
			2008,
			1957,
			1958,
			false,
			"Indiana Jones and the Kingdom of the Crystal Skull"
		],
		[2011, 1949, 1949, false, "The Adventures of Tintin"],
		[2011, 1912, 1918, false, "War Horse"],
		[2012, 1865, 1865, false, "Lincoln"],
		[2015, 1957, 1960, false, "Bridge of Spies"],
		[2016, 1982, 1982, false, "The BFG"],
		[2017, 1966, 1971, false, "The Post"],
		[2018, 2045, 2045, false, "Ready Player One"],
		[2021, 1960, 1960, false, "West Side Story"]
	];

	var massaged_data = [];
	dataTable.addColumn({ type: "string", id: "Movie Year" });
	dataTable.addColumn({ type: "string", id: "Movie Title" });
	dataTable.addColumn({ type: "string", role: "tooltip" });
	dataTable.addColumn({ type: "date", id: "SettingStart" });
	dataTable.addColumn({ type: "date", id: "SettingEnd" });
	var colors = [];

	for (var i = 0; i < rawdata.length; i++) { 
		var movie = rawdata[I];
		var averageSetYear = (movie[1] + movie[2]) / 2;
		var madeYear = movie[0];
		var startYear = 0;
		var endYear = 0;
		var tooltip = [movie[4], "was made in", movie[0]].join(" ");
		var epilogueYear = movie[3]; // future if (averageSetYear > madeYear) {
		colors.push(futureColor);
		startYear = madeYear;
		endYear = averageSetYear;
	} else if (averageSetYear < madeYear) {
		colors.push(pastColor);
		startYear = averageSetYear;
		endYear = madeYear;
	} else {
		colors.push(nowColor);
		startYear = madeYear;
		endYear = averageSetYear;
	}

	var movieYearStart = movie[1];
	var movieYearEnd = movie[2];
	var epilogueYear = movie[3];

	if (movieYearStart == movieYearEnd) {
		tooltip += " It is set in " + movieYearStart + ".";
	} else {
		tooltip += " It is set from " + movieYearStart + " to " + movieYearEnd + ".";
	}
	if (epilogueYear) {
		tooltip += " It has an epilogue set in " + epilogueYear + ".";
	}
	massaged_data.push([
		String(i + 1),
		movie[4],
		tooltip,
		new Date(startYear, 1, 1),
		new Date(endYear, 1, 1)
		]);
	}
	dataTable.addRows(massaged_data);

	var options = {
		colors: colors,
		alternatingRowStyle: false,
		avoidOverlappingGridLines: false
	};

	chart.draw(dataTable, options);
}