Friday, February 25, 2011

Canvas vs. SVG...?

Hi again,
today i would like to share some thoughts about HTML5 canvas and svg with you. It seems that not everybody understand that the new capabilities of HTML5 support for canvas and svg does not mean that we have to decide which is the better technology in general. You just have to choose the right tool for your job...if you have to handle a lot of dead bitmaps without any or just a few interactions you should take a look at canvas and if you need the full dom accessibility and living dom objects you should take svg.
I played around with svg around 2004 and at this time the support was bad (unfortunately). But with todays browser support for svg i thought about combining canvas with svg. 
The idea is to use images that has been generated in canvas and use them as background images for svg animations. In this specific case i asked myself if it would make sense to create the static drawing parts of a gauge (like the background and the foreground) in canvas and put an animated svg pointer in between these images and let svg do the animation instead of a javascript. So the question was how to get a canvas as an image and the easy answer is you have to use the toDataURL("image/png") method on a canvas element. This will create a base64 encoded image in png format that one could use in an svg <image> element.
So i added two functions to the canvas component that returns the backgroundimage and the foregroundimage by using the toDataURL() method. 

// Return a base64 encoded image of the background for svg use
this.getBackgroundImage = function()
{
    init();
    return BACKGROUND_Buffer.toDataURL("image/png");
}  

When this was done i just have to add the image via javascript to the svg element in my html body and the images will be painted by svg instead of canvas.

// Add the canvas as backgroundimage to the svg container
var backgroundImage_dataurl = compass.getBackgroundImage();
// Create a new <image> tag in the svg element with the canvas as a source image
var svg_BackgroundImage = document.createElementNS("http://www.w3.org/2000/svg", "image");
svg_BackgroundImage.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", backgroundImage_dataurl); 
svg_BackgroundImage.setAttribute("id", "background");
svg_BackgroundImage.setAttribute("width", IMAGE_WIDTH); 
svg_BackgroundImage.setAttribute("height", IMAGE_HEIGHT); 
svg.appendChild(svg_BackgroundImage);    

Now i had to add the pointer to the svg element between the background image and the foreground image via javascript which could be done by using the svg <path> element. 

// Add the svg pointer ontop of the image
var northPointer = document.createElementNS("http://www.w3.org/2000/svg", "path");
northPointer.setAttribute("id", "northpointer");
northPointer.setAttribute("width", IMAGE_WIDTH);
northPointer.setAttribute("height", IMAGE_HEIGHT);
var northPath = "M" + IMAGE_WIDTH * 0.5 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "L" + IMAGE_WIDTH * 0.5280373831775701 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "L" + IMAGE_WIDTH * 0.5 + " " + IMAGE_HEIGHT * 0.14953271028037382 +
         "L" + IMAGE_WIDTH * 0.4719626168224299 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "L" + IMAGE_WIDTH * 0.5 + " " + IMAGE_HEIGHT * 0.4953271028037383 +
         "Z";           
northPointer.setAttribute("d", northPath);
northPointer.setAttribute("stroke", "darkred");
northPointer.setAttribute("fill", "red");
svg.appendChild(northPointer);

To add an animation (in this case from 0 to -360 deg in an infinite loop) to the pointer i decided to use the <animateTransform> element of svg and added it to the svg element via javascript. 

// Animate NorthPointer
var svg_animateNorth = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform");
svg_animateNorth.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#northpointer");
svg_animateNorth.setAttribute("id", "animatenorth"); 
svg_animateNorth.setAttribute("attributeName", "transform");
svg_animateNorth.setAttribute("begin", "0s");
svg_animateNorth.setAttribute("dur", "3s");
svg_animateNorth.setAttribute("type", "rotate");
svg_animateNorth.setAttribute("from", "0 100 100");
svg_animateNorth.setAttribute("to", "-360 100 100");
svg_animateNorth.setAttribute("repeatCount", "indefinite");    
svg.appendChild(svg_animateNorth);    

And that's it, now i could compare pure javascript canvas animation with svg animation...

To see the page in action please click on the link below the image.

Click to see it in action...

The canvas animation will work in nearly all non ie browsers but the svg animation seems to have problems with webkit based browsers which means you won't see the right side moving in Chrome and Safari. But it will work in FireFox 4.

So keep coding...



No comments:

Post a Comment