This post is from the talented brunoimbrizi, if you're interested in posting, you can open up a proposal, just like he did!
In this tutorial, we are going to recreate the look of a print by Accept & Proceed called Hours of Dark 2011. All the strokes in the grid represent a day, their width proportional to the hours of darkness and their orientation defined by the angle of the sunset.
Here is our initial setup with a single <canvas>
element, using window.devicePixelRatio
to scale it on retina screens.


We need a few variables to describe the grid. First, the number of strokes which is the same as the number of days in a nonleap year. Then the number of columns and rows, just enough to pack 365 cells in the grid. In this case 23×16 = 368, so the last 3 cells will be blank.


We also need variables to define the dimensions of the grid, which has a landscape aspect. And from that we can calculate the dimensions of each cell and the top and left margins.


Now we have enough to start drawing the strokes. We are going to loop over days
column by column, so first, all the rows in the first column, then all the rows in the second column and so on.
x
and y
depend on the margins and on the cell dimensions. The width and height of each stroke (w
, h
) are arbitrary values which look right for the size of our canvas on the page. The rectangles are drawn from the centre, so this will be their anchor point when we rotate them later.


At this point, the grid is a bit offset to the left and to the top, and this is because x
and y
are the topleft of each cell. So we need one more call to translate
to place the origin at the centre of the cell. These separate calls will come in handy later.


Now we need to calculate the rotation. In the original calendar, the authors used data from the angle of the sunset (known as the Azimuth) to determine the orientation of the lines. Luckily for us, we can get pretty close with a sine curve, thanks to the smooth wobble of our planet.
The trick here is to use two angles.
The first one phi
determines the range of rotation in a year, which is between 0 and Π.
The second one theta
modulates the first one with a sine curve, so instead of rotating a full 180°, it eases in and out of the first half of that angle and then eases back into 0°.


To match the look, we need to nudge the inital angle. We also need to adjust the rotation range so it’s a little bit less than 90°.


The thickness of the strokes is proportional to the hours of darkness in each day. Again, we can get away with a good approximation using a cosine curve.


The last step is to apply a clipping mask so each stroke is only drawn inside its cell. This is where our separate calls to translate
come in handy, so we need to insert the next chunk of code in between those calls.


And there we have it! Simple and elegant. A beautiful piece of data visualisation from Accept & Proceed which we managed to recreate with some sine and cosine curves.