Creating a Radio Using HTML Canvases

December 20, 2020

Approximately 4 minute read time.

Hey everyone! It’s been a solid month since my last post, but I’m back again, and this time I want to focus on finishing up that crappy little radio we made last time. For context, here is what I left off with from this post.

This little project started out as a submission for a programming competition, where I had to use 32 lines of code to make… Something, anything. But now that the competition is over, I can make this little project of mine whole with more code, specifically with CSS to draw a little radio on the screen, and some more JavaScript to make this project a little more robust than it is.

But before we add play and pause functionality, we need to actually render something that resembles a radio. While it might not actually be a radio, I’m going to try to render something that looks like ACNH’s Tape Deck, because I like the way it looks.

Drawing a Radio

First, I need to draw a radio. Most people would likely just… Draw one in Paint, Gimp, or their other favorite image manipulation program. However, this is a coding blog, and drawing a .png file doesn’t require writing any code, so instead we’re going to use a HTML canvas element, which are really cool little elements you can use to draw things with using JavaScript.

This was pretty tough for me to do because I didn’t fully know what methods were available to me in order to be able to draw the radio. I mostly needed to be able to draw shapes, but for the face of the radio I also wanted it to have some textures. I decided to go ahead and start with a box for the body of the radio. In order to do this I need a canvas:

<canvas id="radio" width="500px" height="300px"></canvas>

Easy. Now, I want to draw a box representing the body of the radio. In order to do that, I have to get the 2-dimensional context from the canvas and start drawing shapes:

const canvas = document.getElementById('radio');
const ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.fillStyle = '#ddd';
ctx.fillRect(25, 50, 450, 250);

The code gets a little bit boring from here. It’s mostly repeating setting the fillStyle property and calling fillRect to draw most of the body. I also drew a couple of circles by calling the arc function to create a tape deck looking box, but the circle-drawing code is a little different. fillRect draws rectangles and fills them in with a pattern or solid color, whereas arcs can be drawn differently depending on whether or not you call fill or stroke:

ctx.beginPath();
ctx.fillStyle = '#aaa';
ctx.arc(128, 210, 10, 0, 2*Math.PI);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = '#ddd';
ctx.arc(128, 210, 8, 0, 2*Math.PI);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = '#aaa';
ctx.arc(170, 210, 10, 0, 2*Math.PI);
ctx.fill();
ctx.beginPath();
ctx.fillStyle = '#ddd';
ctx.arc(170, 210, 8, 0, 2*Math.PI);
ctx.fill();

This code will draw gray circles below much lighter-gray circles. Using fill here will create a circle filled in with a particular color based on what fillStyle is set to. stroke, however, has a different effect. Rather than just drawing a circle of the specified color, it draws a circle with a black outline.

I wanted the stereo of the radio to have a textured look, but I didn’t want to repeat a ton of code to write little lines, so what I did is I created a tiny little image with the texture I wanted, and used the context’s createPattern function to create a pattern with that image:

var radioTexture = new Image();
radioTexture.src = 'radio_texture.png';
radioTexture.onload = function() {
  var radioPattern = ctx.createPattern(radioTexture, 'repeat');
  ctx.fillStyle = radioPattern;
  ctx.beginPath();
  ctx.arc(350, 175, 100, 0, 2*Math.PI);
  ctx.fill();
};

This made it really easy to create the texture I wanted without drawing it all using the canvas.

After a little added CSS, I’m starting to like what I created. The radio is a little less ugly now, and it… Actually looks like a radio!

A digital-looking screenshot of something that resembles a 90s tape deck.

Conclusion

I still have a lot more that I want to add to this, but this is a pretty good start for something looking a little bit better. To see the product as it is now, you can click here. I think at some point in 2021 we’ll start to add more functionality, and hopefully by… 2025 we’ll have a finished product!

This is probably going to be the last blog post I make this year, so I just wanted to say that if you enjoyed any of my posts that I’ve written this year, first off thanks so much for reading, and let me know what your favorite one was and why on social media!

Happy Holidays and a Happy New Year to you and your family and friends! I’ll see you all again in 2021!