HTML5, CSS3, SVG, and Beyond

Brad Neuberg
bradneuberg@gmail.com

http://twitter.com/bradneuberg
http://codinginparadise.org
http://ajaxian.com

Who is this Guy?

Ajax
Gears
Open Web
Coworking

Small Pieces Loosely Joined

HTML5

Introduction

What is it?

  1. Existing markup
  2. Web Applications
  3. Web Documents

History of HTML5

  • 1999: HTML 4 & XHTML 1.0
  • 2004: Browser vendors revolt against W3C/XHTML
  • 2004: WHATWG starts Web Apps/Forms 1.0
  • 2008: HTML5 brought into W3C, drops XHTML, Web Apps 1.0 rebranded HTML5

HTML5 Design Principles

  • Backwards compatibility, clear migration path
  • Well-defined error handling
  • Users should not be exposed to authoring errors
  • Practical use
  • Scripting is here to stay
  • Device specific profiling should be avoided
  • Open process

Canvas

Demo by Hakim El Hattab

"Scriptable Image"

<canvas id="canvas" width="900" height="220"></canvas>

<script>
  var canvasContext = document.getElementById("canvas").getContext("2d");
  canvasContext.fillRect(250, 25, 150, 100);
</script>

When to Use The Canvas Tag

  • Bitmaps and pixels
  • Fixed size
  • Keyboard driven
  • Black box
  • Dynamically process HTML5 Video

When Not to Use The Canvas Tag

  • Low frame rate on iPhone/iPad
  • Not search engine or accessibility friendly
  • If need dynamic sizing/scaling
  • Mouse oriented applications
  • Can't style with CSS or nest HTML5

Styles & Colors

ctx.fillStyle = "orange";  
ctx.fillStyle = "#FFA500";  
ctx.strokeStyle = "rgb(0, 0, 255)";  
ctx.strokeStyle = "rgba(0, 0, 255, 1)";
ctx.fillRect(250, 25, 150, 100);

ctx.globalAlpha = 0.5; // From 0.0 to 1.0
ctx.fillRect(300, 75, 200, 150);

// Styles can include gradients and patterns.

Paths

ctx.beginPath();  
ctx.moveTo(30, 30);  
ctx.lineTo(150, 150);  
ctx.bezierCurveTo(60, 70, 60, 70, 70, 150);
ctx.lineTo(30, 30);
// Can also use: arc, arcTo, and quadraticCurveTo
ctx.fill();

// ...
ctx.stroke();

Transforms

ctx.translate(400, 200);  
ctx.scale(1.5, 1.5); 
ctx.rotate(135 * Math.PI / 180); 

Graphics State

ctx.fillStyle = 'red';
ctx.save();
ctx.fillStyle = 'blue';
ctx.restore();
ctx.fillRect(250, 25, 150, 100); // Will draw red.

Line Styles

ctx.lineWidth = 1.0; 
ctx.lineCap = butt; 
ctx.lineJoin = miter; 

Gradients

// Linear Gradient: x1, y1, x2, y2
var linear = ctx.createLinearGradient(0, 0, 150, 150);
linear.addColorStop(0.0, 'blue');
linear.addColorStop(1.0, 'green');

ctx.fillStyle = linear;
ctx.fillRect(0, 0, 150, 150);

// Radial Gradient: x1, y1, r1, x2, y2, r2
var radial = ctx.createRadialGradient(45, 45, 10, 52, 50, 30);
radial.addColorStop(0, '#A7D30C');  
radial.addColorStop(0.9, '#019F62');  
radial.addColorStop(1, 'rgba(1, 159, 98, 0)');

ctx.fillStyle = radial;
ctx.fillRect(0, 0, 150, 150);

Compositing

ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 200, 200);

ctx.globalCompositeOperation = source-over; 

ctx.fillStyle = 'red';
ctx.beginPath();
// x, y, radius, startAngle, endAngle, antiClockwise
ctx.arc(200, 200, 100, 0, Math.PI * 2, false);
ctx.closePath();
ctx.fill();

Patterns & Shadows

var img = new Image();
img.src = 'images/brad-small.jpg';
img.onload = function() {
  ctx.shadowOffsetX = 2; 
  ctx.shadowOffsetY = 2; 
  ctx.shadowBlur = 2.0; 
  ctx.shadowColor = 'rgba(0, 0, 0, 0.5)';
            
  // Can use image or another Canvas element.
  var pattern = ctx.createPattern(img, repeat); 
  ctx.fillStyle = pattern;

  // Draw circle.
  // ...
}

Text

var phrase = 'I can eat glass'; 

var braille = englishToBraille(phrase);

ctx.font = '40pt SomeWebFont Helvetica sans-serif';
ctx.textAlign = center; 
ctx.textBaseline = alphabetic; 

// text, x, y, [maxWidth]
ctx.fillText(braille, 50, 160);
ctx.strokeText(phrase, 50, 250, 50);

Clipping Path

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

Images & Pixels

drawImage

Image Data - From Images

ctx.save();
ctx.rotate(45 * Math.PI / 180);
ctx.drawImage(document.getElementById('sample-image-data1'), 100, 0);
ctx.restore();

var img = new Image();
img.src = 'images/brad.jpg';
img.onload = function() {
  ctx.drawImage(img, 300, 20);
}

Image Data - From Canvas

// Scaling - image, x, y, sWidth, sHeight
ctx.drawImage(document.getElementById('clipping-path-canvas'), 415, 100, 
    900 * 0.5, 225 * 0.5);

Image Data - From Data URL

var img = new Image();
img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAA ...'; 
img.onload = function() {
  ctx.drawImage(img, 430, 100, 100, 100);
};

Image Data - From SVG

ctx.save();
ctx.rotate(45 * Math.PI / 180);
// SVG must be embedded as IMG not Object for this to work.
ctx.drawImage(document.getElementById('canvas-image-svg'), 0, 0, 100, 100);
ctx.restore();

var img = new Image();
img.src = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdG ...'; 
img.onload = function() {
  ctx.drawImage(img, 400, 100, 100, 100);
};

Image Data - From Video

// Slice - image, x, y, sWidth, sHeight, dX, dY, dWidth, dHeight
ctx.drawImage(myVideoObj, 0, 0, 0.5, 0.5, 10, 10, 50, 50);

Image Data - To Image Data URL

var canvas = document.getElementById('clipping-path-canvas');
                            
var mimeType = 'image/png'; 

// For image/jpeg, optional second argument from 0.0 to 1.0
// for JPEG quality level.
var exportImg = canvas.toDataURL(mimeType);

if (exportImg && exportImg.indexOf(mimeType) != -1) {
  var img = document.getElementById('myImageTag');
  img.src = exportImg;
}
Exported Image:  image/png
URL Output

Canvas Animation

  • Clear canvas
  • Save state
  • Draw shapes
  • Restore state

Animation Example

setInterval(animate, 100);
                          
// Part of animate function.
ctx.globalCompositeOperation = 'destination-over';

// Clear canvas.
ctx.clearRect(0, 0, 300, 300);

// Save initial state.
ctx.save();

// Move the earth.
var time = new Date();  
ctx.rotate( ((2 * Math.PI) / 60) * time.getSeconds() 
    + ((2 * Math.PI) / 60000) * time.getMilliseconds());  
ctx.drawImage(earthImg, -12, -12);

// Draw other shapes.
// ...

// Restore state.
ctx.restore();

Multimedia

Demo by Sean Christmann

Video Code

<video width="640" height="480" controls preload>
   <source src="myMovie.mp4"  type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'>
   <source src="myMovie.webm" type='video/webm; codecs="vp8, vorbis"'>
   <source src="myMovie.ogv"  type='video/ogg; codecs="theora, vorbis"'>
</video>
var video = document.querySelectorAll('video')[0];

// Find out when the video is done seeking so we
// can start playing the video.
video.addEventListener('seeked', function() {
   video.play();
});

// Seek 10 seconds in.
video.currentTime = 10.0;

Geolocation

Geolocation Code

if (navigator.geolocation) {
  // Geolocation available.
}
// Get position a single time.  
navigator.geolocation.getCurrentPosition(function(position) {
  useLocation(position.coords.latitude, position.coords.longitude);
});
// Watch position as it changes.
var watchId = navigator.geolocation.watchPosition(function(position) {
  useLocation(position.coords.latitude, position.coords.longitude);
});

// Clear watching the position  
navigator.geolocation.clearWatch(watchId);

Markup

HTML5 Doctype

<!DOCTYPE html>

Elements

<body>
  <header>
    <hgroup>
      <h1>Page title</h1>
      <h2>Page subtitle</h2>
    </hgroup>
  </header>

  <nav>
   <ul>
     Navigation...
   </ul>
  </nav>

  <section>
   <article>
     <header>
       <h1>Title</h1>
     </header>
     <section>
       <figure>
         <img src="example.jpg" />
         <figcaption>
           This is a caption
         </figcaption>
       </figure>
       Content...
     </section>
   </article>

   <article>
     <header>
       <h1>Title</h1>
     </header>
     <section>
       Content...
     </section>
   </article>

   <article>
     <header>
       <h1>Title</h1>
     </header>
     <section>
       Content...
     </section>
   </article>
  </section>

  <aside>
   Top links...
  </aside>

  <footer>
   Copyright © 2009.
  </footer>
</body>

Aside or Figure?

  • <aside>: Related but not essential
    • Inside <article>: Should be related to article (glossary)
    • Outside <article>: Should be related to site (blogroll, advertising, etc.)
  • <figure>: Essential but out of flow

Microdata

Microdata Example

<div itemscope itemtype="http://data-vocabulary.org/Person">
  <img src="http://codinginparadise.org/images/brad.jpg" itemprop="photo" /> 

  My name is <span itemprop="name">Brad Neuberg</span>,
  and I am a <span itemprop="title">JavaScript/HTML5 Consultant</span> for  
  <a href="http://codinginparadise.org" itemprop="affliation">myself</a>.

  I live in  
  <span itemprop="address" itemscope
        itemtype="http://data-vocabulary.org/Address">

    <span itemprop="locality">San Francisco</span>,  
    <span itemprop="region">CA</span> 

  </span>
</div>

Forms

Forms Examples

Implemented

Dedicated UI:
              
<input type="range" min="0" max="50" value="0" /> 
<input results="10" type="search" /> 
<input type="text" placeholder="Search inside" /> 

Input Validation:

<style> :invalid { background-color: red; } </style>
<input type="color" /> 
<input type="number" /> 
<input type="email" /> 
<input type="tel" /> 
etc...

Not yet

<meter>
<progress>
<output>
etc...

ARIA

<ul id="tree1"
      role="tree" 
      tabindex="0" 
      aria-labelledby="label_1"
      >
  <li role="treeitem" tabindex="-1" aria-expanded="true">Fruits</li>
  <li role="group">
    <ul>
      <li role="treeitem" tabindex="-1">Oranges</li>
      <li role="treeitem" tabindex="-1">Pineapples</li>
      ...
    </ul>
  </li>
</ul>

Storage

Web SQL Database

var db = db = window.openDatabase('NoteTest', '1.0', 
    'HTML5 Database API example', 200000);
db.transaction(function(tx) {
   tx.executeSql('CREATE TABLE WebKitStickyNotes '
       + '(id REAL UNIQUE, note TEXT, timestamp REAL, left TEXT, '
       + 'top TEXT, zindex REAL)', [], loadNotes);
});
db.transaction(function(tx) {
   tx.executeSql('SELECT id, note, timestamp, left, top, zindex '
       + 'FROM WebKitStickyNotes', [], function(tx, result) {
            for (var i = 0; i < result.rows.length; ++i) {
                var row = result.rows.item(i);
                var note = new Note();
                note.text = row['note'];
                note.left = row['left'];
                note.top = row['top'];
            }
    }, handleError);
});
Demo by David Hyatt

Local Storage

// Use localStorage for persistent storage.
// Use sessionStorage for per tab storage.

// Saving values.
window.localStorage['value'] = textArea.value;
window.localStorage['timestamp'] = (new Date()).getTime();

// Loading values.
textarea.value = window.localStorage['value'];

Save text value on the client side (crash-safe)

DOM

DOM Selectors

var elems = document.;
<section id="main">
   <ul>
      <li>Item 1</li>
      <li>Item 2</li>
      <li class="important">Item 3</li>
      <li>Item 4</li>
      <li class="important">Item 5</li>
   </ul>

   <aside>
      <input id="possibleValues" type="range" min="0" max="25">
   </aside>
</section>

classList

myElem.classList.add('important');
myElem.classList.add('selected');

// ...
                              
if (myElem.classList.contains('important')) {
  // Do something.
  
  myElem.classList.remove('important');
}

Offline

Web Workers

Demo by Remy Sharp

Web Workers Code

main.js

var worker = new Worker('worker.js');

// Send the worker a message.
worker.postMessage('start');

// Respond to messages from the worker.
worker.onmessage = function(event) {
  console.log('Message received from worker: ' + event.data);
}

worker.js

// Respond to messages sent from main page.
onmessage = function(event) {
  console.log('Message received from main page: ' + event.data);
}                      

function run() {
  // Find prime numbers.
  // ...

  // Send results back to main page.
  postMessage(primeNumber);
}

Web Sockets

Demo by Julien Genestoux

Web Sockets Code

var socket = new WebSocket(location);
socket.onopen = function(event) {
  socket.postMessage('Hello, WebSocket');
}
socket.onmessage = function(event) { alert(event.data); }
socket.onclose = function(event) { alert('closed'); }

Browser History

Content Editable

Drag & Drop

& Etc.

Inline SVG

Sandboxed Iframes

Undo

X-Domain Messaging

File API

CSS3

Selectors

Selectors

.row:nth-child(even) {
  background: #dde;
}
.row:nth-child(odd) {
  background: white;
}
Row 1
Row 2
Row 3
Row 4

Image-like display

div {
  display: inline-block;
}

Specific attributes

input[type="text"] {
  background: #eee;
}

Negation

:not(.box) {
  color: #00c; 
}            
:not(span) {
  display: block; 
}

More specific targetting

h2:first-child { ... }

div.text > div { ... } 
h2 + header { ... }

Transforms & Animations

Transforms

Hover over me:

-webkit-transform: rotateY(45deg);
-webkit-transform: scaleX(0.5);
-webkit-transform: translate3d(0, 0, -500);
-webkit-transform: perspective(500px)
#threed-example {
  -webkit-transform: rotateZ(5deg);
  -webkit-transition: -webkit-transform 2s ease-in-out;
}

#threed-example:hover {
  -webkit-transform: rotateZ(-5deg);
}

Transitions

#box.left {
  margin-left: 0;
}

#box.right {
  margin-left: 1000px;
}

document.getElementById('box').className = 'left'; 
document.getElementById('box').className = 'right'; 
#box {
  -webkit-transition: margin-left 1s ease-in-out;
}

document.getElementById('box').className = 'left'; 
document.getElementById('box').className = 'right'; 

Animation

@-webkit-keyframes pulse {
 from {
   opacity: 0.0;
   font-size: 100%;
 }
 to {
   opacity: 1.0;
   font-size: 200%;
 }
}

div {
  -webkit-animation-name: pulse;
  -webkit-animation-duration: 2s;
  -webkit-animation-iteration-count: infinite;
  -webkit-animation-timing-function: ease-in-out;
  -webkit-animation-direction: alternate;
}
*Please make a better use of it. We don't want a new blink tag ;)
Pulse!

3D Transforms

<div id="experiment">
        <div id="cube">
                <div class="face one">
                        One face
                </div>
                <div class="face two">
                        Up, down, left, right
                </div>
                <!-- etc -->
#experiment {
  -webkit-perspective: 800;
  -webkit-perspective-origin: 50% 200px;
}

#cube {
  /* ... */
  -webkit-transition: -webkit-transform 2s linear;
  -webkit-transform-style: preserve-3d;
}

#cube .one  {
  -webkit-transform: rotateX(90deg) translateZ(200px);
}
Demo by Paul Hayes

Graphics

Gradients

background: -webkit-gradient(linear, left top, left bottom, 
                from(#00abeb), to(white), 
                color-stop(0.5, white), color-stop(0.5, #66cc00))

background: -webkit-gradient(radial, 430 50, 0, 430 50, 200, 
                from(red), to(#000)) 

Rounded Corners

border-radius: 0px; 
Example

Masking

video {
  -webkit-mask-image: url(mask.svg);
}
<svg>
   <text x="50%" y="60%">CSS3</text>
</svg>

Layout

Columns

-webkit-column-count: 2; 
-webkit-column-rule: 1px solid #bbb;
-webkit-column-gap: 2em;

In March 1936, an unusual confluence of forces occurred in Santa Clara County.

A long cold winter delayed the blossoming of the millions of cherry, apricot, peach, and prune plum trees covering hundreds of square miles of the Valley floor. Then, unlike many years, the rains that followed were light and too early to knock the blossoms from their branches.

Instead, by the billions, they all burst open at once. Seemingly overnight, the ocean of green that was the Valley turned into a low, soft, dizzyingly perfumed cloud of pink and white. Uncounted bees and yellow jackets, newly born, raced out of their hives and holes, overwhelmed by this impossible banquet.

Then came the wind.

It roared off the Pacific Ocean, through the nearly uninhabited passes of the Santa Cruz Mountains and then, flattening out, poured down into the great alluvial plains of the Valley. A tidal bore of warm air, it tore along the columns of trees, ripped the blossoms apart and carried them off in a fluttering flood of petals like foam rolling up a beach.

This perfumed blizzard hit Stevens Creek Boulevard, a two-lane road with a streetcar line down its center, that was the main road in the West Valley. It froze traffic, as drivers found themselves lost in a soft, muted whiteout. Only the streetcar, its path predetermined, passed on...

Flexbox

<div id="container">
	<div>Play</div><div>Slider</div><div>VOL</div>
</div>
#flexbox-container {
    width: 50%;
    height: 30px;
    border: 1px solid #ccc;
    display: -webkit-box;
    -webkit-box-orient: 
}

#flexbox-container div:nth-of-type(1) {
  -webkit-box-ordinal-group: 3;
}

#flexbox-container div:nth-of-type(2) {
  -webkit-box-flex: 
  -webkit-box-ordinal-group: 2;
}

#flexbox-container div:nth-of-type(3) {
  -webkit-box-ordinal-group: 1;
}
Play
Slider
Vol

Web Fonts

@font-face {
  font-family: 'LeagueGothic';
  src: url(LeagueGothic.otf);
}

@font-face {
  font-family: 'Droid Sans';
  src: url(Droid_Sans.ttf);
}

header {
  font-family: 'LeagueGothic';
}
LeagueGothic font with no image replacement

SVG

What is it?

  • "HTML for Graphics"
    • Ex: <rect> and <circle>
  • Vector shapes
  • Uses CSS and JavaScript
Demo by Kihyuck Hong

When to Use SVG

  • Dynamic sizing & scaling
  • Want to use CSS
  • Mouse driven
  • Search engine and accessibility friendly

When Not to Use SVG

  • Need lots of sprites
  • Pixel oriented apps

SVG Code & Embedding

<!DOCTYPE html>
<html><head><style>
  .important {
    stroke: red;
    stroke-width: 3px;
  }

  text {
    fill: green;
    stroke: black;
    font-size: 20px;
  }
</style></head>

<body>
  <svg>
    <defs>
      <linearGradient id="myGradient" x1="0%" y1="100%" x2="100%" y2="100%">
        <stop offset="5%" stop-color="red" />
        <stop offset="95%" stop-color="blue" stop-opacity="0.5" />
      </linearGradient>
    </defs>

    <circle id="myCircle" class="important" cx="50%" cy="50%" r="10%" 
        fill="url(#myGradient)"
        onmousedown="alert('hello');" />

    <text x="50%" y="75%" text-anchor="middle">HTML5 Embedding</text>
  </svg>
</body></html>
<?xml version="1.0"?>
                      
<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">
  <style>
    .important {
      stroke: green;
      stroke-width: 3px;
    }

    text {
      fill: red;
      stroke: black;
      font-size: 20px;
    }
  </style>

  <defs>
    <linearGradient id="myGradient" x1="0%" y1="100%" x2="100%" y2="100%">
      <stop offset="5%" stop-color="red" />
      <stop offset="95%" stop-color="blue" stop-opacity="0.5" />
    </linearGradient>
  </defs>

  <circle id="myCircle" class="important" cx="50%" cy="50%" r="10%" 
      fill="url(#myGradient)"
      onmousedown="alert('hello');" />

  <text x="50%" y="75%" text-anchor="middle">SVG File</text>
</svg>
<object type="image/svg+xml" data="sampleEmbed.svg"></object>
<image src="sampleEmbed.svg">
div { background-image: url(sampleEmbed.svg) }

Shapes

<rect x="50" y="50"
    width="100" height="100"
    rx="5" ry="5"
    style="fill: rgba(0, 0, 255, 0.8); stroke-width: 1; stroke: green;" />
<circle cx="250" cy="100" r="50" fill="orange" stroke="black" />
<ellipse cx="10em" cy="5em" rx="200" ry="80"
    fill="rgb(200, 100, 50)" stroke="rgb(0, 0, 100)"
    stroke-width="1cm"
    transform="translate(70, 215) scale(0.2)" />
<line x1="320" y1="100" x2="400" y2="200"
    stroke-width="5px" stroke="blue" />
<polyline points="0,60 20,20 40, 100, 60,40, 80,100, 100,40 120,100"
    fill="red" stroke="black" 
    transform="translate(400, 45)" />
<polygon fill="red" fill-opacity="0.4"
    points="350,75  379,161 469,161 397,215
            423,301 350,250 277,301 303,215
            231,161 321,161"
    transform="translate(0, -20) rotate(15)" />
<path d="M10 10 h 80 v 80 h -80 Z"
    fill="transparent" stroke="black" 
    transform="translate(430, 220)" />

Coordinates & viewBox

<svg xmlns="http://www.w3.org/2000/svg"
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="200" height="200"

    viewBox="   "

    preserveAspectRatio=" "
    />

   <!-- Image Coordinates:  -->
   <!-- Pixels (default). -->
   <image xlink:href="brad.jpg"
       width="50px"
       height="50px" />

</svg>

Linking

<?xml version="1.0"?>
                      
<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink">

  <a xlink:href="http://codinginparadise.org" target="_blank">
    <circle id="myCircle" class="important" cx="50%" cy="50%" r="10%" 
      fill="blue" />
  </a>

</svg>

Styling

<defs>
  <linearGradient id="myGradient" x1="0%" y1="100%" x2="100%" y2="100%">
    <stop offset="5%" stop-color="red" />
    <stop offset="95%" stop-color="blue" stop-opacity="0.5" />
  </linearGradient>
</defs>

<style type="text/css">
  a:hover {
    stroke: black;
    stroke-width: 3px;
  }

  a:hover > circle {
    fill: url(#myGradient) !important;
  }
</style>

<a xlink:href="http://codinginparadise.org" target="_blank">
  <circle id="myCircle" class="important" cx="50%" cy="50%" r="30%" 
      style="fill: blue;" />
</a>

Reusing Elements

<defs>
  <polygon id="polygonSprite" 
    fill="red" fill-opacity="0.4"
    points="350,75  379,161 469,161 397,215
            423,301 350,250 277,301 303,215
            231,161 321,161" />
</defs>

<use xlink:href="#polygonSprite"  
    transform="translate(0, -20) rotate(15)" />

<use xlink:href="#polygonSprite"
    transform="translate(-50, -30) scale(0.5)" />

<use xlink:href="#polygonSprite"
    transform="translate(110, 30) scale(0.7) rotate(-15)" />

Grouping Elements

<?xml version="1.0"?>
                      
<svg xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink="http://www.w3.org/1999/xlink"
     width="300" height="300">

  <g transform="translate(180, -100) rotate(45)" fill="blue">
    <rect x="100" y="100" rx="10" ry="10" width="100" height="100" />
    <text x="150" y="235" font-size="20" text-anchor="middle">Groups</text>
  </g>
</svg>

Transforms

<g transform="">
   <!-- Children shapes in here -->
</g>

Scripting

SVG DOM

var svgns = 'http://www.w3.org/2000/svg';
var xlinkns = 'http://www.w3.org/1999/xlink';

var container = 
    document.querySelector('#svg-dom > div.svg-drawing-area');

var svg = document.createElementNS(svgns, 'svg');
svg.setAttribute('width', 200);
svg.setAttribute('height', 200);

var circle = document.createElementNS(svgns, 'circle');
circle.setAttribute('cx', 100);
circle.setAttribute('cy', 100);
circle.setAttribute('r', 50);
circle.style.fill = 'blue';
circle.className = 'interesting';
circle.addEventListener('mouseover', function(evt) {
  alert('Hello world!');
}, false);

var a = document.createElementNS(svgns, 'a');
a.setAttributeNS(xlinkns, 'href', 'http://codinginparadise.org');
a.setAttribute('target', '_blank');
a.setAttribute('stroke', 'black');
a.setAttribute('stroke-width', 3);
a.appendChild(circle);
svg.appendChild(a);

container.appendChild(svg);

Working With Objects

Going Into Objects

var obj = document.getElementsByTagName('object')[0];
var doc = obj.contentDocument;
var someElems = doc.querySelectorAll('rect.important');
var root = doc.rootElement;

Jumping Out of Objects

var elem = top.document.getElementById('foobar');
var result = top.someFunction();

Inside of Objects

var elem = document.getElementsByTagNamsNS(svgns, 'rect');

Libraries

  • SVG Web
  • Raphaël
  • JQuery SVG
  • Ample SDK

SVG Web

  • JavaScript library that uses Flash to implement SVG on Internet Explorer
  • Simulates SVG DOM so scripting with JavaScript possible
  • http://code.google.com/p/svgweb

SVG Web Video

What is Supported

  • SVG 1.1 Full
  • DOM Scripting With JavaScript
  • Partial
    • CSS
    • SMIL
    • SVG Fonts
    • Video & Sound

Adding SVG Web to Page

  • svg.js
  • svg.swf (application/x-shockwave-flash)
  • svg.htc (text/x-component)
<script src="svg.js"></script>
<script src="../../src/svg.js" data-path="../../src"></script>

Direct Embedding

<script type="image/svg+xml">
  <svg 
     width="200" height="200"
     style="background-color: #D2B48C; display: block; margin-bottom: 5px;"
     id="embeddedSVG">
   <g 
      id="myGroup" 
      fill="blue" 
      style="font-size: 18px; text-anchor: middle; font-family: serif;">
       <circle
            id="myCircle" 
            cx="100" cy="75" r="50"
            stroke="firebrick"
            stroke-width="3" />
       <text x="100" y="155">Hello World</text>
       <text x="100" y="175">From Embedded SVG!</text>
   </g>
  </svg>
</script>
Flash
Native

Object Embedding

<!--[if IE]>
<object src="blocks_game.svg" classid="image/svg+xml"
        width="312" height="187">
<![endif]-->
<!--[if !IE]>-->
<object data="blocks_game.svg" type="image/svg+xml" 
        width="312" height="187">
<!--<![endif]-->
</object>
Flash

SVG Web Renderer

Force Inside Page

<meta name="svg.render.forceflash" content="true"></meta>

Force Through URL

http://example.com/mySvg.html?svg.render.forceflash=false

SVG Web onLoad

window.onsvgload = function() {
  // do stuff now
}
window.addEventListener('SVGLoad', function() {
  // function to be called when SVG Web and the page is done loading
}, false)

Scripting Helloworld

Flash

Scripting Helloworld

function changeColors() {
  // Get elements from our embedded SVG first.

  // Use getElementById.
  var circle = document.getElementById('myCircle');

  // Change using setAttribute.
  circle.setAttribute('stroke', 'green');

  // Can also use style property.
  circle.style.fill = '#8A2BE2';

  // Change the value inside our SVG OBJECT now.

  // Use the 'contentDocument' property to navigate into the SVG OBJECT.
  var doc = document.getElementById('mySVGObject').contentDocument;
  circle = doc.getElementById('myCircle');
  circle.style.fill = '#8A2BE2';
}

Scripting Helloworld

function changeText() {
  // Use getElementsByTagNameNS to get our text from our embedded SVG.

  // 'svgns' is a 'magic' variable that we make available; it is just
  // the SVG namespace 'http://www.w3.org/2000/svg' so you don't always
  // have to remember it.  We also make the variable 'xlinkns' available.
  var textElems = document.getElementsByTagNameNS(svgns, 'text');

  // Change the text Hello World to Goodbye World.
  for (var i = 0; i < textElems.length; i++) {
    if (textElems[i].childNodes[0].nodeValue == 'Hello World') {
      textElems[i].childNodes[0].nodeValue = 'Goodbye World';
    }
  }

  // Change the text inside our SVG OBJECT as well.
  var doc = document.getElementById('mySVGObject').contentDocument;
  textElems = doc.getElementsByTagNameNS(svgns, 'text');
  for (var i = 0; i < textElems.length; i++) {
    if (textElems[i].childNodes[0].nodeValue == 'Hello World') {
      textElems[i].childNodes[0].nodeValue = 'Goodbye World';
    }
  }
}

Creating Nodes

var el = document.createElementNS(svgns, 'circle');
el.setAttribute('cx', 200);
el.setAttribute('cy', 200);
el.setAttribute('r', 5);
el.setAttribute('fill', '#223FA3');
el.setAttribute('stroke-width', '1px');
el.setAttribute('stroke', 'black');

var group = document.getElementById('myGroup');
group.appendChild(el);

var textNode = document.createTextNode('hello world', true);
var svgText = document.createElementNS(svgns, 'text');
svgText.setAttribute('x', 100);
svgText.setAttribute('y', 100);
svgText.appendChild(textNode);

Script Inside SVG Files

<?xml version="1.0"?>

 <svg xmlns="http://www.w3.org/2000/svg" onload="loaded()">
<script type="text/javascript"><![CDATA[
    function loaded() {
      // change onloadFunc to point to your real onload function that you
      // want called when the page is truly ready
      var onloadFunc = doload;

      if (top.svgweb) {
        top.svgweb.addOnLoad(onloadFunc, true, window);
      } else {
        onloadFunc();
      }
    }   

   function doload() {
      // developers original onload handler

      // add an event listener to our circle; on* style events added right
      // to the markup are not yet supported
      var circle = document.getElementById('myCircle');
      circle.addEventListener('mousedown', function() {
        alert('You pressed the mouse button on our circle!');
      }, false);
   }
]]></script>

Miscellaneous

Masks

Gradients

SVG Fonts

foreignObject

Animation

Metadata

Symbols

Markers

WebGL

Sample Code

<canvas id="canvas" width="838" height="220"></canvas>

<script>
  var gl = document.getElementById('canvas').getContext('experimental-webgl');
  // ...
</script>

JavaScript