Sunday, February 12, 2012

KineticJS

HTML5 Canvas is freaking awesome and, although HTML5 has many improvements over HTML4, Canvas is probably one of the strongest and my personal favorite.

One of the things that I like about Canvas is that it provides a really nice low-level API, allowing for a great degree of control over the drawing. The problem is that, without using an external library, some simple tasks are a little bit cumbersome and hard to maintain.

For example, let's assume we want to create a simple page like:
          • Two boxes, one red and one blue.
          • Each box will show an alert when clicked upon.










The code should be something like this:
<html>
    <head>
        <script type="text/javascript" src="jquery-1.7.1.min.js"></script>
        <script type="text/javascript">

            $(function () {

                var canvas = $('#canvas')[0];
                var context = canvas.getContext('2d');
                if (context) {

                    context.fillStyle = 'red';
                    context.fillRect(0, 0, 100, 100);

                    context.fillStyle = 'blue';
                    context.fillRect(0, 100, 100, 100);
                }

                $('#canvas').click(function (e) {

                    if (e.clientX >= 0 && e.clientX < 100) {

                        if (e.clientY >= 0 && e.clientY <= 100) {
                            alert('red square clicked');
                        }

                        if (e.clientY >= 100 && e.clientY <= 200) {
                            alert('blue square clicked');
                        }
                    }
                });

            });
        </script>
    
    </head>

    <body>
        <canvas id='canvas' width='400' height='400'></canvas>
    </body>
</html>
Having one click event-handler and comparing manually the coordinates of objects inside the canvas is a little bit old-school. Nowadays, and with the likes of jQuery, one gets spoiled by it's declarative syntax. For example, with jQuery the event handlers are created like (assuming elements 'red' and 'blue'):
    $('#blue').click(function() { alert('blue square clicked'); });
    $('#red').click(function() { alert('red square clicked'); });
Wouldn't it be great to mix the canvas API with a declarative syntax like jQuery? Fortunately there's a library which does just that. It's called KineticJS.

KineticJS API is, IMHO, brilliant. It mixes a declarative syntax with full control over the Canvas Context element. For example, drawing a simple square:
var redsquare = new Kinetic.Shape(function () {
    var context = this.getContext();
    context.fillStyle = 'red';
    context.fillRect(0, 0, 100, 100);
});
The canvas code is exactly the same. The difference is that we're creating the drawing in the context (pun intended) of a Kinetic.Shape object. Thus, the rectangle becomes a first class citizen, providing properties, methods and events. For example, the click event is implemented as:
redsquare.on("click", function () {
    alert('red square clicked');
});
Hell yeah, and although the API is very simple this is just the tip of the Iceberg. Scaling, rotating, drag-and-drop, etc, you name it. See the full documentation here.
For me writing Canvas code without KineticJS is like writing Javascript without jQuery: it's certainly possible, but why should we? :P
The full source-code with KineticJS:
    
<html>
    <head>
        <script type="text/javascript" src="jquery-1.7.1.min.js"></script>
        <script type="text/javascript" src="kinectic-v.3.7.2.min.js"></script>
        <script type="text/javascript">

            $(function () {

                var stage = new Kinetic.Stage("canvas", 400, 400);
                var layer = new Kinetic.Layer();

                var redsquare = new Kinetic.Shape(function () {
                    var context = this.getContext();
                    context.fillStyle = 'red';
                    context.fillRect(0, 0, 100, 100);
                });

                var bluesquare = new Kinetic.Shape(function () {
                    var context = this.getContext();
                    context.fillStyle = 'blue';
                    context.fillRect(0, 100, 100, 100);
                });

                redsquare.on("click", function () {
                    alert('red square clicked');
                });

                bluesquare.on("click", function () {
                    alert('blue square clicked');
                });

                layer.add(redsquare);
                layer.add(bluesquare);

                stage.add(layer);

            });
        </script>
    
    </head>

    <body>
        <div id='canvas'></div>
    </body>

</html>

No comments:

Post a Comment