HTML 5 canvas performance experiment

I have started playing around with HTML 5 canvas to see what it can be used for and decided to test the performance with an old animated plasma-like demo effect that I used to do in my early days of programming some 20 years ago (I can’t believe I’m that old, how did that happen?).

Here’s a screen dump of the effect on a 600 by 400 pixel canvas:

Screen dump of the plasma effect in action

Here’s the page with the demo in real-life: http://www.meadow.se/codesamples/html5/canvasdemos/canvasdemo2.html

In Chrome I get a frame rate of about 18 frames per second on my Intel Core i7 2.70 GHz laptop with Mobile Intel graphics circuits. That’s okay I suppose, since most of the time is spent in the calculations of the color values using the following formula:

var r = Math.cos(animationOfffset + x/100 * y /100) * 255;
var g = Math.sin(animationOfffset + ((x * x) / 300) * (y / 300)) * 255;
var b = Math.cos(animationOfffset + (x-y) / 500) * 255;

This calculation has to be done for each of the (600 x 400 = 240 000) pixels in each frame. The limiting performance factor in this demo is definetely the CPU rather than the graphical performance of the canvas.

However, when I tried the demo in IE 9 on the same machine, I got about 5 fps! That’s 4 times slower! I have also tried the same demo with IE 10 and while that’s faster than IE 9, it’s still about 2.5 times slower than Chrome on the same machine.

All is not bad for IE though since it rendered the rotating text better. Comparing IE and Chrome side by side it’s obvious that IE has more stable text rendering, in Chrome the individual characters jiggle slightly when rotating the text. Once you notice it, it’s actually rather ugly.

I also tested the demo on my Samsung Galaxy S3 mobile and got 4 fps in Chrome and about the same in the built-in browser. About the same figures as for IE on my laptop. Not bad for a mobile phone…

To conclude, it’s apparently still very important to take the different browsers you’re running you’re Javascript and HTML 5 code on into account when developing web applications. It’s the 90s all over again… 😉

PS. If you try the demo yourself, feel free to post your frame rates in a comment to this post, It’ll be interesting to see how much it differs.

UPDATE 2012-12-06:

I have now tried replacing the calls to the Math.sin and Math.cos functions with pregenerated lookup tables (inspired by this code: Professor Cloud’s Fast Sine demo) and the new demo can be found here:

http://www.meadow.se/codesamples/html5/canvasdemos/canvasdemo2_LUT.html

I now get 42 fps in Chrome on my laptop, i.e. more than doubled performance, which is rather nice. However, the result in IE 9 is still only 5 fps, the same as before. So now Chrome is 8 times faster!

In Chrome on my Samsung Galaxy S3, the result is now 5 fps, also not a great improvement. The only deduction I can make from this is that for IE9 and Galaxy S3, it wasn’t the maths that limited the performance, but something else in the code. I don’t know what it might be so if anyone can shed some light on this it would really appreciated.

/Emil

Refreshing data in jQuery DataTables

Allan Jardine’s DataTables is a very powerful and slick jQuery plugin for displaying tabular data. It has many features and can do most of what you might want. One thing that’s curiously difficult though, is how to refresh the contents in a simple way, so I for my own reference, and possibly for the benefit of others as well, here’s a complete example of one way if doing this:

<table id="HelpdeskOverview">
  <thead>
    <tr>
      <th>Ärende</th>
      <th>Rapporterad</th>
      <th>Syst/Utr/Appl</th>
      <th>Prio</th>
      <th>Rubrik</th>
      <th>Status</th>
      <th>Ägare</th>
    </tr>
  </thead>
  <tbody> 
  </tbody> 
</table>
function InitOverviewDataTable() {
    oOverviewTable = $('#HelpdeskOverview').dataTable(
        {
            bPaginate: true,
            bJQueryUI: true, // ThemeRoller-stöd
            bLengthChange: false,
            bFilter: false,
            bSort: false,
            bInfo: true,
            bAutoWidth: true,
            bProcessing: true,
            iDisplayLength: 10,
            sAjaxSource: '/Helpdesk/ActiveCases/noacceptancetest',
            fnRowCallback: formatRow
        });
}
function RefreshTable(tableId, urlData) {
    //oSettings.sAjaxSource?
    $.getJSON(urlData,
        null, function (json) {
            table = $(tableId).dataTable();
            oSettings = table.fnSettings();

            table.fnClearTable(this);
            for (var i = 0; i < json.aaData.length; i++) {
                table.oApi._fnAddData(oSettings, json.aaData[i]);
            }
            oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
            table.fnDraw();
        });
}
function AutoReload() {
    RefreshTable('#HelpdeskOverview', '/Helpdesk/ActiveCases/noacceptancetest');

    setTimeout(function () { AutoReload(); }, 30000);
}
$(document).ready(function () {
    InitOverviewDataTable();
    setTimeout(function () {
           AutoReload();
        },
        30000);
});