Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Canvas Animation and Web Worker

4.00/5 (5 votes)
13 May 2011CPOL2 min read 30.1K   362  
Canvas Animation and Web Worker

Introduction

In this article, I will try to show one of the basic complex animations of Canvas and Web Worker in HTML5.

We are going to draw a square and animate it around the center of canvas. The square will make double rotation: around a circle (clockwise) and around itself (counterclockwise).

Because the user could modify the radius of the circle and the size of the square, we will create a worker to work in the background. Otherwise the JavaScript will keep forever the application threat if the user enters a bad input.

Using the Code

We start with the HTML markup. Since the Canvas element and the Worker are not supported in the previous version of HTML, the following declaration is the one we need.

HTML
<!DOCTYPE html>

After we declare the canvas:

XML
<canvas id="canvas" height="400" width="400"></canvas>

We need an “Id” because we will access it in JavaScript.

Then we need fields to allow users to interact. To keep thing simple, we create a table with one row only and three columns as follows:

HTML
<table id="table">
      <tr id="table_row">
        <td>
          <label for="tcircle">
            Circle radius</label><br />
          <input type="text" id="tcircle" class="textbox" />
        </td>
        <td>
          <label for="tsquare">
            Square size</label><br />
          <input type="text" id="tsquare" class="textbox" />
        </td>
        <td>
          <input type="hidden" id="hidden" value="34,21" onchange="valueChanged()"/>
          <br />
          <input type="button" value="Apply" id="btn" />
        </td>
      </tr>
    </table>

Now since our user interface is ready, let us move to JavaScript to perform drawing on the canvas.

We start by defining two global variables:

JavaScript
var canvas;
var context;

The first is the canvas and the second is the context on which we will be working on.

Let us create our first function which draws a circle. It takes one parameter: the radius of the circle. Here is the function:

JavaScript
function draw_circle(radius) {
    context.beginPath();
    context.arc(0, 0, radius, 0, 2 * Math.PI, true);
    context.closePath();
    context.stroke();
}

Here is the square function:

JavaScript
function draw_square(size) {
    // Angle between two consecutive vertices where the center of 
    // the repere is the center of the square.
    var angle = 0; 
    
    // distance of a vertice of the center of the square.
    var r = size / Math.SQRT2; 
    context.beginPath();
    context.moveTo(r * Math.cos(angle), r * Math.sin(angle));
    
    // angle between two consecutive vertices, which is 2*Math.PI/n. 
    // Here the regular polygon is a square. So n = 4.
    var gama = Math.PI / 2; 
 
    // Now we make a loop to draw the tree left vertices.
    for (var i = 1; i < 4; i++) {
        angle += gama;
        context.lineTo(r * Math.cos(angle), r * Math.sin(angle));
    }
    context.closePath();
    context.fillStyle = "#00ff00"; // Fill it with the green color
    context.fill();
}

Because we draw, clear the context and draw again, we need one clear function.

JavaScript
function clear() {
    context.clearRect(0, 0, canvas.width, canvas.height);
}

The function to call when the page loads is:

JavaScript
function init() {
 
    // Initialize the canvas.
    canvas = document.getElementById("canvas");
 
    // check if the canvas is supported and also of the getContext is available.
    if (canvas && canvas.getContext) {
        // Initialize the context.
        context = canvas.getContext("2d");
        // The interval of drawing is set to 10 millisecons.
        return setInterval(draw, 10);
    }
    else {
        alert("Canvas is not supported!");
    }
}

Now is our draw function.

First, let us create three others global variables for angles.

JavaScript
// Angle of rotation of the square around itself.
var beta = 0; 

// angle of rotation around the circle.
var alpha = 0; 

// angle radian make by the circle in 10 milliseconds.
var theta = .01 * Math.PI;

Now here is the draw function:

JavaScript
function draw() {

    // We can pass parameters to the clear() function or just 
    // it here in order to scale when clearing.
    clear();
    var R = 30;
    var S = 20;
    alpha += theta;
    context.save();
    context.translate(canvas.width / 2, canvas.height / 2);
    context.rotate(alpha);
    //context.scale(scale, scale);
    draw_circle(R);
 
    // beta = 3.alpha. Because I rotate back the canvas first,
    // then rotate it twice again in order to rotate the square.
    beta -= 3 * theta; 
 
    context.save();
    context.translate(R, 0);
    context.rotate(beta);
    draw_square(S);
    context.restore();
 
    context.restore();
}

We finish the draw and animation. Now let us allow interaction.

We start by creating our worker. It just takes the values of the two text boxes and converts them into one string.

JavaScript
function applyValues(radius, size) {
    return radius + "," + size;
}

/* 
Add a event listener to the worker, this will
be called when the worker receives a message
from the main page.
*/
this.onmessage = function (event) {
    var data = event.data;
    postMessage(applyValues(data.radius, data.size));
};

To finish, in the HTML markup in the script section, we perform the following task with some basic security and information to display to the user.

JavaScript
<script>
    /* Check if Web Workers are supported */
    function getWebWorkerSupport() {
      return (typeof (Worker) !== "undefined") ? true : false;
    }
 
    if (getWebWorkerSupport() == true) {
      var radius, size, message;
      //            var canvas=screen;
 
      worker = new Worker("scripts/worker.js");
 
      /* 
      Add an event listener to the worker, this will
      be called when the worker posts a message.
      */
      worker.onmessage = function (event) {
        document.getElementById("hidden").value = event.data;
      };
 
      // Register event for button
      document.getElementById("btn").onclick = function () {
        radius = document.getElementById("tcircle").value;
        size = document.getElementById("tsquare").value;
        var canvas = document.getElementById("canvas");
 
        // Check if the radius and size are numeric types
        if (!isNaN(radius) && !isNaN(size)) {
          // parse the radius and the size to integer
          radius = parseInt(radius);
          size = parseInt(size);
          // Make sure that the square will never hide the center of the circle
          if (radius >= size / Math.SQRT2) {
            // Make sure the circle and the square will be always visible
            if ((radius + (size / Math.SQRT2)) < 200) {
              message = { 'radius': radius, 'size': size };
              // Post the message.
              worker.postMessage(message);
            }
            else {
              alert("The summation of the radius and the half of the 
			hypotenuse must not be greater than 200 pixels");
            } 
          }
          else {
            alert("The radius must be greater the size/sqrt(2)!");
          }
        }
        else {
          alert("Numerics type are needed!");
        }
      }
    }
  </script>

The event that wires up when the value of the hidden field changed is:

JavaScript
function valueChanged() {
    return document.getElementById("hidden").value;
}

The hidden field is there just to update when drawing.

It is all. Thank you.

History

  • 11th May, 2011: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)