• No results found

The devicemotion Event

In document HTML5 Programming Jonathan Reid (Page 177-184)

* Handles a deviceorientation event on the window object.

* @param {DeviceOrientationEvent} event A standard device orientation event.

*/

function handleDeviceOrientation(event) { // Update the DOM with the raw event data.

alpha.innerHTML = event.alpha;

beta.innerHTML = event.beta;

gamma.innerHTML = event.gamma;

// Use the raw data to get x and y coordinates for the ball.

xposit = getCoord(event.gamma, xposit);

xpos.innerHTML = xposit;

yposit = getCoord(event.beta, yposit);

ypos.innerHTML = yposit;

ball.style.top = yposit + 'px';

ball.style.left = xposit + 'px';

} /**

* Increments a coordinate based on an angle from the device orientation event.

* @param {number} angle The orientation angle.

* @param {number} coord The coordinate to increment.

*/

function getCoord(angle, coord) {

// First, get a delta value from the angle.

var delta = Math.round(angle);

var tempVal = coord + delta;

// Limit the incremented value to between 0 and 194.

if (tempVal > 0) {

// Register the event handler.

window.addEventListener('deviceorientation', handleDeviceOrientation, false);

</script>

</body>

</html>

This example displays the raw event data on the screen, and uses that raw event data to determine the coordinates of the element on the screen. In this case, it limits the position of the element so that it stays inside of its containing element.

The devicemotion Event

The devicemotion event fires regularly on the window object, and produces an event of type

DeviceMotionEvent. The DeviceMotionEvent has four properties: acceleration (the values of which represent the acceleration of the device along the x, y, and z axes, in meters per second squared),

accelerationIncludingGravity (the values of acceleration with the effects of the Earth’s gravity included, if any), rotationRate (the rate of rotation of the alpha, beta, and gamma angles in degrees per second), and interval (how often this information is refreshed from the hardware, in milliseconds). Overall the schema of the DeviceMotionEvent looks like this:

object DeviceMotionEvent = { object acceleration: { number x,

number y, number z },

object accelerationIncludingGravity: { number x,

number y, number z },

object rotationRate: { number alpha,

You can easily display each of these values, as shown in Listing 5-8.

Listing 5-8. Displaying the Values of a devicemotion Event

<!DOCTYPE html>

<html>

<head>

<meta name="viewport" content="width=device-width, user-scalable=no">

<title>The HTML5 Programmer's Reference</title>

</head>

<body>

<h1>Device Motion Demonstration</h1>

<ul>

<li>acceleration:

<ul>

<li id="accX">x: <span class="current"></span>,<br>

max: <span class="max"></span></li>

<li id="accY">y: <span class="current"></span>,<br>

max: <span class="max"></span></li>

<li id="accZ">z: <span class="current"></span>,<br>

max: <span class="max"></span></li>

</ul>

</li>

<li>accelerationIncludingGravity:

<ul>

<li id="aigX">x: <span class="current"></span>,<br>

max: <span class="max"></span></li>

<li id="aigY">y: <span class="current"></span>,<br>

max: <span class="max"></span></li>

<li id="aigZ">z: <span class="current"></span>,<br>

max: <span class="max"></span></li>

</ul>

</li>

<li>rotationRate:

<ul>

<li id="rrAlpha">alpha: <span class="current"></span>,<br>

max: <span class="max"></span></li>

<li id="rrBeta">beta: <span class="current"></span>,<br>

max: <span class="max"></span></li>

<li id="rrGamma">gamma: <span class="current"></span>,<br>

max: <span class="max"></span></li>

</ul>

</li>

</ul>

<script>

// Create a data structure to store the references to the various DOM elements // we will be manipulating, as well as associated maximum values. The structure // also includes an interface method for processing incoming data and mapping // it to the correct DOM elements.

var motionValues = { acceleration : { x : {

domCurr : document.querySelector('#accX .current'), domMax : document.querySelector('#accX .max'), maxVal : 0

}, y : {

domCurr : document.querySelector('#accY .current'), domMax : document.querySelector('#accY .max'), maxVal : 0

}, z : {

selector : '#accZ',

domCurr : document.querySelector('#accZ .current'), domMax : document.querySelector('#accZ .max'), maxVal : 0

} },

accelerationIncludingGravity : { x : {

domCurr : document.querySelector('#aigX .current'), domMax : document.querySelector('#aigX .max'), maxVal : 0

}, y : {

domCurr : document.querySelector('#aigY .current'), domMax : document.querySelector('#aigY .max'), maxVal : 0

},

z : {

selector : '#accZ',

domCurr : document.querySelector('#aigZ .current'), domMax : document.querySelector('#aigZ .max'), maxVal : 0

} },

rotationRate : { alpha : {

domCurr : document.querySelector('#rrAlpha .current'), domMax : document.querySelector('#rrAlpha .max'), maxVal : 0

}, beta : {

domCurr : document.querySelector('#rrBeta .current'), domMax : document.querySelector('#rrBeta .max'), maxVal : 0

}, gamma : {

selector : '#accZ',

domCurr : document.querySelector('#rrGamma .current'), domMax : document.querySelector('#rrGamma .max'), maxVal : 0

} }, /**

* Processes an acceleration value object of a specific type. The values are * enumerated and mapped to their associated DOM elements for display.

* @param {string} valueType The type of the value object, one of

* 'acceleration', 'accelerationIncludingGravity', or 'rotationRate'.

* @param {object} valueObject The object containing the acceleration data.

*/

processValues : function(valueType, valueObject) {

// First, get a reference to the subproperty of the motionValues object we // will be manipulating.

var mvRef = this[valueType];

// Enumerate the valueObject and process each property.

for (property in valueObject) {

// Convenience references to the current values we're working with.

var currMVRef = mvRef[property];

var currVal = valueObject[property];

// Update the DOM to display the current value.

currMVRef.domCurr.innerHTML = currVal;

// If the current value is larger than the last stored maximum value, // update the stored max value to match and display it in the DOM.

if (currVal > currMVRef.maxVal) { currMVRef.maxVal = currVal;

currMVRef.domMax.innerHTML = currVal;

} } } };

/**

* Handles a devicemotion event on the window object.

* @param {DeviceMotionEvent} event A standard device motion event object.

*/

function handleDeviceMotion(event) {

motionValues.processValues('acceleration', event.acceleration);

motionValues.processValues('accelerationIncludingGravity', event.accelerationIncludingGravity);

motionValues.processValues('rotationRate', event.rotationRate);

}

// Register the event handler.

window.addEventListener('devicemotion', handleDeviceMotion, false);

</script>

</body>

</html>

Because there are many values to display, and much of the data is specifically structured thanks to the DeviceMotionEvent schema, Listing 5-8 begins this example by creating an object that has a similar schema.

For each individual property it stores a DOM reference to the element that will display its current value, a DOM reference to the element that will display the maximum value achieved, and the maximum value itself. It also includes a simple interface method that maps the DeviceMotionEvent subproperties to their associated subproperties in the object, and updates the DOM to reflect the new information.

To use this example you need to move your device around. These values are for acceleration, which is the rate of change of velocity (while velocity is the rate of change of position). In order to see appreciable values you will need to move your device fairly quickly. It’s sufficient to shake your device along the various axes of motion. Be careful to keep a firm grip on your device so you don’t accidentally throw it. The maximum values of acceleration along the various axes will be recorded for you so you can see them after you’re done moving your device around. You can also spin the device to see rotation rates.

WebGL

SUppOrt LeVeL

Good

All modern desktop browsers support these features for at least the last two versions, with the exception of Internet explorer, which has only supported them since version 11. Mobile support is poor, as Mobile Safari for iOS does not currently support WebGl, though Apple has committed to full support with iOS version 8.

Specifications:

http://www.khronos.org/webgl/

The Web Graphics Library (WebGL) is an API for drawing complex 2d and 3d graphics in HTML canvas elements. The WebGL API is presented as a drawing context on a given canvas element, just like the standard drawing context that you explored in Chapter 4. Just like the standard canvas drawing context, the WebGL drawing context is accessible in JavaScript via an extensive API. Many WebGL tasks, such as image processing, are delegated to the host system’s Graphics Processing Unit and are not handled by the system’s main CPU, thus providing a significant speed boost.

Unlike most of the other standards covered in this book, the WebGL standard is not maintained by either the W3C or the WHATWG. The standard is maintained by the nonprofit technology consortium Khronos Group. The language itself is based on the OpenGL language, and grew out of experiments in 3d rendering done at Mozilla in 2009. The current stable release of WebGL is 1.0.2. Work started on WebGL 2 in 2013.

Initializing a WebGL drawing context is very similar to initializing a standard drawing context in a canvas element, as shown in Listing 5-9.

Listing 5-9. Initializing a WebGL Drawing Context

<!DOCTYPE html>

<html>

<head>

<title>The HTML5 Programmer's Reference</title>

<style>

<canvas id="myCanvas" width="200" height="200">Did You Know: Every time you use a browser that doesn't support HTML5, somewhere a kitten

This example uses the getContext method just as you did in Chapter 4. The difference is that instead of providing a parameter of '2d' for a 2d drawing context, it provides the 'webgl' parameter to specify a WebGL drawing context. You can easily expand this to be a function, which even provides a place for initializing the context as needed, as shown in Listing 5-10.

Listing 5-10. A WebGL Initialization Function

<!DOCTYPE html>

<html>

<head>

<title>The HTML5 Programmer's Reference</title>

<style>

canvas {

border: 1px solid #000;

}

</style>

</head>

<body>

<canvas id="myCanvas" width="200" height="200">Did You Know: Every time you use a browser that doesn't support HTML5, somewhere a kitten cries. Be nice to kittens, upgrade your browser!

</canvas>

<script>

/**

* Returns a WebGL drawing context on a specified canvas element. If opt_setup * is provided and set to true, this method also performs some basic

* initialization on the context.

* @param {!Element} targetCanvas The reference to the desired canvas element.

* @param {boolean} opt_setup Whether or not to perform additional setup on the * context.

* @return {Object} The WebGL drawing context, or null if WebGL is not supported * or was otherwise unavailable.

*/

function initWebGLOnCanvas(targetCanvas, opt_setup) {

// If opt_setup was not specified, set it to false. In JavaScript, null and // undefined are == to each other and nothing else, so:

if (opt_setup == null) { opt_setup = false;

}

// Try and get the context.

var glContext = targetCanvas.getContext('webgl');

if (glContext == null) {

// Try falling back to an experimental version, works on some older browsers.

glContext = targetCanvas.getContext('experimental-webgl');

if (glContext == null) {

// We were unable to get a WebGL context. Provide a warning diagnostic // message on the console, in case anyone is looking.

console.warn('WebGL is not supported in this browser.');

} }

// If there is a context and setup was requested, do the setup.

if ((opt_setup === true) && (glContext != null)) { // Set the clear color to black (rgba).

glContext.clearColor(0.0, 0.0, 0.0, 1.0);

// Initialize the depth function so that objects that are closer in // perspective hide things that are further away.

glContext.depthFunc(glContext.EQUAL);

// Enable depth testing.

glContext.enable(glContext.DEPTH_TEST);

// Clear both the color and the depth buffer.

glContext.clear(glContext.COLOR_BUFFER_BIT|glContext.DEPTH_BUFFER_BIT);

}

return glContext;

}

var myCanvas = document.getElementById('myCanvas');

var myGLContext = initWebGLOnCanvas(myCanvas, true);

</script>

</body>

</html>

This example expands the initialization function to detect if there has been a problem getting the WebGL context, with a fallback to an older syntax that is present on older browsers. If the context cannot be fetched at all, a warning is output to the console. Running this example will produce a black square in the browser.

As of this writing, Firefox is currently blacklisting a significant number of Windows, MacOS, Linux, and Android graphics drivers in the WebGL initialization process. If you have one of these drivers, Firefox by default will not initialize a WebGL drawing context. If you run this example in Firefox and you see the warning message in the console, chances are your setup is blacklisted. For details and instructions on how to override the block, see https://wiki.mozilla.org/Blocklisting/Blocked_Graphics_Drivers. Another alternative is to use a browser that has a less brittle WebGL implementation (Chrome’s implementation of WebGL is quite solid).

Note Up until recently, Safari Mobile on iOS did not support WebGl. Safari 8.1 introduced full WebGl

support.

WebGL is an extensive language, and fully covering it and everything you can do with it is beyond the scope of this book. If you want to learn more, check out Beginning WebGL for HTML5 by Brian Danchilla (Apress, 2012).

SVG

SUppOrt LeVeL

excellent

In document HTML5 Programming Jonathan Reid (Page 177-184)