Last week in our festive coding challenge, we explored how to code a sliding puzzle toy with some of the latest front-end techniques to grace the developer’s tool kit. But with Christmas drawing ever nearer, we thought it was time to up the ante with a ‘build your own emoji tree’ creation from front-end developer Kate. You can have a play below (or on CodePen). But do tweet us with your tree designs, @simpleweb, we’d love to see them!

If you want to build one yourself, stick around for our second festive tutorial from Kate below.

See the Pen Tree Decorator by Kate Howard (@KateH2) on CodePen.

Here is the seasonal story of how the tree came to be:

The Original Tree🌲

First of all, I created a basic tree in Sketch, exported it as an SVG and used the code from that. As you can see it’s comprised of four overlapping, mathematically beautiful right-angled triangles (polygons), and a rect for the trunk. Later, I added a few shadows to each triangle to make it look marginally more realistic, so this code did get a bit more complex.

Tree Topper Selector ⭐

I started off the customisation by controlling something simple – the decoration to sit at the top of the tree. Traditionally, this is either a star or an angel, although the Apple angel emoji is a quite creepy baby with wings but no body, so that’s why a star is the default. When a different option is selected, the handleChange function sets that as the textContent of the topSelector div. Easy!

Add Present 🎁

In a similar vein, I added an event listener to a button labelled “Add present”, which adds a present emoji to the textContent of the present container (making sure to set its width to match that of the tree, or it all ends up a mess).

Baubles✨

Time to make things a bit more interesting. I went back to Sketch to add baubles on each branch, then set about letting the user change their colour. This was done with custom CSS properties, which are set on the root element with the prefix --

…referenced in the fill attribute for each bauble using the var() function…

…and controlled via the values of a couple of colour pickers with ‘change’ event listeners.

Decorations🔔

Once it was 3D the tree called out for more decorations. I added a ‘click’ event listener to the tree itself that adds a div to the DOM, setting its top and left values according to the coordinates of the MouseEvent (e.clientX and e.clientY). Its textContent is set to the value of a select element, filled with an increasingly wide variety of emojis that vaguely resemble Christmas ornaments.

Being absolutely positioned, the decorations didn’t really work when the browser got resized. I sneakily solved this problem by moving the tree into the top left, after an embarrassingly long time trying to add new SVG text elements to the tree instead.

When I came to add lights (i.e. yellow circle s) I worked out the trick behind this, which wasn’t all that difficult:

const light = document.createElementNS("http://www.w3.org/2000/svg", 'circle'); rather than const light = document.createElement('circle');

Twinkly lights💡

Next, I wanted to make the lights twinkly. This was done with a function that changes the radius of each one every 500 milliseconds, selecting a random number of pixels between 1 and 2.

Let it snow ☃️

Next, for some reason, I decided it was a good idea to conjure up JavaScript snow, using a “Let it snow! ❄️” button to call letItSnow(), which includes two nested functions, createFlake() and snowfall().

createFlake() creates an absolutely positioned <div> which starts off with its top property set to 0px, and left set to a random number within the width of the screen. snowfall() increases the top value by 1px at a random interval, so each one falls down the screen at its own speed.

This was lovely but as the flakes kept falling forever it made my laptop whir quite a lot, so I made each flake remove itself from the DOM when its top exceeded the height of the tree. This led to a few simple styling changes to add some snowy ground (a white div with a width of 100%), and a limit on the number of presents in the present container, so they wouldn’t look silly with snow disappearing halfway down them.

As the processing power usage still sounded excessive I set about making it possible to stop new snow being created. Originally this was with the same button, which toggled its textContent from “Let it snow! ❄️” to “Stop, it’s too snowy 🌨️” when clicked, and used this textContent value to determine what function to perform. This all got horribly confusing and led me to look into various solutions, such as a simple return; to exit the letItSnow() function, and custom errors with a throw statement.

None of this worked, and what I had missed was that the two buttons have to do two separate, but quite simple, things – letItSnow() (set an interval on createFlake()) and stopSnow() (clear that interval). This was also much easier once they were actually two different buttons (which each toggle the other to display: none;, so they appear to be the same button). Crucially, they do both need to refer to snowing, the value returned by setting the interval, so I had to set snowing = null in global scope.

Cat Button 🐈

At the request of a colleague I added a cat into the mix, which knocks decorations off. The suggestion was actually to throw a cat into the tree, but I thought that was a bit too ambitious and cruel.

 

Tinsel🎄

To make tinsel I used SVG path elements, created by mousedown and mouseup events set on the tree while tinsel is selected in the decoration selector. The d attribute for each of them is set to four coordinates: M (the start of the tinsel) has the coordinates of the mousedown event (with some maths to account for margins), and C (Bezier curve) has the coordinates of a spot 18px below the start point, followed by 18px below the end point, then the end point itself, which is where the mouseup event occurred.

The two lower points make the path curve downwards slightly. A better explanation can be found here.

It could look a bit more like tinsel, and also doesn’t really work if someone tries to break it by swiping vertically rather than straight across the tree, but it was quite interesting to work out.

 

This was a fun festive challenge, and great practice for working with CSS and vanilla JavaScript (especially as I’ve got so used to React (/Native) that I nearly forgot how to do event listeners). I also learnt a lot about SVGs, which have always kind of scared me, and hopefully I’ll stay motivated to continue exploring these whenever I run out of good films to watch over the holidays.

If you’d like to discuss your startup or project, get in touch with Simpleweb today.

Related Stories