Create a HTML5 canvas element with clickable elements

Canvas with clickable circles
A client asked me to implement a website with different images having clickable circles on top of them. The circles would be placed randomly – and would be used to display additional information about what was going on in that particular place in the image.

Fortunately, the client did not require that users with older browser should be able to view the website. So I was able to use some modern technology in order to make my life a bit easier.

I have never worked with the HTML5 canvas-element before. So I needed to get some hands-on experience with it. I therefore decided to create a proof-of-concept first. You can see this proof-of-concept in the following fiddle: http://jsfiddle.net/Terkildsen/9pgWf/

The following is a quick walk-through of the elements in the code. First, I start off with a canvas element:

  <body>
    <canvas id="myCanvas" width="1420" height="702"></canvas>
  </body>

After that, I create a reference to the canvas-element in my JavaScript – and initialize a circles-array that will hold information about each circle:

var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var circles = [];

Then I implement a function to handle the drawing of each circle. The function will accept a reference to the canvas-element (context), the x- and y-position of the circle, the fillcolor, radius, and different other parameters necessary to draw the circle. The circle is drawn by using the context.arc-method – which is documented right here: http://www.html5canvastutorials.com/tutorials/html5-canvas-arcs/

var draw = function (context, x, y, fillcolor, radius, linewidth, strokestyle, fontcolor, textalign, fonttype, filltext) {
    context.beginPath();
    context.arc(x, y, radius, 0, 2 * Math.PI, false);
    context.fillStyle = fillcolor;
    context.fill();
    context.lineWidth = linewidth;
    context.strokeStyle = strokestyle;
    context.stroke();
    
    context.fillStyle = fontcolor;
    context.textAlign = textalign;
    context.font = fonttype;
    
    context.fillText(filltext, x, y);    
};

Now I create an object that will hold the position of each circle – this information is used later on for deciding whether or not the user clicked on the circle

var Circle = function(x, y, radius) {
    this.left = x - radius;
    this.top = y - radius;
    this.right = x + radius;
    this.bottom = y + radius;
};

I then create a drawCircle-method that will call the draw-method – in order to draw the circle – and that will store the position of each new circle.

var drawCircle = function (context, x, y, fillcolor, radius, linewidth, strokestyle, fontcolor, textalign, fonttype, filltext, circles) {
    draw(context, x, y, fillcolor, radius, linewidth, strokestyle, fontcolor, textalign, fonttype, filltext);
    var circle = new Circle(x, y, radius);
    circles.push(circle);  
};

Now I can add my circles – naturally, this would come from a database containing the texts as well as the coordinates of each circle.

drawCircle(context, 300, canvas.height / 2, "green", 40, 5, "#003300", "white", "center", "bold 32px Arial", "1", circles);
drawCircle(context, 600, canvas.height / 3, "blue", 50, 5, "#003300", "white", "center", "bold 32px Arial", "2", circles);

And then, finally, I add a jQuery-method that will bind to the click-event, and decide which circle – if any – the user clicked. Here, I use the previously stored information about each circles’ position to calculate whether or not the user clicked a certain circle. Right now, I just alert some dummy text – but I will add a method to display additional information.

$('#myCanvas').click(function (e) {
    var clickedX = e.pageX - this.offsetLeft;
    var clickedY = e.pageY - this.offsetTop;
    
    for (var i = 0; i < circles.length; i++) {
        if (clickedX < circles[i].right && clickedX > circles[i].left && clickedY > circles[i].top && clickedY < circles[i].bottom) {
            alert ('clicked number ' + (i + 1));
        }
    }
});

That’s it – for a complete working sample please go to http://jsfiddle.net/Terkildsen/9pgWf/

Advertisements

9 thoughts on “Create a HTML5 canvas element with clickable elements

  1. Hi Steen,

    i’ve never worked with SVG for anything else than scalable graphics on mobile devices, so I thought you couldn’t do this with SVG.

    I just looked at your fiddle, but I can’t see all the code. Do I need a special editor?

  2. Ok, I downloaded Inkscape and started working. I can see that SVG is probably much easier for a designer to edit and maintain than canvas. Also, it will probably be easier for me to implement this on multiple different screen sizes due to SVG being vector-based.

    However, I can see that SVG comes with a performance hit due to the fact that SVG is available in the DOM. And SVG is not available in Android-versions below 3.0.

    For a comparison of SVG and canvas look at this page: http://www.sitepoint.com/canvas-vs-svg-how-to-choose/

    Thank you Steen – I learned something new 🙂

  3. Hi Richard,

    Sorry for not getting back to you before. Unfortunately, I receive so much spam on this blog, so real comments are drowning.
    I see what you mean – about the jsFiddle site. For some reason it doesn’t work in IE11 – which I will investigate. As you say, it works when you execute the code locally, so it must be related to the jsFiddle. I’ll get back to you.

    Peter

  4. Thanks for this article.
    To make to code with only pure javascript, without the need of a js framework, i changed:
    $(‘#myCanvas’).click(function (e) { … });
    with this:
    canvas.addEventListener(‘click’, function(e) { …});

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s