HTML5 Canvas + Haxe

There are 2 approaches to work with html canvas in Haxe:

  • using HaxeNME as all-in-one solution;
  • work with canvas directly or using one of the native js library.

I'm going to consider both of them.

HaxeNME

I've already mentioned HaxeNME in previous post. With HaxeNME you can compile the same code for different platforms. It is based on Flash API so it wouldn’t be problem for Flash developers to create HaxeNME applications. Here is simple example:

HaxeNME Example:

  
package org.example.test;

import com.eclecticdesignstudio.motion.Actuate;  
import nme.events.MouseEvent;  
import nme.events.Event;  
import nme.display.Shape;  
import nme.display.Sprite;

class Main extends Sprite  
{
    private var _shape:Shape;

    public function new()
    {
        super();
        _shape = new Shape();
        _shape.graphics.beginFill(0xFF0000);
        _shape.graphics.drawCircle(20, 20, 20);
        _shape.graphics.endFill();
        addChild(_shape);

        if (stage != null)
        {
            init();
        }
        else
        {
            addEventListener(Event.ADDED_TO_STAGE, init);
        }
    }

    private function init(?e:Event):Void
    {
        if (e != null)
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
        }

        stage.addEventListener(MouseEvent.CLICK, stageClickHandler);
    }

    private function stageClickHandler(e:MouseEvent):Void
    {
        //Actuate - well-known tween engine for Flash, ported to Haxe
        Actuate.stop(_shape);
        Actuate.tween(_shape, 1, {x:stage.mouseX - 20, y:stage.mouseY - 20});
    }
}

Result of this code:

As you can see code is almost the same as ActionScript 3. Unlike AS3 this code can be compiled to native code for each target platform. So you don’t need any additional runtimes like JVM or Adobe AIR to run HaxeNME application. Currently HaxeNME supports 8 platforms. But this topic is out of current post. Let’s get back to the subject and look at HaxeNME output. As a result of compilation we have to files: html and js. The size of js file is 253KB - quite heavy for this simple example. Optimization of js with advanced compilation level of Google Closure Compiler reduced size of js to 132KB, almost twice smaller, but app stopped to work in browser without any error:-) Using simple compilation level produced 185KB of js and example works fine.

CreateJS

I think everybody who works with Flash and stay tuned with Flash-world heard about new HTML5 functionality of Adobe Flash CS6. Now it’s possible to convert your animations to pure HTML5. This feature based on CreateJS framework, “a suite of Javascript libraries & tools for building rich, interactive experiences with HTML5.” It consists of 4 parts:

  1. EaselJS - "a JavaScript library that makes working with HTML5 Canvas element easy". It's inspired by Flash API.
  2. TweenJS - "a Javascript library for tweening and animating HTML5 and Javascript properties."
  3. SoundJS - "a Javascript library that provides a simple API, and powerful features to make working with audio a breeze."
  4. PreloadJS - "a Javascript library that lets you manage and co-ordinate the loading of assets."

I've created a haxe library createjs in order to use CreateJS toolkit with haxe. It can be installed via

haxelib install createjs

Here's the same simple example but rewritten using CreateJS:

  
package;

import createjs.tweenjs.Ease;  
import createjs.easeljs.Ticker;  
import createjs.tweenjs.Tween;  
import createjs.easeljs.Stage;  
import createjs.easeljs.Shape;

class Main  
{
    private static var _shape:Shape;
    private static var _stage:Stage;

    public static function main():Void
    {
        //Ticker provides a centralized tick or heartbeat broadcast at a set interval.
        //Here we tells it to use browser "requestAnimationFrame" instead of "setTimeout" to process ticks
        Ticker.useRAF = true;
        //Maximum FPS
        Ticker.setFPS(60);

        //Creating of stage. We need to create stage manually. Constructor receives canvas element declared in index.html.
        _stage = new Stage(cast js.Lib.document.getElementById("c"));
        _stage.onMouseUp = stageClickHandler;

        //Shape object, looks familiar:-)
        _shape = new Shape();
        _shape.graphics.beginFill("#FF0000");
        _shape.graphics.drawCircle(20, 20, 20);
        _shape.graphics.endFill();
        _stage.addChild(_shape);

        //Alternative to Event.ENTER_FRAME. Method tickHandler called 60 times per second
        Ticker.addListener(tickHandler);
    }

    //In CreateJS we have to update stage every time any display object changed.
    //So it's not necessary to update it on each frame but in this example choose the simple way.
    private static function tickHandler():Void
    {
        _stage.update();
    }

    //Stage was clicked
    private static function stageClickHandler():Void
    {
        //Using tween-engine from CreateJS
        Tween.removeTweens(_shape);
        Tween.get(_shape).to({x:_stage.mouseX - 20, y:_stage.mouseY - 20}, 1000, Ease.quadOut);
    }
}

It also based on Flash API but the goal of CreateJS isn’t cloning of Flash API but painless transfer from Flash to HTML5. For example, Flash events are not implemented in CreateJS. Instead it uses traditional JS event model (e.g. object.onClick = function(){...}). For this example Haxe produced 1KB of js-code but to be fair we need to add size of CreateJS libraries to this number. Our generated js + 4 CreateJS libraries (although we use only 2 of them) = 93KB - twice smaller than HaxeNME.

But in this case size isn’t so important. I think the most important indicator for graphics is performance. So I created 2 benchmarks to compare performance of CreateJS and HaxeNME:

Benchmark for HaxeNME

Benchmark for CreateJS

Results:

I used latest (today is 31.08.2012) versions of browsers: Chrome 21, Firefox 15 and IE 10 from Windows 8 Release Preview.

It's clear fact that HaxeNME (I mean HTML5 target of HaxeNME) is much slower than CreateJS. HTML5 target of HaxeNME creates new canvas for each DisplayObject so for 1000 penguins it need to create 1000 canvases. While CreateJS uses only one canvas instance to draw all DisplayObjects. This is the main reason for such difference.

Summary

Pros and cons of HaxeNME:

+ Implements Flash API. It will be easy for Flash developer to use this framework;

+ You can easily compile your HaxeNME application to native application for each of 8 supported targets;

- Some features of Flash are not working in HTML5 target. For example, masks. I hope it will be fix in future releases;

- Poor performance of HTML5 target due to DOM-rendering of display list.

CreateJS:

+ Supported by Adobe Flash CS6 so you can easily convert your flash animations to HTML5;

+ Small footprint. It's not necessary to use all libraries from toolkit together. You can use only EaselJS for canvas interactions or only PreloadJS to load your resources;

+ Simmilar to Flash API;

- A lot of features missed for Flash developer, e.g. events, keyboard interactions, BitmapData API. Of course, it's easy to find replacement for them, but it takes more time sort out such things, especially if you're not familiar with JavaScript.

And the last thing. Here is HTML5 remake of famous "Singing Horses" flash. I've made it using CreateJS. Just click on any horse.

Tweet
comments powered by Disqus