Send to Kindle

Sunday, March 11, 2012

Getting Started with Dart Canvas

‹prev | My Chain | next›

Tonight I am going to start playing with Canvas in Dart. I much prefer something like Rapahaƫl for doing Canvas things in Javascript. Still raw Canvas can be useful as times as well. I am basing this off of a post that I did back in 2010 on Canvas.

I start with an HTML page empty except for a title, a script tag to pull in my main.dart file, and a little Javascript kick start that is still necessary to get the Dart engine humming in Dartium:
<html>
<head>
  <title>Hipster Canvas</title>
  <script type="application/dart"
     src="main.dart"></script>

  <script type="text/javascript">
    // start Dart
    navigator.webkitStartDart();
  </script>
</head>

<body>
<h1>Oooh Canvas!</h1>

</body>
</html>
To add the Canvas element, I try:
// Neither of these work...
new CanvasElement();
new CanvasElement.html('<canvas/>');
It seems, however that only Element.html() works as a constructor (sub-classes are not blessed with this ability). So, my main.dart becomes:
#import("dart:html");

main() {
  var canvas = new Element.html('<canvas/>');
  canvas.width = 900;
  canvas.height = 450;

  document.
    body.
    nodes.
    add(canvas);
}
With that, I have a canvas:


I move the canvas initialization into its own buildCanvas() function and would now like to set about drawing my avatar on the canvas:
CanvasRenderingContext context;

int width = 900,
    height = 450;

main() {
  CanvasElement canvas = buildCanvas();
  context = canvas.getContext("2d");
  draw(x: (width/2).toInt(), y: (height/2).toInt());
}
I grab the rendering context from the canvas and squirrel it away in a library-wide variable, context. I also store the width and height in library-wide variables so that I can draw myself at the exact center of my canvas universe. I lack subtlety.

As for drawing myself, for now I will be simply a red rectangle. First, I wipe the canvas clean, then draw myself in the appropriate spot:
draw([int x, int y]) {
  context.beginPath();

  // clear drawing area
  context.clearRect(0,0,width,height);
  context.fillStyle = '#ffffff';
  context.strokeStyle = '#000000';
  context.fillRect(0,0,width,height);

  // draw me and fill me in
  context.rect(x,y,20,20);

  context.fillStyle = 'red';
  context.fill();

  context.stroke();

  context.closePath();
}
And yes, I do end up where I belong:


To move myself about, I encapsulate my position inside a player class:
class Player {
  int x, y;
  Player() {
    x = (width/2).toInt();
    y = (height/2).toInt();
  }
  move(String dir) {
    if (dir == 'left') x-= 10;
    if (dir == 'right') x+= 10;
    if (dir == 'up') y-= 10;
    if (dir == 'down') y+= 10;
  }
}
I then define a library global me and direction variable and update draw() to use me instead of coordinates:
Player me;
String direction;

main() {
  CanvasElement canvas = buildCanvas();
  context = canvas.getContext("2d");

  me = new Player();
  draw();
  attachMover();
}
As for the actual movement, I use the attachMover() function to listen for keyboard events—specifically for the arrow keys:
attachMover() {
  // Move on key down
  document.
    on.
    keyDown.
    add((event) {
      direction = null;

      if (event.keyCode == 37) direction = 'left';
      if (event.keyCode == 38) direction = 'up';
      if (event.keyCode == 39) direction = 'right';
      if (event.keyCode == 40) direction = 'down';

      if (direction != null) {
        event.preventDefault();
        me.move(direction);
        draw();
      }
    });

  // Stop on key up
  document.
    on.
    keyUp.
    add((event) {
      direction = null;
    });
}
With that, I can move myself all over my little canvas:


There really was not much different between that experience and doing the same in Javascript. But at least Dart is not getting in my way yet. And there is still lots more to explore...


Day #322

1 comment:

  1. It would be interesting to try updating this example to use observables from the web-ui library.

    ReplyDelete