is html5 ready? (workshop)

Post on 15-May-2015

2.302 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

TRANSCRIPT

Is HTML5 ready for

production?

Hi, I’m Remy

@remremy@leftlogic.com

I <3 JavaScript

Questions: interrupt & ask!

There's a lot more down here.

HTML5 is a spec

"HTML5" is a brandsort of

^

HTML5

Offline applications

Offline events

Canvas

Video

Web Form

s

"HTML5"

Web Storage

Web SQ

L Databases

Web Sockets

Web W

orkersG

eolocationM

OA

R!!!

NOT HTML5

NOT HTML5

CSS != HTMLBut maybe we should have been more careful

caniuse.com

When can I use "HTML5"?

Making it work in the "other" browser

PolyfillA shim that mimics a futureAPI providing a fallback to

older browsershttp://goo.gl/0Z9eI

ToolsModernizr to detect support

yepnode.js to conditionally load(available as part of Modernizr)

ToolsModernizr.load({ test: Modernizr.geolocation, nope: 'geo-polyfill.js', complete: initMyGeoApp});

Oh, and learn JavaScript

Web Storage

Cookies suck.

Cookies suck.

Not the edible ones, duh.

The code for cookies is a pain - I always

google it.

"Session" cookies leak across sessions.

Persistent cookies require special date

format

Deleting a cookie, isn't really deleting, but setting in the past.

Varying degrees of limitations on size and

number.

Fuck cookies.

Sexy Web Storage FTW

One Interface

localStoragesessionStorage

http://dev.w3.org/html5/webstorage/

localStorage

• Persists

• Applied to document origin, i.e. scheme/host/port tuple

• No expiry

sessionStorage

• Lasts whilst on the document origin

• Doesn't leak

• Exactly the same API as localStorage

How much space do you want?

5mb?Done! \o/However: utf-16 ∴ 2½Mb

APIvoid setItem(key, value)

any* getItem(key)

void removeItem(key)

string key(index)

void clear()

readonly number length

var store = sessionStorage;

store.setItem('name','rem');

store.getItem('name');

store.removeItem('name');

Play

Do it in the console!

APIsetter setItem

getter getItem

deleter removeItem

var store = sessionStorage;

store.name = 'rem';

store.name;

delete store.name;

Play

Do it in the console!

// Safari debugger broken:

ss.setItem('key', 12);

tipThere's no security protecting the API

Values are strings

Work around: JSON(and http://www.json.org/json2.js)

var store = sessionStorage,

user = { screen_name : ‘rem’,

rating : 11 };

store.user = JSON.stringify(user));

var gotUser = JSON.parse(store.user);

alert(gotUser.screen_name);

Play

Events too

window.addEventListener('storage', function (event) {

console.log(event);

}, false);

http://jsbin.com/ahafa3

Storage in all browsers

window.name

sessionStorage = (function () { var data = window.name ? JSON.parse(window.name) : {};

return { clear: function () { data = {}; window.top.name = ''; }, getItem: function (key) { return data[key] || null; }, removeItem: function (key) { delete data[key]; window.top.name = JSON.stringify(data); }, setItem: function (key, value) { data[key] = value; window.top.name = JSON.stringify(data); } };})(); http://gist.github.com/350433

Firefox cookie security applies to Storage too :(

tip

tipvar cookiesEnabled = (function () { // the id is our test value var id = +new Date();

// generate a cookie to probe cookie access document.cookie = '__cookieprobe=' + id + ';path=/';

// if the cookie has been set, then we're good return (document.cookie.indexOf(id) !== -1);})();

Web SQL Databases

http://flic.kr/p/drmCJ

IndexedDB

http://flic.kr/p/5KXFwB

Questions?

Ca

nv

as

Cooler than this guy.

Canvas SVG

http://vimeo.com/6691519

• It's not one is better than the other, they do different things

• Select canvas when it makes sense

• Don't assume interactive means canvas

• Check out raphaeljs.com

http://mrdoob.com

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8" /><title>Canvas</title></head><body> <canvas></canvas></body></html>

Play

canvas-1.html

http://dev.w3.org/html5/canvas-api/canvas-2d-api.html

2D API

ctx = canvas.getContext('2d')

Start Simple

fillRect, strokeRect & colours

ctx.fillRect(10, 10, 100, 100);

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

ctx.lineWidth = 5;

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

ctx.lineWidth = 5;

ctx.arc(100,50,25,0,Math.PI*2,true);

ctx.fillRect(10, 10, 100, 100);

ctx.fillStyle = '#c00';

ctx.fillRect(100, 75, 50, 50);

ctx.strokeStyle = '#0c0';

ctx.lineWidth = 5;

ctx.arc(100,50,25,0,Math.PI*2,true);

ctx.stroke();

Math.PI == 180°

tip

Math.PI *2 == 360°

tip

d * Math.PI / 180 == radian

tip

tip CSS stretches

Gradient fills

1. Create a gradient object

2.Add colour stops

3.Set the gradient to the fillStyle

4.Draw

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);gradient.addColorStop(0, '#fff');gradient.addColorStop(0.5, '#f00');gradient.addColorStop(1, '#000');

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);gradient.addColorStop(0, '#fff');gradient.addColorStop(0.5, '#f00');gradient.addColorStop(1, '#000');

ctx.fillStyle = gradient;

var w = canvas.width, h = canvas.height;

var gradient = ctx.createLinearGradient(0, 0, w, h);gradient.addColorStop(0, '#fff');gradient.addColorStop(0.5, '#f00');gradient.addColorStop(1, '#000');

ctx.fillStyle = gradient;ctx.fillRect(0, 0, w, h);

Play

createRadialGradient(x0,y0,r0,x1,y1,r1)

Pattern Fills

var img = new Image();

img.src = url;

var pattern = ctx.createPattern(img,'repeat');

ctx.fillStyle = pattern;

ctx.fillRect(0, 0, w, h);

tip invalid_state

img.onload = function () { // now use image for canvas};

Playing with paths

• For drawing irregular shapes

• Can be filled

• ...or stroked.

lineWidth

lineTo(x,y)

moveTo(x,y)

beginPath()

closePath()

rect(x,y,h,w)

arc(x,y,r,s,e, anticw)

fill()

stroke()

drawImage

<canvas>

<img> <video><canvas>

drawImage(src, dx, dy)

drawImage(src, dx, dy, dw, dh)

drawImage(src, sx, sy, sw, sh, dx, dy, dw, dh)

Play

canvas-10.html

img.onload = function () { // this == img canvas.width = this.width; canvas.height = this.height; ctx.drawImage(this, 0, 0);};

pixelpushing

ctx.getImageData(0,0,w,h)

ctx.getImageData(0, 0, w, h);

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

pixels.data[i * 4 + 0];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

pixels.data[i * 4 + 1];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

pixels.data[i * 4 + 2];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

pixels.data[i * 4 + 3];

0 1 2 3

i = 0 r g b a

i = 1 r g b a

i... r g b a

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) {

}

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) {

}

This says loop over each pixel

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0]

}

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0] // green: pixels.data[i+1]

}

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0] // green: pixels.data[i+1] // blue: pixels.data[i+2]

}

var pixels = ctx.getImageData(0, 0, w, h), l = pixels.data.length, i;

for (i = 0; i < l; i += 4) { // red: pixels.data[i+0] // green: pixels.data[i+1] // blue: pixels.data[i+2] // alpha: pixels.data[i+3]}

ctx.putImageData(pixels, 0, 0)

ctx.putImageData(pixels, 0, 0)

Needs to be a CanvasPixelArray

object

tip security_err

To use getImageData, your document

must be served over http (or https) -

i.e. it doesn't work offline.

Play

http://jsbin.com/aguho3/2/edit

greyscale = r*.3 + g*.59 + b*.11;

r = g = b = greyscale;

saturation = (Math.max(r,g,b) + Math.min(r,g,b))/2;

r = g = b = saturation;

/workshop/authors-large.jpg

canvas.toDataURL('image/png');

save.onclick = function () { window.open( canvas.toDataURL('image/png') );};

Play

canvas-13.html

Questions?

Offline Applications

Offline Apps

• Application cache / manifest

• Events: offline, online

• navigator.onLine property

http://icanhaz.com/rubiks

Using a Manifest<!DOCTYPE html>

<html manifest="my.appcache">

<body>

<!-- my page -->

</body>

</html>

CACHE MANIFEST

app.html

css/style.css

js/app.js

#version 13

my.appcache

The Manifest

1. Serve as text/manifest, by adding to mime.types:

text/cache-manifest appcache

<IfModule mod_expires.c>

ExpiresActive on

ExpiresByType text/cache-manifest

↪ “access plus 0 seconds”

</IfModule>

tip Firefox caching

The Manifest

2. First line must be:

CACHE MANIFEST

The Manifest

3. Including page is implicitly included in the cache.

The Manifest

4. Two futher namespaces: NETWORK & FALLBACK

FALLBACK:/ offline.html

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Served from cache

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Requests for files not

found in the cache, are

directed to /

i.e. index.html

(when offline).

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Any requests to urls

that don't match / -

i.e. on another

domain, will be

served through the

web.

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

Also ensures

browser even

attempts to load the

asset

CACHE MANIFEST

/index.htmlrange.jsdatastore.js

FALLBACK:# force everything through # the index url/ /

# this won't match # anything unless it's on # another domainNETWORK:*

# v4

The contents of the

manifest must

change to trigger an

update

The Manifest

5. Include some versioning to cache bust your manifest

# version 16

The process

Browser: request Server: serve allBrowser: I have a manifest, cache

assets

Server: serve manifest assets

Browser: applicationCache

updatedBrowser: reload

Browser: serve locally

Browser: only request manifest

file

Server: 304 Not Modified

Browser: request Server: serve allBrowser: I have a manifest, cache

assets

Server: serve manifest assets

Browser: applicationCache

updatedBrowser: reload

Browser: serve locally

Browser: only request manifest

file

Server: 304 Not Modified

Problem:Change of contentrequires 2 refreshes

document.body.onOnline = function () { // fire an update to the cache applicationCache.update();};

applicationCache.onUpdateReady = function () { if (confirm("New version ready. Refresh?")) { // reload window.location.refresh(); }};

tip

Do offline last

Questions?

Web Sockets

Native or polyfilled

new WebSocket(url)

http://dev.w3.org/html5/websockets/

ws://node.remysharp.com:8000

http://github.com/miksago/node-websocket-server

onopen

onmessage

onclose

onerror

var data = JSON.parse(event.data);

.send

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

var url = 'ws://node.remysharp.com:8000',

conn = new WebSocket(url);

conn.onopen = function () {

conn.send('hello world');

};

conn.onmessage = function (event) {

console.log(event.data);

};

Play

Questions?To contact me after my presentation – text NHT to INTRO (46876)

Or --remy@leftlogic.com@rem

top related