How to animate the moon with the canvas element
Tags: javascript, tutorial, hacktoberfest, html
Published: 2021-10-11 03:29:42

For [Hacktoberfest](https://hacktoberfest.digitalocean.com/) this year, I contributed to a [project](https://github.com/zero-to-mastery/Canvaz) using the `<canvas>` element. I was intrigued, as I'd come across it before while I was learning HTML but always thought "Eh, I'll get to that one day...".
##What is the `<canvas>` element?
It's an HTML element that gives you the ability to draw with JavaScript. Pretty neat. It takes whatever `id` and dimensions you'd like as attributes, and wraps around a backup image which only displays if your drawing doesn't load:
![The canvas element embedded in the body element](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8kj2ajxbqy1szqkle01l.png)
##How to animate the moon
You don't have to animate the `<canvas>` element but I thought it'd be a nice challenge. I decided to create a [waxing and waning moon animation](https://gabriellend.github.io/moon-animation/). **My approach was to write a function for each phase and loop through them using `setTimeout()`.**
###Lay the foundation
Before anything else, **every `<canvas>` element must start with two things:**
![The code to initialize the canvas element](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2rp6vqz6kkfaaammd6or.png)
First, we select the `<canvas>` element in the HTML with its `id` and save it in a variable. Second, we create a variable for the *context*. This is what we actually draw on. Surprise! The `<canvas>` element itself is really just a container. This context variable is what we will use in our functions.
###Initialize
I chose a crescent moon as my starting phase. I drew it with a function called `init()` and added it as an attribute to the `<body>` element we saw before, so that it's called when the page loads.
![Shows the body element with the "onload" attribute](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o376xtyns2ge9g6jg1r8.png)
![Shows the "init" function](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ve327qe6gfuve7fryr2a.png)
![Crescent moon phase with corresponding code](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/be6f2s3xeeambr9vqynk.png)
###Repeat with slight variations
I ended up with six very similar functions, so similar that I won't detail each of them here:
1. init()
2. quarterMoon()
3. halfMoon()
4. fullMoon()
5. halfMoonWane()
6. quarterMoonWane()

**Each function calls the next one and `quarterMoonWane()` calls `init()`. That is how the continuous wax/wane effect is achieved.** The only differences are the inner(bezier) and outer(arc) curves of each phase. Really it's only four functions, as `quarterMoon()` and `halfMoon()` are basically equivalent to `quarterMoonWane()` and `halfMoonWane()`. I repeated them because during the waning phase I needed the same shapes but different `setTimeout()` function calls.
##Challenges and reflections
The `<canvas>` element is no joke. I spent two days working out how to achieve this animation. Granted, it was my first try and I had to do a lot of research and trial and error with tricky math, but it's still a challenging element to work with. Even though I'm glad I got acquainted with it, I can't really think of a situation where I'd want to use it again.

One of the hardest things about it is that **you can't see your progress unless you call a method to connect the points you've established** (I used `ctx.fill()` here, you can use `ctx.stroke()` to draw a line instead). It was cumbersome doing that after every line and then deleting them all(except the last one) once I knew what was happening. It makes me wonder if there is an easier way.

**I also really wanted the transition between each stage to be a little smoother.** I tried speeding up the intervals on `setTimeout()` but that didn't give me the effect I was hoping for. I also experimented with `window.requestAnimationFrame()`, another method used with `<canvas>`, but that made it way too fast by itself. I'm sure there is a way to make it work but I wasn't able to find it after much searching and experimenting. 

Finally, since there is a lot of repeated code here, I'm sure there is a more elegant way of achieving this type of animation but in the end it gets the job done and I'm a fan!

[Here's](https://www.w3schools.com/html/html5_canvas.asp) a resource for more info on the `<canvas>` element and, as always, [here's my code](https://github.com/gabriellend/moon-animation) if you'd like to inspect in more detail.