d3 Advent Calendar

, , Leave a comment

I do a different Advent Calendar every year. The skills I use vary with my mood, the time or the privacy I have. One year I made it in a shoe box, with 24 small doors and separators in the box to hide my small gifts (lots of privacy prior December); another year I used a big 50 pages notebook to hide a gift between two pages (so it was portable!); and once just a different piece of chocolate every day (no privacy and no time). 10 years ago, I had made one in HTML and PHP: it was just a large image, some squares were clickable which depended on the date and linked to images, videos or sound.
This year I decided to go back to this and to up a bit my game: the calendar itself is made in d3, and everyday I aim to learning a new thing about programming on the web. I didn’t have the time to make it ahead this year, so I do it as a challenge a day.
I usually construct an Advent Calendar considering three things: how it will look, how the gifts are discovered every day, and what gifts are possible. It’s difficult to get 24 completely different gifts, so it’s often just a case of reusing the concept, changing only one attribute (e.g. dark chocolate on the 5th but white chocolate on the 14th is acceptable).

Basic functions

Inspired by my recent word cloud, I decided to modify it to show the days, adding a Christmas feel to it.


The data I fed my cloud with is a simple list with all the numbers from 1 to 24. Since what matters in an Advent Calendar is the ‘difficulty’ in finding the new date, I decided to use a random function for the size of the number.

function getDates(i) {
  var frequency_list = [];
  for (var i = 0; i < dates.length; i++) {
      var temp = dates[i];
          text : temp,
          freq : 10 + Math.random() * 60
  return frequency_list;

I also kept the updating function, every 2000s.

function shownewdate(vis, i) {
    i = i || 0;
    vis.update(getDates(i ++ % dates.length));
    setTimeout(function() { shownewdate(vis, i + 1)}, 2000);

The background

The real difficulty here was actually to create the background. I had never drawn raw figures in svg, beyond more than one piece of svg at a time. At first I wanted to create a word cloud in a shape of a Christmas tree, but then decided it would be more interesting to simply have the dates moving in front of the tree since I was restricted to only 24 dates. I eventually managed to draw a tree in svg, and to display the numbers on top.


In all my serious project so far I’ve used Bootstrap. This time I wanted to use another framework, and picked Bulma. It looks like a nice framework, a welcomed change from Boostrap!

Javascript only?

I’m also trying to use only Javascript. I’ve relied a lot on jQuery, so it’s interesting to try not using it when possible.

The gifts

Grabbing the gifts

To mimic the basic functionality of an Advent Calendar, I made the numbers as links. It’s very easy in d3 to do so with .on("click, function(){}). However, I wanted to restrict the days that could be opened, so my code compares the date of the day and the number clicked. If it’s before the date of the day, then it opens a new tab. Otherwise it shows a div that contains a message saying it’s not possible to open it. The message disappears after 2000s, otherwise it made it difficult to see it was a new message when clicking twice on a wrong link.

var today = new Date();
var dd = today.getDate();
.on("click", function(d) {
                if(parseInt(d.text) <= dd){
                    // open in a new window if the number clicked is before the date
                     window.open("gifts/"+ d.text +".html");
                } else {
// if it's not possible to open, show a div with the id 'failed'
                    var ele = document.getElementById('failed');
                    ele.style.display = 'block';
                    // hide the div after 2000s
                        ele.style.display = 'none';
                    }, 2000);

The gits

I’ve only done 8 gifts so far.. but I’ve tried to keep it different. I’ll keep writing about them in the near future!