ten things every developer should know about...
TRANSCRIPT
Canvas is Your Best Friend for Advanced UIs
The canvas API brings pixel-addressable graphics to JavaScript
Supports transforms, animations, layered graphics, and much more
Makes possible entire genres of apps (games, photo editors, etc.) that weren't
possible before
Makes possible advanced visual effects that weren't possible before
Corollary: Never do with Canvas what you could do with CSS3
Generating an Image
var bitmap = context.createImageData(100, 100);
for (x = 0; x < bitmap.width; x++)for (y = 0; y < bitmap.height; y++)
drawRandomColor(bitmap, x, y);
context.putImageData(bitmap, 0, 0);
function drawRandomColor(bitmap, x, y) {var index = (x + y * bitmap.width) << 2;bitmap.data[index + 0] = Math.random() * 256; // Redbitmap.data[index + 1] = Math.random() * 256; // Greenbitmap.data[index + 2] = Math.random() * 256; // Bluebitmap.data[index + 3] = 255; // Alpha
Modifying an Image
var image = new Image();image.src = "flowers.jpg";
image.onload = function () {context.drawImage(image, 0, 0, canvas.width, canvas.height);bitmap = dc.getImageData(0, 0, canvas.width, canvas.height);for (x = 0; x < bitmap.width; x++)
for (y = 0; y < bitmap.height; y++)toGray(bitmap, x, y); // Helper function (not shown)
context.putImageData(bitmap, 0, 0);}
The Canvas API
Never Take Performance for Granted
The same code can perform dramatically differently in different browsers
Each browser has its own JavaScript engine, and each tends to be optimized differently
V8 engine in Chrome
Chakra engine in Internet Explorer
SpiderMonkey engine in Firefox
Modern engines JIT-compile JavaScript, often on background threads running on separate cores
Because JavaScript is a (mostly) typeless language, JIT compilers have to make assumptions
Don't assume that because it performs acceptably in Chrome, it will also perform
acceptably in IE (or vice versa)
Test, test, and test some more!
JavaScript Performance
Web Workers Make JavaScript a Modern Language
Web workers allow JavaScript apps to be multithreaded
Make apps more responsive by consigning long-running loops to background threads
Allow apps to leverage multiple cores in modern processors
Web workers run in a special scope that lacks access to document or window
Workers can't update UIs directly because they can't access the browser DOM
Workers can post messages to the UI thread and allow that thread to update the UI
Can also receive message from the UI thread
Limited worker scope takes much of the pain out of multithreading
Starting a Worker and Posting a Message
var worker = new Worker("add.js");worker.addEventListener("message", onMessage, false);worker.postMessage({ op1: 2, op2: 2 }); // Pass values to worker...
function onMessage(e) {alert(e.data); // Display sum
}
Receiving and Posting Messages in a Worker
// add.jsaddEventListener("message", onMessage, false);
function onMessage (e) {var a = e.data.op1;var b = e.data.op2;postMessage(a + b); // Post sum to the main thread
}
Multithreaded JavaScript
Storage Options in HTML5 are Limited
Local Storage provides persistent data store to apps
Data written to local storage subject to shared quota of approx. 5 MB
Data written to local storage can be read, modified, and deleted by any apps that share an origin
Data written to local storage is stored in plaintext and is easily inspected by users
Data written to local storage is unstructured
Indexed DB solves some of these problems
Apps can create multiple client-side databases containing object stores
Indexed DB somewhat alleviates the quotas placed on storage
Indexed DB supports indexing for fast retrieval of data
Indexed DB supports transactions but lacks a query language
Reading and Writing Local Storage
// Write point to local storagevar x = 100;var y = 200;var point = [x, y]; // Stored as "100,200"window.localStorage["point"] = point;
// Read point from local storagevar point = window.localStorage["point"];
if (point != null){
var coords = point.split(",");var x = parseInt(coords[0]);var y = parseInt(coords[1]);
}
Creating and Initializing an Indexed Database
var request = window.indexedDB.open("MyDatabase", 1); // Version 1
request.onupgradeneeded = function (e) {var db = e.target.result; // Contains IDBDatabase reference
// Create an object storevar store = db.createObjectStore(
"employees", { keyPath: "alias" });
// Create an index on the object storestore.createIndex("alias", "alias", { unique: true });
};
Adding an Object to an Object Store
store.add({ firstName: "Jeff", lastName: "Prosise",alias: "v-jeffpr" }).onsuccess = function (e) {// Object added
};
Retrieving Objects from an Object Store
store.get("v-jeffpr").onsuccess = function (e) {var employee = e.target.result;alert(employee.firstName + " " + employee.lastName);
};
Modifying an Object in an Object Store
store.get("v-jeffpr").onsuccess = function (e) {var employee = e.target.result;employee.firstName = "Jeffrey";store.put(employee).onsuccess = function (e) {
// Object modified};
};
Retrieving Records Through an Index Using an "only" Range
var index = store.index("firstName");var range = IDBKeyRange.only("Jeff"); // Case-sensitive!
index.openCursor(range).onsuccess = function(e) {var cursor = e.target.result;if (cursor) {
alert(cursor.key + ": " +cursor.value.firstName + " " +cursor.value.lastName
);cursor.continue();
}};
Indexed DB
Read Access to the Local File System is Limited but Functional
File(Reader) API allows files to be opened and read
File object represents individual files
FileList object represents collections of files
FileReader object provides API for reading data
Blob object holds data
Files must be selected by the user in order to be opened and read; gallery apps
simply are not possible (and probably never will be)
Selected through an <input type="file"> element
Selected through drag-and-drop
File(Reader) API is widely supported by browsers
Loading a File
// HTML<input type="file" id="picker" />
// JavaScriptdocument.getElementById("picker").addEventListener
("change", onFileSelected, false);
function onFileSelected(e) {// Get a File object representing the selected filevar file = e.target.files[0];
}
Getting Information About a File
// Retrieve a File from a FileListvar file = e.target.files[0];
// Get the file's name, type, size, and last-modified datevar name = file.name;var type = file.type; // e.g., "image/jpeg"var size = file.size;var stamp = file.lastModifiedDate;
// Determine whether the file is an image fileif (file.type.match("image.*") {
// It's an image!}
Reading a Text File
var reader = new FileReader();
reader.onload = function(e) {// Read the file's text content from e.target.resultvar data = e.target.result;
}
reader.onerror = function(e) {// If an error occurred, make the user awarealert(e.target.error.code); // Display error code
}
reader.readAsText(file);
Reading an Image File
var reader = new FileReader();
reader.onload = function(e) {// Assign data URL to src property of <img> elementvar img = document.getElementById("image");image.src = e.target.result;
}
reader.onerror = function(e) {alert(e.target.error.code); // Display error code
}
reader.readAsDataUrl(file);
Reading a Binary File
var reader = new FileReader();
reader.onload = function(e) {// Wrap an array around the ArrayBuffer and read each bytevar bytes = new Uint8Array(e.target.result);for (i=0; i<bytes.length; i++) {
var byte = bytes[i];}
}
reader.onerror = function(e) {alert(e.target.error.code); // Display error code
}
reader.readAsArrayBuffer(file);
Reading from the Local File System
Write Access to the Local File System Sucks
FileSystem and FileWriter APIs provide for file writing, but…
W3C has officially discontinued work on both
Only Chrome and recent versions of Opera support these APIs
Even in Chrome, APIs write to a virtual file system, not the physical file system
Must rely on browser-specific APIs to save files to the local file system
Saving a Blob (IE10+)
// Save a blob containing a stringvar blob = new Blob(["Hello, blob!"]);window.navigator.msSaveBlob(blob, "Sample.txt");
// Save a blob containing a canvas imagevar blob = canvas.msToBlob();window.navigator.msSaveBlob(blob, "Sample.jpg");
XMLHttpRequest Level 2 is Awesome
Networking has been too limited for too long in JavaScript
No cross-origin requests
No intrinsic support for time-outs or progress events
Limited ability to transmit and receive binary data
XMLHttpRequest Level 2 brings JavaScript networking out of the Stone Age
Support for cross-origin requests
Support for file uploads and progress events
Support for request time-outs
Support for binary input and output and more
Sending a Request
var xhr = new XMLHttpRequest();xhr.open("GET", "services/weather/98052", true);xhr.addEventListener("load", onLoad, false);xhr.addEventListener("error", onError, false);xhr.addEventListener("timeout", onTimeout, false);xhr.timeout = 10000; // 10 secondsxhr.send();...
function onLoad(e) {// Request completed successfully
}
Sending a String
var xhr = new XMLHttpRequest();xhr.open("POST", "services/weather", true);xhr.addEventListener("load", onLoad, false);xhr.send("98052");...
function onLoad(e) {// Request completed successfully
}
Sending Binary Data
var xhr = new XMLHttpRequest();xhr.open("POST", "services/upload", true);xhr.addEventListener("load", onLoad, false);var bytes = new Uint8Array([1, 2, 3, ...]);xhr.send(bytes.buffer);...
function onLoad(e) {// Request completed successfully
}
Uploading a File
var xhr = new XMLHttpRequest();xhr.open("POST", "services/upload", true);xhr.addEventListener("load", onLoad, false);xhr.send(file);
HTML5 file object representing file to be uploaded
Monitoring Upload Progress
var xhr = new XMLHttpRequest();xhr.open("POST", "services/upload", true);xhr.addEventListener("load", onLoad, false);xhr.upload.addEventListener("progress", onProgressChanged, false);xhr.send(file);...
function onProgressChanged(e) {if (e.lengthComputable) {
var percentComplete = (e.loaded / e.total) * 100;}
Downloading Binary Data
var xhr = new XMLHttpRequest();xhr.open("GET", "images/image.png", true);xhr.responseType = "arraybuffer";xhr.addEventListener("load", onLoad, false);xhr.send();...
function onLoad(e) {var type = this.responseType; // e.g., "arraybuffer"var bytes = new Uint8Array(this.response);
};
"" (text), "text", "json", "arraybuffer", "document", or "blob"
Cross-Domain Calls with XMLHttpRequest Level 2
No One Knows What Touch Will Look Like in HTML5
Original Touch Events specification was based on Safari touch API
http://www.w3.org/TR/touch-events/
Originally blessed by Apple, work stopped in 2012 due to patent considerations
Patent issues were settled and Touch Events were formalized in 2013
Newer Pointer Events API is based on pointer events in Internet Explorer
http://www.w3.org/TR/pointerevents/
Many at W3C were wary of Apple and were searching for an alternative touch API; Microsoft responded
Future looked bright for a while, but Chromium dropped support for pointer events in August 2014
In March 2015, Google announced that Chrome would support pointer events
It's anybody's guess what will happen next
Detecting Presses and Releases with the Pointer API
var canvas = document.getElementById("#canvas");canvas.addEventListener("pointerdown", onPointerDown, false);canvas.addEventListener("pointerup", onPointerUp, false);
function onPointerDown(e) {// Pointer pressed
}
function onPointerUp(e) {// Pointer released
}
Getting the Pointer Type
function onPointerDown(e) {switch (e.pointerType) {
case "mouse":alert("You used a mouse!");break;
case "pen":alert("You used a pen!");break;
case "touch":alert("You used a finger!");break;
}}
Pointer Events
New APIs Will Keep HTML5 Relevant for a Long Time
HTML5 is constantly evolving with new APIs, many of them needed for mobile
apps, apps that deal with media content, and apps that network
Device-motion API
Media Capture and Streams (getUserMedia) API
WebRTC API
Web Notifications API
Web Speech API
Web NFC API
Web Cryptography API
Battery Status API
And many more…
Using the Device-Motion API
window.addEventListener("devicemotion", onMotionChanged);...
function onMotionChanged(e) {// Accelerations expressed in meters/second2 (1G == 9.81)var ax = e.acceleration.x; // Acceleration in X directionvar ay = e.acceleration.y; // Acceleration in Y directionvar az = e.acceleration.z; // Acceleration in Z direction
// Rotation rates expressed in degrees/secondvar rx = e.rotationRate.alpha; // Rate around Z axisvar ry = e.rotationRate.beta; // Rate around X axisvar rz = e.rotationRate.gamma; // Rate around Y axis
}
Using the getUserMedia API
// Request webcam accessnavigator.getUserMedia({
video: true, // Request webcam accessaudio: true // Request microphone access
}, onMediaReady, onError);...
function onMediaReady(stream) {// Play the audio/video stream in a VIDEO elementvar video = document.getElementById("video");video.src = window.URL.createObjectURL(stream);video.play();
}
Using the Battery Status API
navigator.getBattery().then(function(battery) {// Get the battery levelvar level = battery.level; // 0.0 to 1.0
// If the battery is charging, get the remaining charge timeif (battery.charging) {
var time = battery.chargingTime; // Seconds}
});
Some of the Best Parts of HTML5 Aren't Part of HTML5
All HTML5 browsers support a native JSON API
JSON.stringify - Generate a JSON string from an object
JSON.parse - Generate an object from a JSON string
Modern selectors API provides more flexibility than document.getElementById
document.querySelector
document.querySelectorAll
WebGL offers hardware-accelerated rendering for 2D and 3D graphics
Specification maintained by non-profit Khronos Group
Generating and Consuming JSON
// Generate a JSON stringvar person = { firstName: "Jeff", lastName: "Prosise" };var json = JSON.stringify(person);
// Consume the JSON stringvar somebody = JSON.parse(json);var firstName = somebody.firstName;
Querying the Browser DOM
// Get all elements whose class is "content"var elements = document.querySelectorAll(".content");
// Get all checkboxes that are checked in "myform"var elements = document.querySelectorAll
("#myform input[type='checkbox']:checked");
// Set the background color of every other row of "mytable"// to light grayvar rows = document.querySelectorAll
("#mytable tr:nth-child(even)");
for (var i = 0; i < rows.length; i++) {rows[i].style.backgroundColor = "#e0e0e0";
}
Download the Code
http://1drv.ms/1tO5j5Y