SVG and Canvas

CSCE 242

University of South Carolina


José M. Vidal [1]
http://jmvidal.cse.sc.edu/talks/canvassvg/ [2]

Examples taken from

1 Canvas

1.1 The Canvas Element

<div>
<script type="text/javascript">
  function draw(){
  var canvas = document.getElementById('tutorial');
  if (canvas.getContext){
  var ctx = canvas.getContext('2d');
  }
  }
</script>
<canvas style="border: 1px solid black" 
         id="tutorial" width="150" height="150"></canvas>
</div>

1.2 Shapes

function draw(){
  var canvas = document.getElementById('tutorial');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

    ctx.fillRect(25,25,100,100);
    ctx.clearRect(45,45,60,60);
    ctx.strokeRect(50,50,50,50);
  }
}
draw() [9]

function drawpath(){
  var canvas = document.getElementById('tutorial2');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');
      ctx.beginPath();
      ctx.moveTo(75,50);
      ctx.lineTo(100,75);
      ctx.lineTo(100,25);
      ctx.fill();
  }
}
drawpath() [10]

function drawface(){
  var canvas = document.getElementById('tutorial3');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');
      ctx.beginPath();
      ctx.arc(75,75,50,0,Math.PI*2,true); // Outer circle
      ctx.moveTo(110,75);
      ctx.arc(75,75,35,0,Math.PI,false);   // Mouth (clockwise)
      ctx.moveTo(65,65);
      ctx.arc(60,65,5,0,Math.PI*2,true);  // Left eye
      ctx.moveTo(95,65);
      ctx.arc(90,65,5,0,Math.PI*2,true);  // Right eye
      ctx.stroke();
  }
}
drawface() [11]

function drawcallout(){
  var canvas = document.getElementById('tutorial4');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

      // Quadratric curves example
      ctx.beginPath();
      ctx.moveTo(75,25);
      ctx.quadraticCurveTo(25,25,25,62.5);
      ctx.quadraticCurveTo(25,100,50,100);
      ctx.quadraticCurveTo(50,120,30,125);
      ctx.quadraticCurveTo(60,120,65,100);
      ctx.quadraticCurveTo(125,100,125,62.5);
      ctx.quadraticCurveTo(125,25,75,25);
      ctx.stroke();
  }
}
drawcallout() [12]

function drawheart(){
  var canvas = document.getElementById('tutorial5');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');

      // Bezier curves example
      ctx.beginPath();
      ctx.moveTo(75,40);
      ctx.bezierCurveTo(75,37,70,25,50,25);
      ctx.bezierCurveTo(20,25,20,62.5,20,62.5);
      ctx.bezierCurveTo(20,80,40,102,75,120);
      ctx.bezierCurveTo(110,102,130,80,130,62.5);
      ctx.bezierCurveTo(130,62.5,130,25,100,25);
      ctx.bezierCurveTo(85,25,75,37,75,40);
      ctx.fill();
  }
}
drawheart() [13]

1.3 Drawing Text

function writetext(){
  var canvas = document.getElementById('tutorial');
  if (canvas.getContext){
    var ctx = canvas.getContext('2d');
      ctx.translate(10,50);
      ctx.fillStyle = "red";
      ctx.mozDrawText("Hello There");
      ctx.stroke();
      //in Firefox 3.1 this will be:
      //ctx.fillText("Hello There", 0,0);
  }
}
writetext() [15]

var manifesto =
    'The Internet is becoming an increasingly important part of our lives. ' +
    'The Mozilla project is a global community of people who believe that openness, innovation, and opportunity are key to the continued health of the Internet. We have worked together since 1998 to ensure that the Internet is developed in a way that benefits everyone. We are best known for creating the Mozilla Firefox web browser. ' +
    'The Mozilla project uses a community-based approach to create world-class open source software and to develop new types of collaborative activities. We create communities of people involved in making the Internet experience better for all of us. ' +
    'As a result of these efforts, we have distilled a set of principles that we believe are critical for the Internet to continue to benefit the public good as well as commercial aspects of life';
var numsegs = 5;
var amplitude = 40;

function draw()
{
    canvas= document.getElementById('tutorial2');
    var width = canvas.width;
    var height = canvas.height;
    var ctx = canvas.getContext('2d');
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, width, height);
    ctx.save();
    ctx.translate(10, height/2);
    var segwidth = width/numsegs;
    ctx.moveTo(0,0);
     for(var i = 0; i < numsegs; i++)
    {
        var dx = segwidth * i;
        var dy = i % 2 ? amplitude : -amplitude;
        var cpx = dx + segwidth*0.5;
        var cpy = dy;
        ctx.bezierCurveTo(cpx,cpy,cpx,cpy,dx+segwidth,0);
    }
    ctx.fillStyle = "black";
    ctx.mozTextAlongPath(manifesto, false);
    ctx.restore();
}
draw() [16]

1.4 Using Images

  1. Create a new Image or use one from document.images.
  2. Use drawImage to draw it on the canvas.
function drawchart() {
    var ctx = document.getElementById('canvas').getContext('2d');
    var img = new Image();
    img.src = 'backdrop.png';
    img.onload = function(){
        ctx.drawImage(img,0,0);
        ctx.beginPath();
        ctx.moveTo(30,96);
        ctx.lineTo(70,66);
        ctx.lineTo(103,76);
        ctx.lineTo(170,15);
        ctx.stroke();
    }
}
drawchart() [17]

1.5 Color

// these all set the fillStyle to 'orange'
ctx.fillStyle = "orange";
ctx.fillStyle = "#FFA500";
ctx.fillStyle = "rgb(255,165,0)";
ctx.fillStyle = "rgba(255,165,0,1)";
function drawcolors() {
  var ctx = document.getElementById('canvas').getContext('2d');
  for (i=0;i<6;i++){
    for (j=0;j<6;j++){
      ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' + 
                       Math.floor(255-42.5*j) + ',0)';
      ctx.fillRect(j*25,i*25,25,25);
    }
  }
}
      
drawcolors() [18]

function drawtransparency() {
  var ctx = document.getElementById('canvas2').getContext('2d');
  // draw background
  ctx.fillStyle = '#FD0';
  ctx.fillRect(0,0,75,75);
  ctx.fillStyle = '#6C0';
  ctx.fillRect(75,0,75,75);
  ctx.fillStyle = '#09F';
  ctx.fillRect(0,75,75,75);
  ctx.fillStyle = '#F30';
  ctx.fillRect(75,75,150,150);
  ctx.fillStyle = '#FFF';

  // set transparency value
  ctx.globalAlpha = 0.2;

  // Draw semi transparent circles
  for (i=0;i<7;i++){
      ctx.beginPath();
      ctx.arc(75,75,10+10*i,0,Math.PI*2,true);
      ctx.fill();
  }
}
drawtransparency() [19]

function drawlineargradient() {
  var ctx = document.getElementById('canvas3').getContext('2d');

  // Create gradients
  var lingrad = ctx.createLinearGradient(0,0,0,150);
  lingrad.addColorStop(0, '#00ABEB');
  lingrad.addColorStop(0.5, '#fff');
  lingrad.addColorStop(0.5, '#26C000');
  lingrad.addColorStop(1, '#fff');

  var lingrad2 = ctx.createLinearGradient(0,50,0,95);
  lingrad2.addColorStop(0.5, '#000');
  lingrad2.addColorStop(1, 'rgba(0,0,0,0)');

  // assign gradients to fill and stroke styles
  ctx.fillStyle = lingrad;
  ctx.strokeStyle = lingrad2;
  
  // draw shapes
  ctx.fillRect(10,10,130,130);
  ctx.strokeRect(50,50,50,50);

}
drawlineargradient() [20]

1.6 Line Styles

function drawlines() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var lineCap = ['butt','round','square'];

  // Draw guides
  ctx.strokeStyle = '#09f';
  ctx.beginPath();
  ctx.moveTo(10,10);
  ctx.lineTo(140,10);
  ctx.moveTo(10,140);
  ctx.lineTo(140,140);
  ctx.stroke();

  // Draw lines
  ctx.strokeStyle = 'black';
  for (i=0;i<lineCap.length;i++){
    ctx.lineWidth = 15;
    ctx.lineCap = lineCap[i];
    ctx.beginPath();
    ctx.moveTo(25+i*50,10);
    ctx.lineTo(25+i*50,140);
    ctx.stroke();
  }
}
drawlines() [21]

function drawlinejoin() {
  var ctx = document.getElementById('canvas2').getContext('2d');
  var lineJoin = ['round','bevel','miter'];
  ctx.lineWidth = 10;
  for (i=0;i<lineJoin.length;i++){
    ctx.lineJoin = lineJoin[i];
    ctx.beginPath();
    ctx.moveTo(-5,5+i*40);
    ctx.lineTo(35,45+i*40);
    ctx.lineTo(75,5+i*40);
    ctx.lineTo(115,45+i*40);
    ctx.lineTo(155,5+i*40);
    ctx.stroke();
  }
}
drawlinejoin() [22]

1.7 Save and Restore

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

ctx.fillRect(0,0,150,150);   //  draw a rectangle with default settings
ctx.save();                  //  Save the default state

ctx.fillStyle = '#09F'       // Make changes to the settings
ctx.fillRect(15,15,120,120); // Draw a rectangle with new settings

ctx.save();                  // Save the current state
ctx.fillStyle = '#FFF'       // Make changes to the settings
ctx.globalAlpha = 0.5;    
ctx.fillRect(30,30,90,90);   // Draw a rectangle with new settings

ctx.restore() [23]
ctx.fillRect(45,45,60,60); [24] - is not alpha blended.
ctx.restore() [25]
ctx.fillRect(60,60,30,30); [26] - fillstyle is now black

1.8 Transformations

function drawtranslate() {
    var ctx = document.getElementById('canvas').getContext('2d');
    ctx.fillRect(0,0,300,300);
      for (var i=0;i<3;i++) {
        for (var j=0;j<3;j++) {
            ctx.save();
            ctx.strokeStyle = "#9CFF00";
            ctx.translate(50+j*100,50+i*100);
            drawSpirograph(ctx,20*(j+2)/(j+1),-8*(i+3)/(i+1),10);
            ctx.restore();
        }
      }
}
function drawSpirograph(ctx,R,r,O){
    var x1 = R-O;
    var y1 = 0;
    var i  = 1;
    ctx.beginPath();
    ctx.moveTo(x1,y1);
      do {
        if (i>20000) break;
          var x2 = (R+r)*Math.cos(i*Math.PI/72) - (r+O)*Math.cos(((R+r)/r)*(i*Math.PI/72))
          var y2 = (R+r)*Math.sin(i*Math.PI/72) - (r+O)*Math.sin(((R+r)/r)*(i*Math.PI/72))
          ctx.lineTo(x2,y2);
          x1 = x2;
          y1 = y2;
          i++;
      } while (x2 != R-O && y2 != 0 );
    ctx.stroke();
}
drawtranslate() [27]

1.9 Compositing

drawcompositing() [28]












var compositeTypes = [
  'source-over','source-in','source-out','source-atop',
  'destination-over','destination-in','destination-out','destination-atop',
  'lighter','darker','copy','xor'
];
function drawcompositing(){
  for (i=0;i<compositeTypes.length;i++){
    var label = document.createTextNode(compositeTypes[i]);
    document.getElementById('lab'+i).appendChild(label);
    var ctx = document.getElementById('tut'+i).getContext('2d');

    // draw rectangle
    ctx.fillStyle = "#09f";
    ctx.fillRect(15,15,70,70);

    // set composite property
    ctx.globalCompositeOperation = compositeTypes[i];
    
    // draw circle
    ctx.fillStyle = "#f30";
    ctx.beginPath();
    ctx.arc(75,75,35,0,Math.PI*2,true);
    ctx.fill();
  }
}

1.9.1 Clip

function drawclip() {
  var ctx = document.getElementById('canvas').getContext('2d');
  ctx.fillRect(0,0,150,150);
  ctx.translate(75,75);

  // Create a circular clipping path        
  ctx.beginPath();
  ctx.arc(0,0,60,0,Math.PI*2,true);
  ctx.clip();

  // draw background
  var lingrad = ctx.createLinearGradient(0,-75,0,75);
  lingrad.addColorStop(0, '#232256');
  lingrad.addColorStop(1, '#143778');
  
  ctx.fillStyle = lingrad;
  ctx.fillRect(-75,-75,150,150);

  // draw stars
  for (j=1;j<50;j++){
    ctx.save();
    ctx.fillStyle = '#fff';
    ctx.translate(75-Math.floor(Math.random()*150),
                  75-Math.floor(Math.random()*150));
    drawStar(ctx,Math.floor(Math.random()*4)+2);
    ctx.restore();
  }
  
}
function drawStar(ctx,r){
  ctx.save();
  ctx.beginPath()
  ctx.moveTo(r,0);
  for (i=0;i<9;i++){
    ctx.rotate(Math.PI/5);
    if(i%2 == 0) {
      ctx.lineTo((r/0.525731)*0.200811,0);
    } else {
      ctx.lineTo(r,0);
    }
  }
  ctx.closePath();
  ctx.fill();
  ctx.restore();
}
drawclip() [29]

1.10 Animation

var sun = new Image();
var moon = new Image();
var earth = new Image();
function init(){
  sun.src = 'sun.png';
  moon.src = 'moon.png';
  earth.src = 'earth.png';
  setInterval('draw()',100);
}

function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');

  ctx.globalCompositeOperation = 'destination-over';
  ctx.clearRect(0,0,300,300); // clear canvas

  ctx.save();
  ctx.fillStyle = 'rgba(0,0,0,0.4)';
  ctx.strokeStyle = 'rgba(0,153,255,0.4)';
  ctx.translate(150,150);

  // Earth
  var time = new Date();
  ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
  ctx.translate(105,0);
  ctx.fillRect(0,-12,50,24); // Shadow
  ctx.drawImage(earth,-12,-12);

  // Moon
  ctx.save();
  ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
  ctx.translate(0,28.5);
  ctx.drawImage(moon,-3.5,-3.5);
  ctx.restore();

  ctx.restore();
  
  ctx.beginPath();
  ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit
  ctx.stroke();
 
  ctx.drawImage(sun,0,0);
}
init();draw(); [30]

1.10.1 Blob

2 SVG

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="9cm"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     version="1.1"
     baseProfile="full">
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
    <circle cx="6cm" cy="2cm" r="100" fill="red"
                    transform="translate(0,50)" />
    <circle cx="6cm" cy="2cm" r="100" fill="blue"
                    transform="translate(70,150)" />
    <circle cx="6cm" cy="2cm" r="100" fill="green"
                    transform="translate(-70,150)" />
  </g>
</svg>

2.1 Basics

2.2 Shapes

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
    <rect x="20" y="20" rx="0" ry="0" fill="red" width="20%" height="20%"/>
  </g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
     <circle cx="100" cy="100" r="90px" fill="blue" />
  </g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
<line x1="10" y1="10" x2="190" y2="190" stroke="blue" stroke-width="4" />
  </g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
<polyline points="10,190 20,190 20,150 50,150 50,190 80,190 
  80,110 110,110 110,190 140,190 140,70 
  170,70 170,190 190,190" stroke="blue" fill="darkblue" stroke-width="4" />
  </g>
</svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
<polygon points="100,10 40,180 190,60 10,60 160,180 100,10" stroke="blue" fill="darkblue" stroke-width="4" fill-rule="nonzero" />
  </g>
</svg>

2.3 Image

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g stroke="black" stroke-width="0.1cm">
    <image x="0" y="20" width="200" height="180" xlink:href="backdrop.png" />
  </g>
</svg>

2.4 Text

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="200px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g stroke="black" stroke-width="1px">
<text  x="50%" y="50%," dx="0,0,0,0,20" dy="0,0,0,0,8"
                        rotate="20,30,40,50,0,0,-10" 
                        textLength="..." 
                        lengthAdjust="..." 
         font-size="30" text-anchor="middle" >Hello World</text>
  </g>
</svg>

2.5 Color

Class ExplanationExample
Keyword
SVG defines everything from 'aliceblue' to 'yellowgreen' on its type page [34].
Aliceblue
Functional
A functional way to define the color. Either values in the range from 0 to 255 or percentages can be used. Mixing percents and values is illegal.
rgb(255,255,255)
rgb(100%,100%,100%)
Hexadecimal
This is the same way colors are defined in HTML.
#FFFFFF
URI
A reference to a color gradient or pattern. Described later...
url(#MyGradient)

2.6 Defs and Use

<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="250px"
     xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full">
  <g fill-opacity="0.7" stroke="black" stroke-width="0.1cm">
<defs>
<g id="group1" fill="green" opacity="0.9" >
<rect x="20" y="20" width="100" height="100" opacity="0.5" />
<rect x="80" y="80" width="100" height="100" fill="gray" />
</g>
</defs>
<use x="0" y="0" width="200" height="200" xlink:href="#group1" />
<use x="0" y="0" width="200" height="200" xlink:href="#group1" transform="rotate(70, 100, 100)" />
  </g>
</svg>

2.7 Gradient

<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve"
         width="100%" height="200" viewBox="0 0 1200 200" >
        <defs>
        <linearGradient id="myFillGrad" >
            <stop offset="5%" stop-color="red" />
            <stop offset="95%" stop-color="blue" stop-opacity="0.5" />
        </linearGradient>
        </defs>

        <!-- Gradient Example -->
    <rect x="20" y="20" width="1160" height="160" fill="url(#myFillGrad)" stroke="black" 
        stroke-width="2" />
</svg>

2.8 Transformations

2.9 Path

2.10 JavaScript and SVG

$(document).ready(function() {
   $('#canvas').svg({onLoad: drawInitial});});

function drawInitial(svg) {
        svg.circle(75, 75, 50, {fill: 'none', stroke: 'red', 'stroke-width': 3});
        var g = svg.group({stroke: 'black', 'stroke-width': 2});
        svg.line(g, 15, 75, 135, 75);
        svg.line(g, 75, 15, 75, 135);
}
$('#canvas').svg('get').rect(50,50,15,15,{fill: 'none', stroke: 'blue', 'stroke-width': 3});

URLs

  1. José M. Vidal, http://jmvidal.cse.sc.edu
  2. http://jmvidal.cse.sc.edu/talks/canvassvg/, http://jmvidal.cse.sc.edu/talks/canvassvg/
  3. Canvas Tutorial, http://developer.mozilla.org/en/HTML/Canvas
  4. Interactive Canvas Tutorial, http://billmill.org/static/canvastutorial/
  5. SVG Presentation, http://www.w3.org/Consortium/Offices/Presentations/SVG/
  6. W3C standard, http://www.w3.org/Graphics/SVG/
  7. SVG Tutorial, http://apike.ca/prog_svg_intro.html
  8. ExplorerCanvas, http://excanvas.sourceforge.net/
  9. draw(), javascript:draw()
  10. drawpath(), javascript:drawpath()
  11. drawface(), javascript:drawface()
  12. drawcallout(), javascript:drawcallout()
  13. drawheart(), javascript:drawheart()
  14. drawing text tutorial, https://developer.mozilla.org/en/Drawing_text_using_a_canvas
  15. writetext(), javascript:writetext()
  16. draw(), javascript:draw()
  17. drawchart(), javascript:drawchart()
  18. drawcolors(), javascript:drawcolors()
  19. drawtransparency(), javascript:drawtransparency()
  20. drawlineargradient(), javascript:drawlineargradient()
  21. drawlines(), javascript:drawlines()
  22. drawlinejoin(), javascript:drawlinejoin()
  23. ctx.restore(), javascript:ctx.restore()
  24. ctx.fillRect(45,45,60,60);, javascript:ctx.fillRect(45,45,60,60);
  25. ctx.restore(), javascript:ctx.restore()
  26. ctx.fillRect(60,60,30,30);, javascript:ctx.fillRect(60,60,30,30);
  27. drawtranslate(), javascript:drawtranslate()
  28. drawcompositing(), javascript:drawcompositing()
  29. drawclip(), javascript:drawclip()
  30. init();draw();, javascript:init();draw()
  31. W3C standard, http://www.w3.org/Graphics/SVG/
  32. Firefox, http://developer.mozilla.org/en/docs/SVG_in_Firefox
  33. inkscape, http://www.inkscape.org/download/?lang=en
  34. type page, http://www.w3.org/TR/SVG11/types.html#ColorKeywords
  35. jQuery SVG plugin, http://keith-wood.name/svg.html

This talk available at http://jmvidal.cse.sc.edu/talks/canvassvg/
Copyright © 2009 José M. Vidal . All rights reserved.

05 March 2009, 09:42AM