Hi folks,
The idea of this post came into my mind when I was navigating the web to find some images for coloring (albeit for my 28 month old son, not myself!) This is not meant however to be an all-in-one tutorial for HTML 5. If you need to learn what HTML5 offers, please give the dive into HTML 5 web site a try.

As my previous post, let’s give it a live try. The idea is to move the mouse over consecutive numbers starting with 1.

If you like it, read on.

Attention IE users: The sample demo uploaded here is not supported on your browser. However, you can download the .zip file and see how it works on your local machine.

There are several steps associated with the making of this piece of software.

Step 1. Finding an image for coloring

To do so, I just searched the web and finally picked up the Scare Bear from this page. Please note that this image is a copyrighted material.

Step 2. Printing the image on a graph paper

The idea is to convert the raster image of Scare Bear into a vector image. This conversion can be made in different ways. As indicated by other people, the Adobe Illustrator can do the job as well as other softwares found out there. But I didn’t find any free conversion utility, so I decided to print the Scare Bear on a graph paper and do the job manually.

If you don’t have a graph paper, don’t worry. You can use GridOmatic to create one.

Scare Bear

Step 3. Internet Explorer Canvas Support

Although IE6 is survived by son IE7, and grand-daughter IE8 (as stated in IE6 Funeral), I believe Microsoft has to address the needs of community in its browser or else, it will lose the market soon or later. As you have guessed so far, IE7 and IE8 don’t support the new HTML5 canvas tag element. However, I needed to address Internet Explorer too.

To do so, I searched the net and found out that there’s a javascript named ExplorerCanvas. So, I used this open source project for bringing the same functionality of canvas tag element to Internet Explorer. To use this script, you need to include a single script tag in your existing web page:

<!--[if IE]>
    <script src="excanvas.js"></script>
<![endif]-->

I did this and the hack worked perfectly on my local machine (as well as the .zip file attached). However, when I tried to do the same thing online, I failed over and over again and I don’t have time to spend fixing this issue more than this.

Step 4. The HTML

There’s nothing special about this HTML. It just contains a canvas element (680×680 pixel), a div element that’s identified by “timer” and another one that I have applied the “filled” class to it.

<canvas id="graph" width="680" height="680"></canvas>
<div id="timer"></div>
<div class="filled"></div>

Actually, the filled class (and therefore it’s containing element) has to be removed. However, I was not planning this ahead so I just surprised how to fill the Scare Bear’s nose, lips and eyebrows when the entire project is completed. So I decided to use a hack to address this problem. You actually don’t need to do this, if you plan how to draw points ahead and therefore you can use the fill method to fill a given closed path.

Step 5. The CSS

.circle {
    background: url('circle.png');
    width: 24px;
    height: 24px;
    text-align: center;
    font-size: .8em;
    line-height: 24px;
    display: block;
    position: absolute;
    cursor: pointer;
    color: #333;
    z-index: 100;
}
.filled {
    background: url('filled.png');
    position: absolute;
    width: 172px;
    height: 251px;
    display: none;
}
#graph {
    left: 200px;
    top: 20px;
    position: relative;
    border: 1px dotted #ddd;
}
#timer {
    position: absolute;
    font-family: Arial;
    font-weight: bold;
    font-size: 1em;
    background: #c00;
    color: #fff;
    padding: 5px;
    text-align: center;
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    font-variant: small-caps;
}

Well, the style sheet is simple. It consists of a “circle” class that handles hotspots, a “filled” class that provides a hack I already described (to fill Scare Bear’s body parts), a “graph” class that positions the canvas on the page, and finally, a “timer” that decorates the red timer displayed in the upper left side of the canvas element.

Step 6. The JavaScript

To start, I just asked my wife to help me to vectorize the Scare Bear. Thank you Mitra. This post wouldn’t be possible without your help.

We decided to select some points on the paper to create an array that contains the entire points necessary to display the image. Each point, contains an (x, y) pair. A point that’s indicated by (-1, -1) means that the line is completed and we need to move the pen to somewhere else on the image. Then, we start over from another (x, y) point and continue this procedure until the image is drawn completely.

var dots = [193, 207, 188, 208, 185, 205, 183, 204, -1, -1,
            188, 208, 181, 208, 172, 207, 169, 206, 166, 204,
            164, 203, 164, 197, 163, 191, 160, 186, 167, 188, -1, -1,
            160, 186, 131, 187, 103, 190];

This is just a sample. It indicates that we need to draw a line started at point (193, 207) to (188, 208) to (185, 205) to (183, 204). Well, we’ve the (-1, -1) pair. Now what? It says that the line is completed and we need to lift up the pen from the surface and move it to the next point indicated by (188, 208) pair. Then we start over and draw a line from (188, 208) to (181, 208) and the like.

At this point, I decided to have a light grid in the background of the image, hence, displayGrid function is born:

function displayGrid(ctx) {
    var gridSize = 20, width = 900;
    for (var ypos = 0; ypos < width; ypos += gridSize) {
        ctx.moveTo(0, ypos);
        ctx.lineTo(width, ypos);
    }
    for (var xpos = 0; xpos < width; xpos += gridSize) {
        ctx.moveTo(xpos, 0);
        ctx.lineTo(xpos, width);
    }

    ctx.strokeStyle = "#eee";
    ctx.lineWidth = .7;
    ctx.stroke();
}

Then, I decided to select hotspots randomly. So, if you refresh the page, the hotspots will be changed. On the other hand, each hotspot has to be positioned so that no two hotspot intersect the other.

function addPoint(index, x1, y1) {
    for (var i = 0; i < points.length; i++) {
        var x2 = points[i].x, y2 = points[i].y;
        var d1 = Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2));
        var d2 = radius * 2 + 2;
        if (d2 > d1) {
            return false;
        }
    }

    points.push({ 'x': x1, 'y': y1, 'index': index });
    return true;
}

This function decides whether a given point can be recognized as a hotspot where it contains three formal parameters: index, x1, and y1. Index indicates the index of the dot element in “dots” array, while (x1, y1) represents the center of a circle to examine. The function uses “points” array to make sure that no two hotspot intersect with another. If it decides that a given point can be a hotspot, it keeps the point index (as well as it’s x, y pair) and returns true; Otherwise, it returns false.

Now we need to decide which points (and lines) to draw and which ones has to be left intact as hotspots. This is what getRandomPoints does:

function getRandomPoints(totalPoints) {
    var indexes = new Array();
    for (var i = 0; i < totalPoints; i++) {
        var done = false;
        while (!done) {
            var index = Math.floor(Math.random() * dots.length);
            if (index % 2 != 0) {
                index++;
                if (index > dots.length) {
                    continue;
                }
            }

            if (!contains(indexes, index)) {
                indexes.push(index);
                done = true;
            }
        }
    }

    return indexes.sort(function(a, b) {
        return a - b;
    });
}

where totalPoints indicates the total number of points to select. However, please note that it doesn’t address the total number of hotspots.

Finally, we need to make sure that maximum “n” points are selected while the following conditions are satisfied:

  1. The points have to be next to each other, if applicable.
  2. The points do not intersect with another hotspot.

The first condition is addressed using a variable named “hops” while the second condition is already addressed in the addPoint function we already talked about.

The remaining is easy. We just need to handle “mouseover” event of hotspots, make sure that user passes hotspots in consecutive order, and animate the hotspot while drawing the required path.

The source code is easy to understand and is packaged into a single zip file that can be downloaded from here.

That’s all for now, folks!

 

19 Responses to Having fun with jQuery and HTML 5

  1. Anonymous says:

    so amazing

  2. Zonk says:

    wow so coooool….
    very nice..

  3. imans62 says:

    wooooooooooow … it’s wonderfull

  4. Anonymous says:

    Nice Job. Very Interesting.

  5. My name is Carlos Cardona. I am a member of the W3C HTML5 Working Group. Recently I started a blog to aggregate all of the creative and exciting things I see around the web regarding HTML5. I have posted a link to your article on HTML5. Please let me know if you have any future posts related to HTML5. Thanks!
    http://html5app.com/blog/?p=29

  6. Anonymous says:

    Eyval Dash mehdi , that was really nice of you

  7. Ina Centaur says:

    excanvas.js hack might not work because you gave a relative link – your blogger address is mod_url/rewrite, so you will need an absolute link

  8. mohit says:

    good job
    nicely done!!

  9. Mehrdad says:

    Good job man,

  10. tony nab says:

    Glad it happening. :-)

  11. ROAdmin says:

    Great Tutorial.
    I hope canvas will be used in more Websites.

    Best regards
    ROAdmin

  12. dmccallum says:

    Would it be possible to have a sound play when the last hotspot is activated? I’ve tried modifying it myself and although I can get it to work it stops the filled from being activated.

    • Mehdi Mousavi says:

      Hi,
      There’s a block of code that’s responsible to show the filled sections of the picture, albeit, using the “filled.png” image found in the enclosed zip file.

      $('.filled').css({
          left: gpos.left + xDisplacement + 10,
          top: gpos.top + yDisplacement + 150
      }).fadeIn('slow');
      

      If you’re going to do this correctly, however, you need to plan ahead how to connect those points together, so that you’ll end up having some closed paths that can be easily filled using the fill method.

      Hope this helps

  13. suresh says:

    How can we do this with variable images

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Recent Tweets

Polly is a transient-fault-handling .NET library that allow you to express policies such as Retry, Timeout & more bit.ly/2ow9pzK

Sponsors