Javascript Canvas - Red circle

In this tutorial we are going to explore how to get started with Canvas when using Javascript haxe. We are not going to use any external libraries.

In this tutorial we are going to explore manipulating Canvas pixels in Javascript Haxe.

The canvas tag may not be supported on Internet Explorer, it depending on the version, so lets assume for these tests we are running a recent version of Chrome, Firefox or Opera, especially since pixel manipulation in the browser can be potentially quite heavy.

Installing Html5 haxelib


Haxe javascript out of the box does not currently support Html5 so we need to install the html5 haxelib, open a Terminal or Command prompt.
haxelib install html5

Currently I have some problems with this version of the html5 library, I always end up patching the ContextRenderingContext2D class, I keep a handy amended copy of this class in my Divtastic repository you can grab the class here:

http://code.google.com/p/divtastic/source/browse/js/html5/CanvasRenderingContext2D.hx

The html5 library can be found in the haxelib directory, on a mac it will be...

usr/lib/haxe/lib/html5/

on windows it's likely to be
c:/motion twin/haxe/lib/html5/

Basic Javascript setup


We are now ready to start coding. For javascript target we need to always import some javascript standard classes, often js.Lib and js.Dom are a good start, containing many of the Typedef's that help define javascript internal classes. So the top of our class starts with a directory package structure which we can assume a namespace based on this tutorial.
package haxe_instructor.justinfront.canvas_pixels;
import js.Lib;
import js.Dom;

Our main class needs the usual static main and new methods, and for javascript we appendChild Div's to the document body, since we may need to access the document again let create a local variable for this:
class Main
{
    var body: Body;   
    static function main(){ new Main(); }
    publc function new()
    {
        trace('test');
        var doc = Lib.document;
        body = doc.body;
    }
}

Testing our project, creating an index and compile.hxml


We can create an index html page to run this code we normally start this with a standard Doc type then in the head of the html doc we add some project details and then in the body we can reference our javascript code. I put this in a deploy folder with the name index.html.
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
   "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Justinfront</title>
    <meta name="author" content="Justin L Mills">
    <!-- Date: 1st Nov 2012 -->
</head>
<body bgcolor="#ffffff">
<script type="text/javascript" src="justinfront_canvas_pixels.js"></script>
</body>

To compile our code we need to create an hxml file, with the -main class name, the -js output javascript code and include the html5 library we installed earlier, notice the package path for the Main class and the deploy folder defined in the output so that the code is placed next to the index.html.
-main haxe_instructor.justinfront.canvas_pixels.Main
-js deploy/justinfront_canvas_pixels.js
-lib html5
#-cmd open -a /Applications/firefox.app deploy/index.html

I commented out the last line, but on a mac it allows me to open and run the javascript in the browser automatically after compiling, you can do similar on a pc or open manually.
When we run this we will get a black page not very exciting but if you open the browsers console you should see a trace output "test".

Creating a Canvas


Next we need to appendChlld our canvas to the body of the html document. If we want to draw or manipulate pixels then we need to get a reference to the CanvasRenderingContext2D which is the same as a Sprites graphic ( consider a javascript Canvas or Div to be a bit like a flash Sprite ). It's a bit strange but at the moment with haxe you endup creating a generic HtmlDom element and then you cast it to a Canvas. Then we have to use untyped to grab the CanvasRenderingContext2D to draw on. Lastly we set the dimensions, I have choose a default screen size 1024x768 but if you omit this it normally defaults to 300x300 pixels. Manipulating a large canvas is not a good idea but we can manipulate a larger canvas as parts so later we will work on just 250x250 image.
    var dom: HtmlDom = doc.createElement('Canvas');
    var canvas: Canvas  = cast dom;
    // grab the CanvasRenderingContext2D for drawing on
    var surface = untyped canvas.getContext('2d');
    // style can be used for postioning/styling the div or canvas.
    var style = dom.style;
    // add the canvas to the body of the document
    body.appendChild( dom );
    // setup dimensions.
    canvas.width = 1024;    
    canvas.height = 768;

Ok so adding this to our current code is still going to result in blank page. So let draw a circle on the CanvasRenderingContext2D. In the example method I am using arc but you can probably use circle, I am not going to explain the code as it is just to test the canvas is created, it just draws a red circle with black edge.
    public function drawCircle( x: Float, y: Float, radius: Float )
    {
        surface.strokeStyle = '#000000';
        surface.lineWidth = 1;
        surface.fillStyle = '#ff0000';
        surface.beginPath();
        surface.arc( x + radius, y + radius, radius, 0, 2*Math.PI, false );
        surface.stroke();
        surface.closePath();
        surface.fill();
    }

Red Circle on Canvas


Ok so we need to add some code to call the drawCircle function and also I am storing the CanvasRenderingContext2D as surface. We don't need the trace now so we can remove it. So the whole class now looks like...
package haxe_instructor.justinfront.canvas_pixels;
import js.Lib;
import js.Dom;

class Main
{
    var body: Body;
    var surface: CanvasRenderingContext2D;
    static function main(){ new Main(); }
    public function new()
    {
        var doc = Lib.document;
        body = doc.body;
        var dom: HtmlDom = doc.createElement('Canvas');
        var canvas: Canvas = cast dom;
        surface = untyped canvas.getContext('2d');
        var style = dom.style;
        body.appendChild( dom );
        canvas.width = 1024;
        canvas.height = 768;
        drawCircle( 100, 100, 30 );
    }
    
    public function drawCircle( x: Float, y: Float, radius: Float )
    {
        surface.strokeStyle = '#000000';
        surface.lineWidth = 1;
        surface.fillStyle = '#ff0000';
        surface.beginPath();
        surface.arc( x + radius, y + radius, radius, 0, 2*Math.PI, false );
        surface.stroke();
        surface.closePath();
        surface.fill();
    }
}

version #15652, modified 2012-11-06 17:10:48 by JLM