Gavin Doughtie

xdraw.org

Jon Stewart

jonathan.l.stewart@gmail.com

July 26, 2006

Slides http://www.xdraw.org/oscon_slides/

Java ActiveX VRML Shockwave<

Even 3-Dimensional Crossword Puzzles (!!)

And the winner is...

Flash
  • Installed Everywhere
  • Rich Media Capabilities
  • Great Editing Tools and more
  • CanvasScape
    http://www.abrahamjoffe.com.au/ben/canvascape/
  • SVG Drawing Editor
    http://www.xdraw.org/
  • Canvas Painter
    http://caimansys.com/painter/
  • Chiptune.com
FirefoxOperaSafariInternet Explorer
DOMALL
Vector GraphicsSVGSVGSVGVML
Bitmap CanvasCanvasCanvasCanvasDirect Animation*
  • CSS Properties
  • Bitmap Images
  • Text
  • Declarative
  • Access via Javascript
  • Walter Zorn's Crazy Library (Hello, world!)
function drawShapes() { // get the canvas: var ctx = new jsGraphics('gfx'); // Circle parameters: var r = 50; var cx = 150; var cy = 100; var strokeWeight = 15; // Draw the solid circle: ctx.setColor("#ff0000"); ctx.fillEllipse(cx - r, cy - r, r * 2, r * 2); // Draw the stroked outline: ctx.setColor("#ffbb00"); ctx.setStroke(strokeWeight); var strokeOffset = strokeWeight / 2; ctx.drawEllipse(cx - r - strokeOffset, cy - r - strokeOffset, r * 2, r * 2); ctx.paint(); // <--- forces DIVs to render ...
function drawShapes() { // get the canvas: var ctx = new jsGraphics('gfx'); // Circle parameters: var r = 50; var cx = 150; var cy = 100; var strokeWeight = 15; // Draw the solid circle: ctx.setColor("#ff0000"); ctx.fillEllipse(cx - r, cy - r, r * 2, r * 2); // Draw the stroked outline: ctx.setColor("#ffbb00"); ctx.setStroke(strokeWeight); var strokeOffset = strokeWeight / 2; ctx.drawEllipse(cx - r - strokeOffset, cy - r - strokeOffset, r * 2, r * 2); ctx.paint(); // <--- forces DIVs to render ...
... var ctx = new jsGraphics('gfx2'); ctx.setColor("#00ff00"); //draw the filled ellipse ctx.fillEllipse(cx - rx, cy - ry, rx * 2 , ry * 2); strokeWeight = 5; ctx.setStroke(strokeWeight); ctx.setColor("#00ffbb"); strokeOffset = strokeWeight / 2; // draw the stroked ellipse ctx.drawEllipse(cx - rx - strokeOffset, cy - ry - strokeOffset, rx * 2, ry * 2); // paint everything ctx.paint(); setOpacity(document.getElementById('gfx2'), 0.5); }
... var ctx = new jsGraphics('gfx2'); ctx.setColor("#00ff00"); //draw the filled ellipse ctx.fillEllipse(cx - rx, cy - ry, rx * 2 , ry * 2); strokeWeight = 5; ctx.setStroke(strokeWeight); ctx.setColor("#00ffbb"); strokeOffset = strokeWeight / 2; // draw the stroked ellipse ctx.drawEllipse(cx - rx - strokeOffset, cy - ry - strokeOffset, rx * 2, ry * 2); // paint everything ctx.paint(); setOpacity(document.getElementById('gfx2'), 0.5); }
<script> function setOpacity(aDiv, aVal) { for (var i = 0; i < aDiv.childNodes.length; ++i) { aDiv.childNodes[i].style['opacity'] = aVal; } } </script> <!--[if gte IE 6]><script> function setOpacity(aDiv, aVal) // IE version of transparency fixer: { for (var i = 0; i < aDiv.childNodes.length; ++i) { var node = aDiv.childNodes[i]; if (node && node.style) { node.style.filter = "Alpha(Opacity=" + aVal * 100 + ")"; } } }</script><![endif]-->
  • Drawing Shapes
  • Paths
  • Fancy Filling and Clipping
  • Affine Transforms
  • W3 Standard
  • Available now
  • Broad Application Support
  • Not in IE

Hello, Static World!
Hello, Dynamic World!

<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="275px" width="275px"> <circle cx="150px" cy="100px" r="50px" fill="#ff0000" stroke="#ffbb00" stroke-width="15px"/> <ellipse cx="200px" cy="120px" rx="50px" ry="100px" fill="#00ff00" stroke="#00ffbb" stroke-width="5px" opacity="0.5"/> </svg>
<svg version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="275px" width="275px"> <circle cx="150px" cy="100px" r="50px" fill="#ff0000" stroke="#ffbb00" stroke-width="15px"/> <ellipse cx="200px" cy="120px" rx="50px" ry="100px" fill="#00ff00" stroke="#00ffbb" stroke-width="5px" opacity="0.5"/> </svg>
function drawShapes() { var gfx = document.getElementById('gfx'); var svg = document.createElementNS( "http://www.w3.org/2000/svg", 'svg'); svg.setAttribute('width', 275); svg.setAttribute('height', 275); gfx.appendChild(svg); var circle = document.createElementNS( "http://www.w3.org/2000/svg", 'circle'); circle.setAttribute('cx', "150px"); circle.setAttribute('cy', "100px"); circle.setAttribute('r', "50px"); circle.setAttribute("stroke", "#ffbb00"); circle.setAttribute("stroke-width", "15px"); circle.setAttribute('fill', '#ff0000'); svg.appendChild(circle);
function drawShapes() { var gfx = document.getElementById('gfx'); var svg = document.createElementNS( "http://www.w3.org/2000/svg", 'svg'); svg.setAttribute('width', 275); svg.setAttribute('height', 275); gfx.appendChild(svg); var circle = document.createElementNS( "http://www.w3.org/2000/svg", 'circle'); circle.setAttribute('cx', "150px"); circle.setAttribute('cy', "100px"); circle.setAttribute('r', "50px"); circle.setAttribute("stroke", "#ffbb00"); circle.setAttribute("stroke-width", "15px"); circle.setAttribute('fill', '#ff0000'); svg.appendChild(circle);
var ellipse = document.createElementNS( "http://www.w3.org/2000/svg", 'ellipse'); ellipse.setAttribute('cx', "200px"); ellipse.setAttribute('cy', "120px"); ellipse.setAttribute('rx', "50px"); ellipse.setAttribute('ry', "100px"); ellipse.setAttribute('fill', "#00ff00"); ellipse.setAttribute('stroke', "#00ffbb"); ellipse.setAttribute('stroke-width', "5px"); ellipse.setAttribute('opacity', "0.5"); svg.appendChild(ellipse);
  • W3 Proposal (predating SVG)
  • Available in IE
  • Microsoft Office Support

Hello, Static World!
Hello, Dynamic World!

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft.com:vml" xml:lang="en"> <head> <!--[if gte IE 6]> <object id="VMLRender" classid="CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E"> </object> <style type="text/css"> v\:* { behavior: url(#VMLRender) } </style> <![endif]--> </head>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft.com:vml" xml:lang="en"> <head> <!--[if gte IE 6]> <object id="VMLRender" classid="CLSID:10072CEC-8CC1-11D1-986E-00A0C955B42E"> </object> <style type="text/css"> v\:* { behavior: url(#VMLRender) } </style> <![endif]--> </head>
<body> <div id="gfx" width="300px" height="300px"> <v:group style="width: 300px; height: 300px;" coordsize="30,30"> <!-- local coordinate space for group --> <v:oval style="position: absolute; left: 10; top: 5; width: 10; height: 10" fill="true" fillcolor="#ff0000" strokeweight="15px" strokecolor="#ffbb00"/> <v:oval style="position: absolute; left: 15; top: 2; width: 10; height: 20;"/> </v:group> </div> </body>
<body> <div id="gfx" width="300px" height="300px"> <v:group style="width: 300px; height: 300px;" coordsize="30,30"> <!-- local coordinate space for group --> <v:oval style="position: absolute; left: 10; top: 5; width: 10; height: 10" fill="true" fillcolor="#ff0000" strokeweight="15px" strokecolor="#ffbb00"/> <v:oval style="position: absolute; left: 15; top: 2; width: 10; height: 20;"/> </v:group> </div> </body>
<body> <div id="gfx" width="300px" height="300px"> <v:group style="width: 300px; height: 300px;" coordsize="30,30"> <!-- local coordinate space for group --> <v:oval style="position: absolute; left: 10; top: 5; width: 10; height: 10" fill="true" fillcolor="#ff0000" strokeweight="15px" strokecolor="#ffbb00"/> <v:oval style="position: absolute; left: 15; top: 2; width: 10; height: 20;"/> </v:group> </div> </body>
<body> <div id="gfx" width="300px" height="300px"> <v:group style="width: 300px; height: 300px;" coordsize="30,30"> <!-- local coordinate space for group --> <v:oval style="position: absolute; left: 10; top: 5; width: 10; height: 10" fill="true" fillcolor="#ff0000" strokeweight="15px" strokecolor="#ffbb00"/> <v:oval style="position: absolute; left: 15; top: 2; width: 10; height: 20;"> <v:stroke opacity="0.5" color="#00ffbb" weight="5px"/> <v:fill opacity="0.5" color="#00ff00"/> </v:oval> </v:group> </div> </body>
  • Imperative
  • Familiar to Programmers
  • Lightweight
  • Like an <img> tag you can draw on
  • Javascript API
  • Similar to GDI, Java Graphics, X Drawable
  • WHATWG standard
  • Not in IE

Hello, World!

<body onload="drawShapes();"> <div id="gfx"> <canvas id="canvas" width="275px" height="275px"> </canvas> <!-- end tag is required so it works in both safari and ffox --> </div> </body>
function drawShapes() { // Used to compute control points var KAPPA = 4 * ((Math.sqrt(2) -1) / 3); // Total number of radians in a circle var RADIANS = 2*Math.PI; // Get the canvas element var canvas = document.getElementById('canvas'); // Get the 2D context from the element var ctx = canvas.getContext('2d'); // Draw the circle var cx = 150; var cy = 100; var r = 50; ...
... ctx.save(); ctx.fillStyle = "#ff0000"; ctx.strokeStyle = "#ffbb00" ctx.lineWidth = 15; ctx.translate(cx, cy); ctx.beginPath(); // Move to outer edge before stroking, // or Opera draws a line: ctx.moveTo(r, 0); ctx.arc(0,0, r, 0, RADIANS ,1); ctx.fill(); // closes the path ctx.stroke(); ...
... ctx.save(); ctx.fillStyle = "#ff0000"; ctx.strokeStyle = "#ffbb00" ctx.lineWidth = 15; ctx.translate(cx, cy); ctx.beginPath(); // Move to outer edge before stroking, // or Opera draws a line: ctx.moveTo(r, 0); ctx.arc(0,0, r, 0, RADIANS ,1); ctx.fill(); // closes the path ctx.stroke(); ...
... ctx.save(); ctx.fillStyle = "#ff0000"; ctx.strokeStyle = "#ffbb00" ctx.lineWidth = 15; ctx.translate(cx, cy); ctx.beginPath(); // Move to outer edge before stroking, // or Opera draws a line: ctx.moveTo(r, 0); ctx.arc(0,0, r, 0, RADIANS ,1); ctx.fill(); // closes the path ctx.stroke(); ...
... cx = 200; cy = 120; var rx = 50; var ry = 100; ctx.fillStyle = '#00ff00'; ctx.lineWidth = 5; ctx.strokeStyle = "#00ffbb"; ctx.globalAlpha = 0.5; // No oval primitive, so draw with bezier curves ctx.save(); ctx.beginPath(); ctx.moveTo(cx, cy - ry); ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy); ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry); ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy); ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry); ctx.fill(); ctx.stroke(); ctx.restore(); }
... cx = 200; cy = 120; var rx = 50; var ry = 100; ctx.fillStyle = '#00ff00'; ctx.lineWidth = 5; ctx.strokeStyle = "#00ffbb"; ctx.globalAlpha = 0.5; // No oval primitive, so draw with bezier curves ctx.save(); ctx.beginPath(); ctx.moveTo(cx, cy - ry); ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy); ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry); ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy); ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry); ctx.fill(); ctx.stroke(); ctx.restore(); }
... cx = 200; cy = 120; var rx = 50; var ry = 100; ctx.fillStyle = '#00ff00'; ctx.lineWidth = 5; ctx.strokeStyle = "#00ffbb"; ctx.globalAlpha = 0.5; // No oval primitive, so draw with bezier curves ctx.save(); ctx.beginPath(); ctx.moveTo(cx, cy - ry); ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy); ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry); ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy); ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry); ctx.fill(); ctx.stroke(); ctx.restore(); }
... cx = 200; cy = 120; var rx = 50; var ry = 100; ctx.fillStyle = '#00ff00'; ctx.lineWidth = 5; ctx.strokeStyle = "#00ffbb"; ctx.globalAlpha = 0.5; // No oval primitive, so draw with bezier curves ctx.save(); ctx.beginPath(); ctx.moveTo(cx, cy - ry); ctx.bezierCurveTo(cx + (KAPPA * rx), cy - ry, cx + rx, cy - (KAPPA * ry), cx + rx, cy); ctx.bezierCurveTo(cx + rx, cy + (KAPPA * ry), cx + (KAPPA * rx), cy + ry, cx, cy + ry); ctx.bezierCurveTo(cx - (KAPPA * rx), cy + ry, cx - rx, cy + (KAPPA * ry), cx - rx, cy); ctx.bezierCurveTo(cx - rx, cy - (KAPPA * ry), cx - (KAPPA * rx), cy - ry, cx, cy - ry); ctx.fill(); ctx.stroke(); ctx.restore(); }
  • Javascript-accessible COM interface
  • IE-only
  • On its way out, even from IE

Hello, World!

function drawShapes() { var gfx = document.getElementById('gfx'); var width = 275; var height = 275; // Init the control (can also declare) var daControl = document.createElement('Object'); daControl.setAttribute('id', 'DAControl'); daControl.setAttribute('classid', "CLSID:B6FFC24C-7E13-11D0-9B47-00C04FC2F51D"); daControl.style.cssText = "position: absolute; left: 0; top: 0; width: " + width + "px; height: " + height + "px;"; gfx.appendChild(daControl); // The DirectAnimation library lib = DAControl.PixelLibrary; // as opposed to MeterLibrary
function drawShapes() { var gfx = document.getElementById('gfx'); var width = 275; var height = 275; // Init the control (can also declare) var daControl = document.createElement('Object'); daControl.setAttribute('id', 'DAControl'); daControl.setAttribute('classid', "CLSID:B6FFC24C-7E13-11D0-9B47-00C04FC2F51D"); daControl.style.cssText = "position: absolute; left: 0; top: 0; width: " + width + "px; height: " + height + "px;"; gfx.appendChild(daControl); // The DirectAnimation library var lib = DAControl.PixelLibrary; // as opposed to MeterLibrary ...
... var fillColor = lib.ColorRgb(1.0, 0.0, 0.0);// red var strokeColor = lib.ColorRgb(1.0, 0.73, 0.0); // orange var fill = lib.SolidColorImage(fillColor); var ls = lib.DefaultLineStyle. color(strokeColor). AntiAliasing(1).width(15 / 2); var radius = 50; var cx = 50; var cy = 100; var xform = lib.Translate2(-10, -30); var p = lib.Oval(radius * 2, radius * 2); var circleImg = p.Fill(ls, fill).Transform(xform); ...
... // Now draw the green ellipse: fillColor = lib.ColorRgb(0.0, 1.0, 0.0); // green strokeColor = lib.ColorRgb(0.0, 1.0, 0.73); // blue-green fill = lib.SolidColorImage(fillColor); ls = lib.DefaultLineStyle. color(strokeColor). AntiAliasing(1).width(5 / 2); xform = lib.Translate2(40, 0); p = lib.Oval(100, 200); var ellipseImg = p.Fill(ls, fill). Transform(xform).Opacity(0.5); ...
... var finalImg = lib.Overlay(ellipseImg, circleImg); // set the image to be displayed DAControl.Image = finalImg; // start the animation DAControl.Start(); }
... var finalImg = lib.Overlay(ellipseImg, circleImg); // set the image to be displayed DAControl.Image = finalImg; // start the animation DAControl.Start(); }
  • IE7 + Vista/IE7 + .NET 3.0 define unified graphics model: Windows Presentation Foundation
  • WPF API available for Windows applications and IE 7
  • XAML: XUL for Windows
  • XAML maps WPF API directly into XML
  • WPF API and XAML DOM are accessible to Javascript
Internet Explorer 7
  • Images rendered by server on-demand (Hello, World!)
  • Javascript-managed user interaction
  • Lots of high-quality server-side libraries
  • More demanding of server and bandwidth (Server drawing only) (With WZ Divs)
<body onload="fixTransparency('gfx');"> <div id="gfx"> <img src="/oscon/ellipse?rx=50&ry=50& fill=ff0000&stroke=ffbb00&strokeWeight=15&opacity=1.0" style="position: absolute; left: 120px; top: 70px;"> <img src="/oscon/ellipse?rx=50&ry=100& fill=00ff00&stroke=00ffbb&strokeWeight=5&opacity=0.5" style="position: absolute; left: 180px; top: 50px;"> </div> </body>
<body onload="fixTransparency('gfx');"> <div id="gfx"> <img src="/oscon/ellipse?rx=50&ry=50& fill=ff0000&stroke=ffbb00&strokeWeight=15&opacity=1.0" style="position: absolute; left: 120px; top: 70px;"> <img src="/oscon/ellipse?rx=50&ry=100& fill=00ff00&stroke=00ffbb&strokeWeight=5&opacity=0.5" style="position: absolute; left: 180px; top: 50px;"> </div> </body>
<body onload="fixTransparency('gfx');"> <div id="gfx"> <img src="/oscon/ellipse?rx=50&ry=50& fill=ff0000&stroke=ffbb00&strokeWeight=15&opacity=1.0" style="position: absolute; left: 120px; top: 70px;"> <img src="/oscon/ellipse?rx=50&ry=100& fill=00ff00&stroke=00ffbb&strokeWeight=5&opacity=0.5" style="position: absolute; left: 180px; top: 50px;"> </div> </body>
def ellipse uri = request.request_uri filename = 'public' + uri + '.png' if !FileTest.exists?(filename) p = request.parameters r = (p['r'] || 100).to_f rx = (p['rx'] || r).to_f ry = (p['ry'] || rx).to_f strokeWeight = (p['strokeWeight'] || 1.0).to_f width = (strokeWeight * 2) + (rx * 2.0) height = (strokeWeight * 2) + (ry * 2.0) cx = width / 2 cy = height / 2 ...
... fill = (p['fill'] || 'ffffff') fill = "\##{fill}" stroke = p['stroke'] || '000000' stroke = "\##{stroke}" opacity = (p['opacity'] || 1.0).to_f gc = Magick::Draw.new canvas = Magick::Image.new(width, height) gc.fill('white') render_ellipse(gc, canvas, false, cx, cy, rx, ry, stroke, fill, strokeWeight, opacity) gc.draw(canvas) ...
def render_ellipse(gc, image, ismatte, cx, cy, rx, ry, stroke, fill, strokeWeight, opacity) if ismatte gc.fill_opacity(opacity) gc.stroke_opacity(opacity) gc.stroke('transparent') gc.stroke_width(strokeWeight); opacityVal = 255 * opacity; gc.fill("rgb(#{opacityVal}, #{opacityVal}, #{opacityVal})"); else gc.stroke(stroke); gc.stroke_width(strokeWeight); gc.fill(fill) end gc.ellipse(cx, cy, rx, ry, 0, 360); gc.draw(image) end
... alpha = Magick::Image.new(canvas.columns, canvas.rows) {self.background_color = 'black'} render_ellipse(gc, alpha, true, cx, cy, rx, ry, stroke, fill, strokeWeight, opacity) canvas.matte = true alpha.matte = false canvas = canvas.composite(alpha, Magick::CenterGravity, Magick::CopyOpacityCompositeOp) canvas.write(filename) end response.headers['content-type'] = 'image/png' render :file => filename end
function fixTransparency(anId) { var aDiv = document.getElementById(anId); for (var i = 0; i < aDiv.childNodes.length; ++i) { var node = aDiv.childNodes[i]; var src = node['src']; if (src) { var opacity = node.opacity; var filterStr = "progid:DXImageTransform. Microsoft.AlphaImageLoader(src='" + src + ", sizingMethod='scale')"; node.src = '/images/transparentpixel.gif'; node.style.filter = filterStr; } } }
function updateImg(aUrl) { gImg.setAttribute('src', aUrl); } function updateDrawing() { // send points collected onmousemove // to be rendered var str = pointsToPath(gDrawPoints); dojo.io.bind({ url: "/oscon/renderpath?pathid=" + gPathId + "&width=800&height=500&path=" + str, load: function(type, evaldObj){ updateImg(evaldObj);}, mimetype: "text/plain", // get plain text, don't eval() transport: "XMLHTTPTransport", method: 'post' }); }
  • Dojo Toolkit
  • Excanvas (google)
  • CanvaSVG
  • iesvg
  • Drawing Object Javascript API
  • Normalizes SVG and VML
  • Architecture can support Canvas, WZ
<html> <head> <title>Hello, Dojo</title> <script type="text/javascript">djConfig = { isDebug: false };</script> <script type="text/javascript" src="/dojo-dev/dojo.js"></script> <script type="text/javascript"> dojo.require("dojo.gfx.*"); dojo.addOnLoad(drawShapes); function drawShapes(){...} </script> </head> <body> <div id="gfx" width="300" height="300"></div> </body> </html>
function drawShapes() { var gfx = dojo.byId('gfx'); var g = dojo.gfx.defaultRenderer; var surface = g.createSurface(gfx, 300, 300); var redCircle = surface. createCircle({ cx: 150, cy: 100, r: 50}). setFill([255, 0, 0, 1]). setStroke({color: "#ffbb00", width: 15}); var greenEllipse = surface. createEllipse({cx: 200, cy: 120, rx: 50, ry: 100}). setFill([0, 255, 0, 0.5]). setStroke({color: [0, 255, 187, 0.5], width: 5}); }
function drawShapes() { var gfx = dojo.byId('gfx'); var g = dojo.gfx.defaultRenderer; var surface = g.createSurface(gfx, 300, 300); var redCircle = surface. createCircle({ cx: 150, cy: 100, r: 50}). setFill([255, 0, 0, 1]). setStroke({color: "#ffbb00", width: 15}); var greenEllipse = surface. createEllipse({cx: 200, cy: 120, rx: 50, ry: 100}). setFill([0, 255, 0, 0.5]). setStroke({color: [0, 255, 187, 0.5], width: 5}); }
  • Primarily DOM events
  • Issues with canvas graphics
  • Get Kathy!
  • SVG declarative animation
  • Direct Animation, HTML+TIME
  • SMIL declarative animation
  • setTimeout()/setInterval() in Javascript
function drawShapes() { var gfx = document.getElementById('gfx'); var svg = document.createElementNS("http://www.w3.org/2000/svg", 'svg'); // do all the svg setup setTimeout(animate, 50); } function randomWalk(c) { var diry = 1 - (2 * Math.floor(Math.random() * 2)); var dirx = 1 - (2 * Math.floor(Math.random() * 2)); var dy = diry * Math.floor(Math.random() * 3); var dx = dirx * Math.floor(Math.random() * 3); var cx = c.cx.baseVal.value + dx; var cy = c.cy.baseVal.value + dy; c.setAttribute('cx', cx + "px"); c.setAttribute('cy', cy + "px"); } function animate() { randomWalk(document.getElementById('circle')); randomWalk(document.getElementById('ellipse')); setTimeout(animate, 50); }
  • Video
  • Sound
  • Input (webcams and microphones)
  • Authoring Tools
  • xdraw.org http://www.xdraw.org/oscon2006/
  • SVG Spec (http://www.w3.org/TR/SVG11/)
  • VML Spec (http://www.w3.org/TR/NOTE-VML)
  • WHATWG Spec (includes canvas -- http://www.whatwg.org/specs/web-apps/current-work/)
  • Direct Animation (http://msdn.microsoft.com/workshop/author/behaviors/reference/reference.asp)
  • Walter Zorn (http://walterzorn.com/)
  • Patrick Schmitz's SMIL Demos (http://ludicrum.org/demos/)