Archive for the 'canvas' Category

Load a photo in a canvas, then flip

Saturday, May 3rd, 2008

zlati-nathalie.jpg

Today our family went to the yearly photo session with the girls. We took one shot that can be looked normally, as well as upside down, so I was wondering can you flip an image using a canvas tag. Turns out, yes, you can and it's pretty easy.

» Demo is here.

How to load an image in a canvas tag?

Start unpretentiously with an empty canvas tag:

<canvas id="canvas"></canvas>

Now the javascript. Two variables to store a handle to the canvas element and the 2D context of the canvas:

var can = document.getElementById('canvas');
var ctx = can.getContext('2d');

Now let's load an image into the canvas. Using the new Image() constructor you can create an image object, then set its src property to point to the location of the image file. Then set an onload handler for the image which is an anonymous function to be called when the image is done loading. There you put the image inside the canvas using the drawImage() method of the canvas context.

var img = new Image();
img.onload = function(){
    can.width = img.width;
    can.height = img.height;
    ctx.drawImage(img, 0, 0, img.width, img.height);
}
img.src = 'zlati-nathalie.jpg';

You can also notice how the dimensions of the canvas are adjusted to match the dimensions of the image.

How to flip the image upside down

The canvas context provides a rotate() method. The rotation always happens around the top left corner of the image, so we first translate() the image to the bottom right. This way when the image is rotated, it fits back into the canvas. (There is also a one pixel correction, I have no idea why, just saw that the image wasn't flipping exactly otherwise). Assigning this functionality to the onclick:

can.onclick = function() {
    ctx.translate(img.width-1, img.height-1);
    ctx.rotate(Math.PI);
    ctx.drawImage(img, 0, 0, img.width, img.height);
};

C'est tout! Once again, the demo is here.

 

Canvas pie with tooltips

Saturday, March 8th, 2008

This is very flattering: Greg Houston took my script for DIY canvas pie and added tooltips and better colors logic. Here's the result, it's really nice, built with some MooTools. The tooltips are not supported in <canvas> but Creg used an image that overlays the pie and set the tooltips with an image map. Clever, isn't it?

I just used random colors for the pieces of the pie, but Greg knows better. Based on a tutorial by Jim Bumgardner, he was able to achieve much more pleasing, yet reliable results. Funny thing that Jim works in Yahoo! two floors above me (used to be even on the same floor).

Check the demo and the post, cool stuff, works in IE too!

 

Canvas pie

Tuesday, February 5th, 2008

OK, so you have an HTML table. Let's turn it into a pie chart with a bit of javascript.

We'll be using the canvas tag, so the browser has to support it. For IE - well, you still have the table. That's why we'll call it progressive enhancement. Unobtrusive too. Here's a screenshot:
canvas-pie.png

» The demo is here (refresh for new colors)

Here are the ingredients to the recipe:

  1. One <canvas> tag
  2. One <table> full of data
  3. javascript to get the data from the table
  4. javascript to plot the data on the canvas

One canvas tag

<canvas id="canvas" width="300" height="300"></canvas>

One table full of data

This is a bare bone unstyled old school table.

<table id="mydata">
    <tr>       <th>Lang</th><th>Value</th> </tr>
    <tr><td>JavaScript</td>  <td>100</td>  </tr>
    <tr><td>       CSS</td>  <td>200</td>  </tr>
    <tr><td>      HTML</td>  <td>300</td>  </tr>
    <tr><td>       PHP</td>  <td> 50</td>  </tr>
    <tr><td>     MySQL</td>  <td> 30</td>  </tr>
    <tr><td>    Apache</td>  <td> 10</td>  </tr>
    <tr><td>     Linux</td>  <td> 30</td>  </tr>
</table>

javascript to get the data from the table

First, some setup. Let's tell the script which is the ID of the data table, the ID of the canvas tag and which column contains the data:

// source data table and canvas tag
var data_table = document.getElementById('mydata');
var canvas = document.getElementById('canvas');
var td_index = 1; // which TD contains the data

Next, select all table rows, then loop through the rows, selecting all TDs. Add the data we need to a data array. While at it, run a total of the data in the column and also create an array of random colors. Paint each row with the selected color. (we'll see the actual getColor() in a bit.)

var tds, data = [], color, colors = [], value = 0, total = 0;
var trs = data_table.getElementsByTagName('tr'); // all TRs
for (var i = 0; i < trs.length; i++) {
    tds = trs[i].getElementsByTagName('td'); // all TDs

    if (tds.length === 0) continue; //  no TDs here, move on

    // get the value, update total
    value  = parseFloat(tds[td_index].innerHTML);
    data[data.length] = value;
    total += value;

    // random color
    color = getColor();
    colors[colors.length] = color; // save for later
    trs[i].style.backgroundColor = color; // color this TR
}

javascript to plot the data on the canvas

Time for the fun part, the drawing! First, we need to create a context object. Then figure out the raduis of the pie and the center, all based on the width/height pf the canvas tag:

// get canvas context, determine radius and center
var ctx = canvas.getContext('2d');
var canvas_size = [canvas.width, canvas.height];
var radius = Math.min(canvas_size[0], canvas_size[1]) / 2;
var center = [canvas_size[0]/2, canvas_size[1]/2];

Next, let's loop through data and paint pieces of the pie. To draw a piece of pie, you basically need to call these methods of the context object:

  • beginPath() - to start the piece of the pie
  • moveTo() - to set the pencil in the center
  • arc() - draw a piece of a circle
  • lineTo() - finish the circle piece with a line back to the center
  • closePath() and fill() but set the fill color first.

Here's the actual code for this part, hopefully the comments help:

var sofar = 0; // keep track of progress
// loop the data[]
for (var piece in data) {

    var thisvalue = data[piece] / total;

    ctx.beginPath();
    ctx.moveTo(center[0], center[1]); // center of the pie
    ctx.arc(  // draw next arc
        center[0],
        center[1],
        radius,
        Math.PI * (- 0.5 + 2 * sofar), // -0.5 sets set the start to be top
        Math.PI * (- 0.5 + 2 * (sofar + thisvalue)),
        false
    );

    ctx.lineTo(center[0], center[1]); // line back to the center
    ctx.closePath();
    ctx.fillStyle = colors[piece];    // color
    ctx.fill();

    sofar += thisvalue; // increment progress tracker
}

utility

Here's the function that gives a random color:

    // utility - generates random color
    function getColor() {
        var rgb = [];
        for (var i = 0; i < 3; i++) {
            rgb[i] = Math.round(100 * Math.random() + 155) ; // [155-255] = lighter colors
        }
        return 'rgb(' + rgb.join(',') + ')';
    }

C'est tout! Enjoy your pie :D

UPDATE: Comment by Zoltan below, if you use Explorer Canvas, you can make this work in IE with only this:
<!--[if IE]><script type="text/javascript"
src="/path/to/excanvas.js"></script><![endif]-->