Chapter 5. Creating Interactive Canvas and SVG Applications

Introduction

The Web is a richer place, indeed, with the new and improved innovations ready to use. Our old friends SVG and Canvas are getting new life and generating new interest. JavaScript and CSS provide a malleable palette in which to paint web pages, but the HTML5 svg and canvas elements provide the capability to take those pages into new and exciting territory.

SVG, or Scalable Vector Graphics, is an XML-based vector graphics language that can be used to create scalable vector graphics within web pages. With HTML5, you can insert the SVG directly in the web page via the svg element.

SVG is not dependent on JavaScript. You can create graphical images using markup, and even animate them using CSS transitions or declarative animation via SMIL (Synchronized Multimedia Integration Language). However, as will be demonstrated in this chapter, the svg element and JavaScript can be used to create any number of dynamic and interactive effects.

The canvas element originated with Apple, and has now become standardized as part of the HTML5 work. Unlike SVG, the canvas element is totally dependent on JavaScript. We add canvas elements into our page and then use a context API in order to draw into these elements.

The svg and canvas elements are now implemented, in varying degrees, in all of this book’s target browsers and environments.

All of the examples in this chapter are implemented with JS Bin, which means you can test the actual code, not just read about. All JS Bin output is represented by a rectangle about the graphical interface area; most provide input controls for adding data or performing some action.

See Also

The canvas element is documented in the HTML5 specification at HTML5 Canvas spec. The current working draft for the Canvas 2D Context can be found at W3C Canvas 2D Context Spec. Keep up with current work on SVG at SVG spec.

Creating a Simple Rectangle in a Canvas Element

Problem

You want to add a canvas element to a web page, and then create a simple rectangle within the element.

Solution

Insert a canvas element into the web page:

<canvas width="300" height="300" id="imgcanvas"
style="border: 1px solid black; background-color: white">
<p>A single rectangle, red with a black border,
sized 100x100 pixels, in upper left corner.</p>
</canvas>

Then use the Canvas 2D context to draw the rectangle within the canvas element’s coordinate system:

var canvas = document.getElementById("imgcanvas");

// if canvas element successfully accessed
if (canvas.getContext) {

   // get 2D context
   var ctx = canvas.getContext('2d');

   // ensure area is clear
   ctx.clearRect(0,0,canvas.width, canvas.height);

   // set circle fill and outline colors
   ctx.fillStyle="rgb(255,0,0)";
   ctx.strokeStyle="#000000";

   // fill and outline rectangle
   ctx.fillRect(0,0,100,100);
   ctx.strokeRect(0,0,100,100);

 }

The result is a simple red square with a black outline and white background, positioned with its left, top edge at the left, top corner of the larger canvas element.

Discussion

The canvas element is inserted into the web page in the location you want the canvas drawing to exist. If you wish, you can provide CSS styling for the element. In the solution, I outlined the canvas element in black to make the container visible. By default, the background of the canvas area is transparent.

Set the width and height of the canvas element using the width and height attributes. You can also, as shown in the solution, provide fallback content—in this case, a paragraph describing what’s being drawn within the canvas element.

The area of the canvas element is a resolution-dependent bitmap. If scripting is enabled, the content reflects the JavaScript function calls drawing into the canvas element. If the page is printed, the canvas area reflects the state of the element’s bitmap at the time of the printing. If scripting is disabled, the fallback content of the element is displayed.

To draw into the canvas element you first have to get the canvas element’s context. To access the element’s 2D context, specify 2d when calling the canvas element’s getContext() method. To access the element’s 3D context, specify 3d, though be aware that there is limited support for 3D at this time

Before you begin drawing, test to see if the canvas element is supported by checking to see if the getContext method is available. If it is, access the canvas context:

var canvas = document.getElementById("imgcanvas");

// if canvas element successfully accessed
if (canvas.getContext) {

   // get 2D context
   var ctx = canvas.getContext('2d');

   ...

 }

The 2D Context API has one basic predefined shape, the rectangle. It also has three rectangle methods:

fillRect
Uses the currently set fillStyle value to fill the rectangle
strokeRect
Uses the currently set strokeStyle value to outline the rectangle
clearRect
Clears whatever is drawn within the rectangle area

In the Solution, the first method called is clearRect, which clears the area of any previously drawn graphics, but without resetting any previously set styles or transformations. If the canvas element is drawn into only once, it’s not necessary to use clearRect because the canvas area is already clear. However, if your JavaScript is interactive, and the canvas area is drawn into again and again, any new drawing overlaps the existing drawing.

To demonstrate, modify the code to enclose the JavaScript that draws the box, and remove the call to clearRect. In addition, change the code to use variables to hold the rectangle origin parameters, and then adjust the values each time the function is called. Lastly, call setTimeout to call the function multiple times to create an animation effect of a red square moving diagonally across and down the page:

x = 0;
y = 0;

function drawBox() {
  var canvas =    document.getElementById("imgcanvas");

  // if canvas element successfully accessed
  if (canvas.getContext) {

     // get 2D context
     var ctx = canvas.getContext('2d');

     // set rectangle fill and outline colors
     ctx.fillStyle="rgb(255,0,0)";
     ctx.strokeStyle="#000000";

     // fill and outline rectangle
     ctx.fillRect(x,y,20,20);
     ctx.strokeRect(x,y,20,20);

   }
  x+=20;
  y+=20;

  // animate
  if (x < 300) {
    setTimeout(drawBox, 200);
  }

Add a button to call the newly created function when clicked:

<button type="button" onclick="drawBox()">
    Run Example</button>

Contrary to what you might expect, clicking on the button doesn’t move the box down and over on the page—it replicates it, with each succeeding box placed just to the right and bottom of the previous.

Adding a call to clearRect ensures a clean canvas area, regardless of how we change the JavaScript at a later time.

function drawBox() {
  var canvas =    document.getElementById("imgcanvas");

  // if canvas element successfully accessed
  if (canvas.getContext) {

     // get 2D context
     var ctx = canvas.getContext('2d');

     // clear the space
     ctx.clearRect(0,0,canvas.width, canvas.height);

     // set rectangle fill and outline colors
     ctx.fillStyle="rgb(255,0,0)";
     ctx.strokeStyle="#000000";

     // fill and outline rectangle
     ctx.fillRect(x,y,20,20);
     ctx.strokeRect(x,y,20,20);

   }
  x+=20;
  y+=20;

  // animate
  if (x < 300) {
    setTimeout(drawBox, 200);
  }
}

And now we have a moving box, rather than a replicated box.

Speaking of moving the rectangle, it’s important to understand the canvas element’s coordinate system before you begin drawing.

The canvas element’s coordinate system is a two-dimensional grid. A coordinate of 0,0 is at the top, left corner of the element’s area. If x represents the horizontal position, and y the vertical, increasing the value of x moves the origin down the page, while increasing the value of y moves the origin to the right.

Consider the solution. Both the fillRect and strokeRect methods take the rectangle origin (x,y) in the first two parameters, and the width and height in the third and fourth parameters, respectively. In the solution, the calls to both methods set the top, left corner of the box at 0,0 and the width and height at 100.

To reposition the rectangle, change the first two parameters. To increase the width of the rectangle towards the right, increase the width parameter. However, to move the border of the rectangle to the left, you an specify a negative value for the width. The same apples to the height: an increasing positive value expands the rectangle to the bottom; using an increasing negative value expands the rectangle to the top of the canvas space.

If you don’t use numeric values, no error is given; the values are ignored, and the rectangle isn’t drawn.

Test the forgiving nature of the Canvas methods, first by providing valid numeric values, then nonsensical non-numeric values. If you have your JavaScript console open, you won’t see any errors.

Of course, it’s also important to ensure that the rectangle is colored the way you want. There’s two different components when it comes to the rectangle’s color—the rectangle’s fill color and the color of the outline—and you need to set both if you’re planning on using both.

To set the fill color, call the fillStyle method, passing in a CSS color, a CanvasGradient, or a CanvasPattern. The latter two are more advanced than we want to examine in this introduction, so we’ll just focus on the CSS color:

ctx.fillStyle="rgb(255,0,0); // solid color red
ctx.fillStyle="rgba(255,0,0,.5); // incorporating transparency
ctx.fillStyle="black";
ctx.fillStyle="#00cc00"; // darker green

The strokeStyle is used to define the style for the lines outlining the shape. It also takes a CSS color, CanvasGradient, or CanvasPattern:

ctx.strokeStyle="rgb(0,0,0); // black outline
ctx.strokeStyle="red";
ctx.strokeStyle="rgba(0,0,255,.1); // faint blue outline
ctx.strokeStyle="#ff00ff"; // magenta

As with the origin and width and height parameters, a nonsensical value is ignored. Not providing a correct strokeStyle or fillStyle value causes the canvas element to revert to the default, which is black for both.

The following example takes both a fillStyle and a strokeStyle color. Click the "Edit in jsBin" to modify the example to also take a lineWidth value, to change the width of the outline.

Manipulating a Simple Rectangle in SVG

Problem

You want to be able to directly access a rectangle drawn in SVG and embedded in an HTML5 document and modify its properties.

Solution

You can provide an identifier for an SVG element as easily as you provide one for any other element in an HTML5 document.

<svg width="300" height="300"
style="border: 1px solid black; background-color: white" id="svgelem">
  <rect id="rect1" x="0" y="0" width="50"
  height="100" fill="green" stroke="black" />
</svg>

In JavaScript, access the rect element directly using document.getElementById() method and set the element’s attributes however you wish using the DOM (Document Object Model) method setAttribute.

The following code snippet:

var rect = document.getElementById('rect1');

rect.setAttribute('width',100);
rect.setAttribute('fill', 'red');

Results in a square, red box with a black outline, fitted to the upper, left corner of the svg element.

Discussion

SVG is not dependent on JavaScript. If you want a red box in a svg element within an HTML5 web page, you just create it directly using XML, and the box is drawn as long as the browser supports the svg element.

You can, however, use JavaScript to create, remove, or manipulate the contents of the SVG element, just as you can create, remove, or manipulate other elements in the page.

In the solution, two attributes for the SVG rect element are modified: fill and width. The code uses the setAttribute to make the changes. This method takes an attribute name and a new value, and changes the attribute on an existing element. Any of the attributes for the element can be modified, including the following attributes specific to the rect element:

  • x: The x-axis coordinate representing the leftmost corner of the rectangle
  • y: The y-axis coordinate representing the topmost corner of the rectangle
  • width: The width of the rectangle
  • height: The height of the rectangle
  • rx: The x-axis radius of the ellipse used to round the corners of the rectangle
  • ry: The y-axis radius of the ellipse used to round the corners of the rectangle

The latter two attributes, rx and ry are interesting. SVG supports rounded rectangle corners. If neither attribute is specified, then the corners are squared off, as shown in the solution. If only one of the values is provided, the other is assumed to be equal to the one provided. And if the value set for either is wider than half the width of the rectangle, it’s automatically reset to half the width, no more. In other words, the rectangle is transformed into an ellipse (or a circle if the width and height are the same).

There is limited error checking for the attribute. If you set a non-existing attribute, nothing negative happens. No error is thrown. However, if you provide a nonsensical value for an existing attribute, such as providing a value of cat for rx, you will get an error.

Take the following SVG example for a spin, providing both valid and invalid values for the parameters. Open your JavaScript console to see the resulting errors if you provide nonsensical values for existing attributes. You’ll also notice the changes are cumulative.

One perk with using SVG over Canvas is you can animate a SVG object directly, rather than having to repaint the canvas area. For instance, to re-create the animated box example demonstrated with Canvas earlier, animating the same box in SVG could be accomplished with the following JavaScript:

x = 20;
y = 20;

function moveBox() {
  var box =    document.getElementById("rect1");

  box.setAttribute("x",x);
  box.setAttribute("y",y);

  x+=20;
  y+=20;

  // animate
  if (x < 300) {
    setTimeout(moveBox, 200);
  }
}

We’re accessing and moving an element, not repainting the entire bitmap.

Another major difference between Canvas and SVG is SVG is resolution independent. What this means is that where a bitmap image created by Canvas degrades if the image is sized larger (resulting in a pixelated image), the SVG image won’t. Resolution independence has always been the advantage of vector graphics: they resize from the very small to the very large without loss of quality.

The coordinate system for the svg element is the same as the coordinate system for the canvas element: the origin of 0,0 is the topmost, left corner of the element’s grid, with increasing values of x moving down, and increasing values of y moving right. In SVG, this coordinate system is known as the viewport.

SVG does, however, provide a way to map a user defined coordinate system on to the viewport. For instance, the following JavaScript would increase the width and height of the square to 400 pixels each, which would size the square outside of the svg element’s visible area.

function expandSquare() {
  var rect = document.getElementById("rect1");

  rect.setAttribute("width",400);
  rect.setAttribute("height", 400);
}

I made the outline larger by setting stroke-width to 10 so you can see how the lower bottom and far right of the rectangle are clipped by the svg element border when the rectangle is expanded.

However, if I incorporate a user coordinate system that maps two units of measurement onto every unit of the coordinate system, the rectangle would fit into the given space. The way to do this is to use the svg element viewBox attribute.

The viewBox attribute is a set of values—min-x, min-y, width, and height—separated by commas or white space, which specifies a rectangle in the user space that is mapped to the viewport. In this case, we want to ensure all of the rectangle is visible when we expand its size, so we set the viewBox attribute on the svg element to a value of 0,0,600,600, making the space more than sufficient to display the entire rectangle.

function expandSquare() {
  var svgelement = document.getElementById("svgelem");

  svgelement.setAttribute("viewBox", "0,0,600,600");

  var rect = document.getElementById("rect1");

  rect.setAttribute("width",400);
  rect.setAttribute("height", 400);
}

Now, the entire rectangle fits into the svg element, without having to change the rectangle’s dimensions. The use of a viewBox is typically how you make an SVG image fit into an element within your page or application, even if the dimensions of the elements within the SVG exceed the space you want to provide. This ability is especially important when you’re using SVG you’ve found elsewhere.

Test out the viewBox capability more fully by trying out different combinations of min-x, min-y, width, and height of the svg element.

Speaking of finding SVG to copy elsewhere, a great resource for open source SVG is the OpenClipArt web site. You can copy the SVG markup directly and use as is or modify for your own purposes.

Another interesting aspect of SVG is the ability to manipulate the _aspect ratio_—the ratio of width to height—when you’re using a viewBox. In the previous example, I used a 1:1 ratio when I added the viewBox. In the following code snippet, though, the aspect ratio is no longer a 1:1 between width and height—the aspect ratio has changed to 3:4. So what happens to the square?

<svg width="300" height="300"
  viewBox="0,0,600,800"
  style="border: 1px solid black">
    <rect id="rect1" x="30" y="30"
    width="400" height="400"
    fill="red" stroke="yellow"
    stroke-width="10" />
  </svg>

Absolutely nothing. The square is still a square.

The reason why the square didn’t suddenly become an elongated rectangle is because of another important SVG attribute, preserveAspectRatio. The preserveAspectRatio controls what happens to the aspect ratio of the SVG element contents. Using it, you can decide if you want to preserve the aspect ratio, and if so, in what way.

There are various values you can use with preserveAspectRatio. They consist of one or two parameters, the first of which is the align parameter:

  • none - Do not force uniform scaling. Scale the graphic content of the given element non-uniformly if necessary such that the element’s bounding box exactly matches the viewport rectangle. (Note: if <align> is none, then the optional <meetOrSlice> value is ignored.)
  • xMinYMin - Force uniform scaling. Align the <min-x> of the element’s ‘viewBox’ with the smallest X value of the viewport.Align the <min-y> of the element’s ‘viewBox’ with the smallest Y value of the viewport.
  • xMidYMin - Force uniform scaling. Align the midpoint X value of the element’s ‘viewBox’ with the midpoint X value of the viewport. Align the <min-y> of the element’s ‘viewBox’ with the smallest Y value of the viewport.
  • xMaxYMin - Force uniform scaling. Align the <min-x>+<width> of the element’s ‘viewBox’ with the maximum X value of the viewport. Align the <min-y> of the element’s ‘viewBox’ with the smallest Y value of the viewport.
  • xMinYMid - Force uniform scaling. Align the <min-x> of the element’s ‘viewBox’ with the smallest X value of the viewport. Align the midpoint Y value of the element’s ‘viewBox’ with the midpoint Y value of the viewport.
  • xMidYMid (the default) - Force uniform scaling. Align the midpoint X value of the element’s ‘viewBox’ with the midpoint X value of the viewport.Align the midpoint Y value of the element’s ‘viewBox’ with the midpoint Y value of the viewport.
  • xMaxYMid - Force uniform scaling. Align the <min-x>+<width> of the element’s ‘viewBox’ with the maximum X value of the viewport.Align the midpoint Y value of the element’s ‘viewBox’ with the midpoint Y value of the viewport.
  • xMinYMax - Force uniform scaling. Align the <min-x> of the element’s ‘viewBox’ with the smallest X value of the viewport. Align the <min-y>+<height> of the element’s ‘viewBox’ with the maximum Y value of the viewport.
  • xMidYMax - Force uniform scaling. Align the midpoint X value of the element’s ‘viewBox’ with the midpoint X value of the viewport. Align the <min-y>+<height> of the element’s ‘viewBox’ with the maximum Y value of the viewport.
  • xMaxYMax - Force uniform scaling. Align the <min-x>+<width> of the element’s ‘viewBox’ with the maximum X value of the viewport. Align the <min-y>+<height> of the element’s ‘viewBox’ with the maximum Y value of the viewport.

An optional second parameter, the meetOrSlice parameter, can also be specified for preserveAspectRatio. It’s separated from the align parameter by one or more spaces, and has one of two values:

  • meet (the default) - Scale the graphic such that: aspect ratio is preserved the entire ‘viewBox’ is visible within the viewport the ‘viewBox’ is scaled up as much as possible, while still meeting the other criteria. In this case, if the aspect ratio of the graphic does not match the viewport, some of the viewport will extend beyond the bounds of the ‘viewBox’ (i.e., the area into which the ‘viewBox’ will draw will be smaller than the viewport).
  • slice - Scale the graphic such that: aspect ratio is preserved the entire viewport is covered by the ‘viewBox’ the ‘viewBox’ is scaled down as much as possible, while still meeting the other criteria. In this case, if the aspect ratio of the ‘viewBox’ does not match the viewport, some of the ‘viewBox’ will extend beyond the bounds of the viewport (i.e., the area into which the ‘viewBox’ will draw is larger than the viewport).

When no preserveAspectRatio is provided, a default value of xMidYMid meet is used. The result of this default value is that the aspect ratio is enforced, the midpoint x, y value of the viewBox is aligned with the midpoint x,y value of the viewport, all of the viewBox is visible in the viewport and is scaled as large as possible while still maintaining the same aspect ratio.

What all this means is that the preserveAspectRatio default value preserves the image aspect ratio in as large and non-disruptive manner as possible.

Most of the time, the default will suit your needs. However, sometimes you may want your image to scale to fit the viewport completely, or you’re not as concerned about maintaining the aspect ratio. That’s when you’re going to need to try out different preserveAspectRatio values to find the one that suits your needs.

To see what happens with various preserveAspectRatio settings, I created an application that allows the user to select an align parameter, and then one of the meetOrSlice values. Both are concatenated and used to modify the SVG element. In addition, the preserveAspectRatio setting used is printed beneath the SVG, for verification purposes.

The control elements for the demonstration:

<select id="align">
  <option value="none">none</option>
  <option value="xMinYMin">xMinYMin</option>
  <option value="xMidYMin">xMidYMin</option>
  <option value="xMaxYMin">xMaxYMin</option>
  <option value="xMinYYMid">xMinYMid</option>
  <option value="xMidYMid">xMidYMid</option>
  <option value="xMaxYMid">xMaxYMid</option>
  <option value="xMinYMax">xMinYMax</option>
  <option value="xMidYMax">xMidYMax</option>
  <option value="xMaxYMax">xMaxYMax</option></select>
  <br />

<input type="radio" name="meetOrSlice"
value="meet">meet<br>
<input type="radio" name="meetOrSlice"
value="slice">slice<br />

<button type="button"
  onclick="changeAspect()">Run Example</button>

The controlling JavaScript:

function changeAspect() {

 var mtslice="";
 var align=document.getElementById("align");
 var alignVal = align.options[align.selectedIndex].value;

 if (alignVal != "none") {

     var meetOrSlice =
       document.getElementsByName("meetOrSlice");

    for (var i = 0; i < meetOrSlice.length; i++) {
      if (meetOrSlice[i].checked) {
         mtslice=meetOrSlice[i].value;
         break;
      }
    }

  }

 var preserve = alignVal + " " + mtslice;

 document.getElementById("svgelem").
 setAttribute("preserveAspectRatio",preserve);

 document.getElementById("preserve").innerHTML=
   "<p>Aspect setting: " + preserve + "</p>";

}

Finally, the svg element and the div element for holding the text of the aspect ratio setting:

<svg id="svgelem" width="300" height="300"
  viewBox="0,0,600,1200"
  preserveAspectRatio="xMaxYMax meet"
  style="border: 1px solid black; background-color: white">
    <rect id="rect1" x="30" y="30" width="400"
    height="400" fill="red" stroke="yellow"
    stroke-width="10" />
</svg>
<div id="preserve"></div>

Putting it altogether, you can try out the different aspect ratio settings until you get a good idea of how it all fits together.

Start with selecting none first, to see what the figure looks like when the aspect ratio is not preserved.

Inserting a Circle Using Canvas

Problem

You want to create an arbitrarily sized and placed circle in a web page using the canvas element.

Solution

Insert a canvas element into the web page:

<canvas width="300" height="300" id="imgcanvas"
style="border: 1px solid black; background-color: white">
<p>A simple rectangle</p>
</canvas>

Then use the Canvas 2D Context to create the circle shape:

var canvas = document.getElementById("imgcanvas");

// if canvas element successfully accessed
if (canvas.getContext) {

   // get 2D context
   var ctx = canvas.getContext('2d');

   // set circle fill and outline colors
   ctx.fillStyle="rgb(255,0,0)";
   ctx.strokeStyle="#000000";

   // begin path
   ctx.beginPath();

   // draw circle
   ctx.arc(150,150,150,0,Math.PI*2,true);

   // close path
   ctx.closePath();

   // fill and outline
   ctx.fill();
   ctx.stroke();

 }

Discussion

The canvas 2d context only supports a built-in rectangle shape. Any other shape is going to require the use of a Canvas path.

A Canvas path begins and ends with beginPath() and endPath(). The actual makeup of the path is drawn with various canvas context methods, but in this example, we’re focusing only on one, arc().

The arc() method can be used to draw a circle, or parts of the circumference of a circle. It takes, as parameters, an x, y value representing the center of a circle, the radius, the starting angle, ending angle, and a boolean indicating whether to draw the circle in a clockwise direction (false), or anticlockwise direction (true).

To create a circle, use zero (0) as a beginning angle, and Math.PI*2. as the ending angle. Specify whatever radius and origin suits your needs.

ctx.beginPath();
ctx.arc(x,y,radius,0,Math.PI*2,true);
ctx.closePath();

Once the path is defined, it needs to be drawn. You can outline the circle using the stroke() method, and fill an enclosed path with fill(). The following JavaScript:

ctx.fillStyle="rgb(255,0,0)";
ctx.strokeStyle="#000000";

ctx.beginPath();

ctx.arc(x,y,radius,0,Math.PI*2,true);

ctx.closePath();

ctx.fill();
ctx.stroke();

Creates a red circle with black border centered in the canvas element’s space.

To get a better idea of how arc() works, modify the y and y coordinate of the origin and the arc radius in the following example to see what the impact each has on the finished drawing. Note that any part of the circle that does not fit into the canvas element is visibly clipped at the element’s borders.

Canvas and Accessibility

It’s important to provide fallback content not only if JavaScript is not enabled, but also for accessibility purposes.

Current work is underway with the W3C to provide more in-depth accessibility information with the canvas element. Until implemented, though, you shouldn’t use the canvas element for important information (unless you provide a fallback), or for site navigation or other critical site use.

Creating a Circle in SVG

Problem

You want to dynamically create an arbitrarily sized circle in a web page using SVG, rather than statically creating the circle.

Solution

Use document.createElementNS() to create the new circle, setAttribute() to set each attribute you want to set, and then appendChild() to add the newly created circle to the existing svg element in the web page.

var svgelem = document.getElementById('svgelem');

// create circle
// note use of namespace
var circle =
  document.createElementNS("http://www.w3.org/2000/svg", "circle");

circle.setAttribute("cx", 150);
circle.setAttribute("cy", 150);
circle.setAttribute("r",  150);
circle.setAttribute("fill", "red");
circle.setAttribute("stroke", "black");

svgelem.appendChild(circle);

Discussion

Creating a circle in SVG is no different than creating a div element with text, or rows in an HTML table. You create the new element, you assign values to its attributes, and then you append the new element to an existing web page element.

The one difference, and it is significant, is that with svg, you have to use the namespace version of the DOM methods to create the internal SVG elements, as only the svg element is within the HTML5 namespace—not the SVG elements, themselves.

var circle =
  document.createElementNS("http://www.w3.org/2000/svg", "circle");

Once you’ve created the new element, then you can use the non-namespace specific DOM methods to finish up your task. You can assign values to its attributes using setAttribute():

circle.setAttribute("cy", 150);

You can append the new element to its parent element with appendChild():

svgelem.appendChild(circle);

The result is a red circle with black border identical in appearance to the one created using Canvas, earlier in this chapter.

To get a better idea of how creating circles works, create an application that takes parameters for circles and adds them to the same svg element. Each circle overlaps earlier circles, as they are added to the web page.

The input controls:

<label>cx: </label><input type="text" value="150" id="cx" />
<br />
<label>cy: </label><input type="text" value="150" id="cy" />
<br />
<label>radius: </label><input type="text" value="150" id="r" />
<br />
<label>fill: </label><input type="text" value="red" id="fill" />
<br />
<label>stroke: </label><input type="text" value="black"
id="stroke" />
<br />
<button type="button" onclick="drawCircle()">Run Example</button>

The parent svg element:

<svg id="svgelem" width="300" height="300"
  style="border: 1px solid black; background-color: white">
  </svg>

And the JavaScript that controls it all:

function drawCircle() {

  var svgelem = document.getElementById('svgelem');

  // get attributes
  var cx = document.getElementById('cx').value;
  var cy = document.getElementById('cy').value;
  var r = document.getElementById('r').value;
  var fill = document.getElementById('fill').value;
  var stroke = document.getElementById('stroke').value;

  // create circle
  // note use of namespace
  var circle =
  document.createElementNS("http://www.w3.org/2000/svg", "circle");

  circle.setAttribute('cx', cx);
  circle.setAttribute('cy', cy);
  circle.setAttribute('r',  r);
  circle.setAttribute('fill', fill);
  circle.setAttribute('stroke', stroke);

  svgelem.appendChild(circle);
}

There is no way to clear the display space in SVG as there is with Canvas. Canvas is a bitmap environment, while SVG is vector-based. The only way to clear the svg element space would be to remove all existing element using the DOM.

Try differing sizes of circles, positioned all throughout the svg element space to see how the new elements overlap.

Of course, an advantage to SVG being vector-based, not bitmap, is that it’s very easy to animate individual components of the SVG space (demonstrated earlier), as well as attach events to each element. The only way to catch events for Canvas elements, such as capturing mouse clicks for a Canvas circle, is to capture the mouse click for the canvas element, and extrapolate its position relative to whatever objects are in the work space.

Microsoft was late to the game when it comes to both Canvas and SVG, but has been making up for lost time. One of the better discussions on the relative advantages to each graphics approach—Canvas or SVG—can be found at the IEBlog, in an article titled Thoughts on when to use Canvas and SVG.