All Articles

A Birthday Card for Pandemic Times

Let’s say you are trying to put together a special birthday for someone, but it’s hard because the world is in the middle of a pandemic so you can’t gather all of your friends to celebrate a birthday. You can’t even pass around a birthday card and have everyone sign it without mailing it to a bunch of places! Here’s a wacky solution I came up with back in May and I thought I’d write about it since I do like wacky things.

How about a virtual birthday card?

Picture of a virtual birthday card

I had all of the birthday boy’s friends doodle a little picture of themselves with a picture of a gift that they would give him. The nice part was that since these were just drawings of gifts and not real gifts they had to buy, the gifts could get really creative. There were drawings ranging from a basket of cats to rare sneakers to the ability to have arms the size of Andre Iguodala’s. With the doodle, I also asked everybody to include a short birthday message.

The image itself can be put together in any image editing tool. It was just a lot of removing backgrounds and laying out people’s drawings until it seemed to look pretty good. I used Procreate because I already had that on my iPad, but MS Paint would also do nicely.

My goal was for the birthday boy to be able to hover over each of his friends’ doodles and see what message they sent him. It seemed to me like D3.js would be a good option to do this, where I would create a JSON data file with the coordinates of all of the doodles. Then, I’d use D3 to draw invisible rectangles on each of the doodles and give them a mouseOver function, so when someone hovers over it, a tooltip would pop up with the birthday message in it. The most difficult part of this was getting the coordinates of each image, but that’s mostly just a tedious task.

Debug mode to see the rectangle coordinates around each doodle

I added a debug mode to my JavaScript which puts a red border around these invisible rectangles. I also added some extra console log statements so I could mouseover anywhere on the screen and get the coordinates, then jot those coordinates down in my data file.

My data file ended up looking like this:

[
  {
    "name": "Peach",
    "message": "Meow... I won't bite the recycling box today... meowbe...",
    "start": [770, 847],
    "end": [1107, 947]
  },
  {
    "name": "Alan",
    "message": "To many more mother/daughter combos in the years to come! <br><div class='gallery'> <image src='assets/alan.png' width='200', height='150'/></div>",
    "start": [156, 258],
    "end": [336, 406]
  }
  ...
]

The message field I allowed to actually take HTML too since some friends wanted to add pictures to their message. This is safe enough since only I was editing the file, but if you were allowing user input it could be dangerous.

With all of the data set, the code becomes quite simple.

// read in the data
d3.json("assets/data.json").then((data) => {
  // add a rect for every doodle
  svg
    .selectAll("rect")
    .data(data)
    .enter()
    .append("rect")
    .attr("x", (d) => d.start[0] - margin)
    .attr("y", (d) => d.start[1] - margin)
    .attr("width", (d) => d.end[0] - d.start[0])
    .attr("height", (d) => d.end[1] - d.start[1])
    // make the rect invisible
    .style("fill", "white")
    .style("fill-opacity", "0")
    // if debug mode, add the red border
    .style("stroke", () => (debug ? "red" : "none"))
    // when this doodle is moused over, show the tooltip with the message
    .on("mouseover", (d) =>
      tooltip
        .style("visibility", "visible")
        .html(`<p>${d.message}</p><p>${d.sign ? d.sign : `— ${d.name}`}</p>`)
    )
    // move the tooltip with the mouse
    .on("mousemove", () => {
      tooltip
        .style("top", d3.event.pageY - 10 + "px")
        .style("left", d3.event.pageX + 10 + "px");
    })
    // close the tooltip when we exit the doodle space
    .on("mouseout", () => {
      tooltip.style("visibility", "hidden");
    });
});

And that’s it! The full code lives in this repo and the live card lives here. I didn’t put much effort into the tooltip styling but I think it gets the birthday festivities feel across.