Accessing the gyroscope and accelerometer using JavaScript

With the advent of "mobile" devices such as the iPad, iPhone and all the gazillion Android devices, an increasing demand for browser-applications to sport the features and functionality native applications arises. In this article I'll have a quick look at one of these features, namely «device orientation». First of all, take a look at the demo. In this demo I'm using the "deviceorientation" event listener of the «window» object to listen for orientation events. Orientation events are in short events triggered when your device is twisting and turning, sort of. In my iPhone, these events originate in the accelerometer and the gyroscope. For your phone this might be different, but it doesn't matter as the API's for accessing the data are pretty much the same and part of the «DeviceOrientation Event Specification». Note that this demo is only tested on the iPhone 4, so if you have something else it might not work. Let's get to it then.
window.addEventListener('deviceorientation', orientationHandler, false);

First of all we need to add an event listener for the «device orientation» event. This event is fired by the «window» object as mentioned above. We then simply set up our event handler.

function orientationHandler(e)
{
 image.style.webkitTransform = "perspective(500) 
rotateZ("+e.alpha+"deg) 
rotateX("+e.beta+"deg) 
rotateY("+e.gamma+"deg)";
}

There are three properties of the «orientation event» we want to get at.

  • «alpha» - This is rotation about the Z axis. In other words left and right rotation.
  • «beta» - This is rotation about the X axis. This means how much you are tilting the device towards you.
  • «gamma» - This is the rotation about the Y axis, or the angle of the device screen if you may.
There are also two other properties present in iOS 5 which gives you access to the compass and it's accuracy, but those are not used in this example.

The «perspective(500)» transform simply defines how "far away" from the object you are when it's rotated, or the depth if you like. Since the properties of the «device orientation» event correlates to the values handled by the CSS transform properties, no calculation is needed. Try it out! (Should work on iPhone 4 and iPad 2)

References:

HTML 5 Web Workers and image processing

One of the more exiting things we are getting via the new HTML specification is Web Workers. If you have no idea what Web Workers (lets call them Worker from now on) are you can basically think of them as "sandboxed" threads. By threads I do refer to threads as in «multithreading», an architectural feature of modern CPUs and operating systems. Workers allow us to run tasks separately from the main thread where all the drawing, animation and DOM manipulation is going on. This allows us to do calculations without leaving the impression on the user that the browser is "hanging". If you have worked with other "thread wrapping" technologies like Grand Central Dispatch (GCD) you will get Workers without fuzz, however Workers do have some limitations that other similar technologies don't have.

Workers limitations and usage
First of all, Workers are separate code blocks of JavaScript not found in the spawning script, kinda.. In most cases a Worker is a separate JavaScript file which you DO NOT refer to in you HTML script tags in the HTML document. However, Workers can also be defined inline through the BlobBuilder interface. In this post I will use only external Workers. Also, there are two kinds of Workers, «Shared» and «Dedicated». I will only use «Dedicated Workers» in this post.

Workers cannot access the following:
  • The DOM or the DOM APIs
  • The window object
  • The document and the parent object. 
A worker can access:
  • The «navigator» object
  • «XMLHttpRequest»
  • A read-only version of the «location» object
  • The Application cache
  • setTimeout(), clearTimeout() and setInterval(), clearInterval()
A Worker can also spawn other Workers and import external scripts via «importScripts()».

The demo (aka. the fun part)
For the demo this time I have created a simple web-app which loads and displays 3 pictures n times. You can randomize the position of the images by clicking the randomize button. You can pick the number of images displayed as well as their size. The two image manipulation buttons will grayscale and invert the images, if you check the checkbox the images will perform the randomize animation concurrently with the image processing. It's this latter part which calls for the usage of Workers.

The demo will show you how to spawn a separate Worker for each of the images, thereby allowing for concurrent processing and animation without much degradation in performance. I won't explicitly go through all the layout and animation code here, rather focusing on the usage of the Workers.

var worker = new Worker('DWGrayscale.js');
worker.addEventListener('message', function(e){
   ctxAr[e.data.index].context.putImageData(e.data.imagedata,0,0);
});
worker.postMessage(...imagedata...);

On line 126 - 133 within the grayscale function we create a Worker for each of the images, then we add a listener for the «onmessage» event allowing the Worker to communicate with the main thread. We finish off by posting a message to the worker using «postMessage» and passing the image data. These messages are the only way to communicate with a Worker. This means that we also need to implement this interface in the Worker itself.
addEventListener('message', function(e){
 var imageData = e.data.imagedata;
 //....process image data....
 postMessage(...imagedata...);
});
In the Worker «DWGrayscale.js» we grab the passed image data from the «data» property of the event. We then go on processing the image data, when done we post a message back to the main thread passing the image data which then in turn can be used to update the canvas element on screen.

Why not pass the Canvas element or at least the Canvas context?
Workers do not have access to the DOM, because it would not be thread safe. Workers are limited to passing object which can be serialized into JSON, which does not support cyclic objects. The Canvas element is a DOM element and the context is a cyclic object, hence we need to get the actual pixel array which we can pass back and forth to the Worker.

Take a look at the demo and the source code to learn in more detail how the demo was created.
Note also that you should probably run the demo in Safari as it has no limitation on the number of Workers concurrently running like Chrome has, also the animations uses the WebKit prefix and will not work in non WebKit browsers. So, please don't use this code in an production environment!

References:

Quicktip: Skewing an image with JavaScript and CSS3

Have you ever found yourself in a situation where you needed to skew a rabbit? If you haven't, you'll probably enter this place soon, so here I am to prepare you. The task is to skew an image on a HTML page using CSS and JavaScript. This could be attached to for instance a button click event. This is a one liner..
document.getElementById('myImage').style.transform = "skew(-15deg)"
The «skew» property of the «transform» CSS method takes degrees of skew as an input. Negative numbers will skew the image top right, bottom left and positive numbers..the other way around.
Note that in order for this to actually work, you will need to use vendor prefixes as the time of writing this post. For Safari (desktop and iOS) and Chrome (and Android) you would use «webkitTransform» for FireFox «mozTransform» and so on.

The Peacekeeper

Peacekeeper on an iMac 3.0 Ghz
I decided to try out Futuremaks spanking "new" Peacekeeper browser tester today. In contrast to other more "nerdy" tests like Acid3 and SunSpider which are useful for people like me, Peacekeepers tests are more targeted at actual normal usage of a browser, making it slightly more interesting for users without a degree in computer science.

On the other hand, if you want to understand the six test, well.. it gets a bit technical. The first test «rendering» is a test of how fast the browser can draw stuff to the screen, while doing other calculations and operations at the same time. The second test which Futuremark calls «social networking» is actually a test in how fast the browser can create a SHA1 hash, parse some XML and filtering and sorting the elements of an array. Thirdly we arrive at the «complex graphics» test, which is a test on canvas drawing operations, canvas being part of the new HTML 5 standard. The «data» test which I have renamed to "arrays" does work on exactly that, array manipulation. The «DOM manipulation» test, is one of the most important tests as this tests the browsers ability to look up elements in the DOM fast. This should be of particular interest to jQuery fans. The last test «text parsing», is what its name suggests, parsing and searching in strings. To get a full detailed explanation of what the individual test entails, see Futuremarks FAQ site.

My testcomputer was an iMac 3.06 GHz, with 8GB of RAM and an ATI Radeon HD 4670 graphics card running OS X 10.6.7. It matters, because these tests will very, much, depending on your computer and OS.

As for the results one can clearly see that the WebKit browsers beat the snot out of Firefox. Chrome is clearly the fastest browser overall, however for DOM manipulation Safari is slightly faster than Chrome. Again, beware of this one jQuery fans because this is where all those selectors come into play. Chrome is ruling the array manipulation speed, this might be due to the V8 JavaScript engine. All the browsers basically suck when it comes to rendering HTML 5 Canvas graphics. As a side-note, I observed a test that was run on a Windows based computer as well. To our surprise, both Chrome and Opera beat Internet Explorer 9 into the slippers when it came to canvas performance. Beauty of the web my ass, in your own tests internally made tests perhaps.

Conclusion
So, judging from this Google Chrome is the browser your should go for. And in my opinion, it is. For me, I'm sticking with Safari for my day to day use, but I'm using Chrome when writing this blog post.