Design, CG Graphics & Inspiration
LibCanvas Basics. The Practice

LibCanvas Basics. The Practice

This is a continuation of the article about LibCanvas basics. In the first part we’ve touched upon the theoretical side and now we’re going to do some practice and try to implement very basic and simple things. The main purpose of the article is to master the basic knowledge about LibCanvas, we’ll write a simple scripts, unsuitable for the use in real life, but you can develop them into something great.

HTML

The html-file structure is very simple:

<!DOCTYPE html>
<html>
   <head>
      <meta charset="utf-8" />
      <script src="atom.js"></script>
      <script src="libcanvas.js"></script>
      <script src="application.js"></script>
   </head>
   <body>
      <canvas></canvas>
   </body>
</html>

You should connect the last AtomJS and LibCanvas. The beginners should better use *- full-compiled versions from the repository. Next, we’ll consider the contents of application.js.

A simple drawing into the canvas

We are still able to draw into the canvas with the help of context. You must wait until the DOM is fully loaded, to get a canvas element, its context and draw two figures. I globalized immediately the entire contents of LibCanvas. Later, when I’ll be showing examples -the contents of onready-function would be meant only.

Now we simply draw a green rectangle and red circle on a light coffee canvas:

LibCanvas.extract();

atom.dom(function() {
   var canvas  = atom.dom('canvas').first;
   var context = canvas.getContext('2d-libcanvas');

   context
      .fillAll( '#efebe7' )
      .fill( new Rectangle( 75, 75, 30, 30 ), 'green' )
      .fill( new Circle   ( 50, 50, 20 )    , '#c00'  );
});

Animation

But this approach let’s you draw only some static images. For anything interactive you need to create LibCanvas object. Let’s make a very simple application – a black canvas filled with random green rectangles. Note two important points:

1. By default, the canvas is cleared with every new frame, that’s why you should turn off this default behavior by {clear: null}.

2. The function passed to start is referred to render phase, that’s why it won’t be called without updating the canvas, we have achieved it with the help of .addFunc (libcanvas.update). In fact, it’s a bad decision, but in this case it’s the right one.

var libcanvas = new LibCanvas('canvas', { clear: null });

libcanvas.ctx.fillAll('black');

libcanvas
   .start(function () {
      this.ctx.fill(
         new Rectangle({
            from: this.ctx.rectangle.getRandomPoint(),
            size: [ 2, 2 ]
         }), 'green'
      );
   })
   .addFunc( libcanvas.update );

Objects

Now let’s add the object. Let it be a segment of black color, which will rotate around one of its points. This time we need to clear the canvas before drawing the next frame, because we will not cancel clear. Look at the code and read the comments:

var Item = atom.Class({
   Implements: [ Drawable ],
   // In the constructor, we take two  -
   // Point - the center of rotation and rotational speed in radians per second
   initialize: function (center, speed) {
      this.line = new Line( center,
         // We clone and displace the point to the right so we get
         // another point in the twenty pixels from the current
         center.clone().move([ 20, 0 ])
      );
      // the time is in milliseconds, and the speed is specified in milliseconds too
      // therefore it is necessary to bring speed to the format "radians / millisecond"
      this.speed = speed / 1000;
   },
   update: function (time) {
      // we rotate the second point of the line around the first
      this.line.to.rotate(
         // in order to make speed independent from fps we
         // multiply the speed by elapsed time. If the fps is low, than it
         // will be updated less frequently, but the changes will be at a greater angle
         this.speed * time,
         this.line.from
      );
      // It is needed to report to libcanvas, that the appearence of the canvas has changed
      // and it would be necessary to redraw it
      this.libcanvas.update();
   },
   draw: function () {
      // just draw a straight line
      this.libcanvas.ctx
         .stroke( this.line, 'black' );
   }
});

var libcanvas = new LibCanvas('canvas');

// We construct a new object
// Pay attention to the angle designation. A person usually accustomed to calculate the angle in degrees
// In programming, it's appropriate to keep the angle in radians.
// Such designation makes it easy to get radians from degrees
var item = new Item( new Point(50, 50), (180).degree() );


libcanvas.addElement( item )
   // It is important not to forget to "run" the LibCanvas, it waits for your command "start"
   .start()
   // Note that if we just give "item.update", then it will be called
   // with the wrong context, that's why we tie it to the object with a bind:
   .addFunc( item.update.bind(item) );

We’ve got a twisting arrow.

The response to a mouse

Let’s take our arrow into the red circle that you can drag. It’s quite easy, as you can see only a few lines has changed. Please note that I have created a feature shape, and not circle. This is necessary for Draggable.

var Item = atom.Class({
   Implements: [ Drawable, Draggable /* Таскаемый */ ],
   [...]
   initialize: function (center, speed) {
      [...]
      // create a circle
      this.shape = new Circle( center, 25 );
   },
   [...]
   draw: function () {
      [...]
         .stroke( this.shape, '#c00' );
   }
});

[...]
libcanvas.listenMouse();
item.draggable()

We see that almost everything began to work, but there is an error, when we drag the circle – the arrow changes its length. The secret is that when we move the circle, the point center, which is the beginning of the segment, also moves. The end of the segment remains on its place and begins to spin on a new trajectory.

initialize: function (center, speed) {
   [...]
   // It is necessary for the second point to move along with the first
   center.addEvent('move', function (diff) {
      this.line.to.move(diff);
   }.bind(this))
},

Now it’s correct.

Stopwatch

Now let’s add another arrow, and thus realize the stopwatch – time that has elapsed since the first moment of visiting the page. Code will change a little, but mostly it will be very similar to the previous one, so I will comment only the important parts and give only the class code:

var StopWatch = atom.Class({
   Implements: [ Drawable, Draggable ],
   initialize: function (center) {
      this.center   = center;
      this.millisec = this.line();
      this.seconds  = this.line();
      this.minutes  = this.line();
      this.shape    = new Circle( center, 25 );

      center.addEvent('move', function (diff) {
         // we call the "move" method with "diff" parameter for all points
         [this.millisec.to, this.seconds.to, this.minutes.to].invoke('move', diff);
      }.bind(this));
   },
   // Method for easy line creation
   line: function () {
      return new Line( this.center, this.center.clone().move([0, -20]) );
   },
   update: function (time) {
      var full = (360).degree();

      // Methods toSeconds, toMinutes and toHours are taken from LibCanvas.Utils.Math
      // Millisecond hand must make a complete revolution per second
      this.millisec.to.rotate( full * time.toSeconds(), this.center );
      // Second - per minute
      this.seconds .to.rotate( full * time.toMinutes(), this.center );
      // Minute - per hour
      this.minutes .to.rotate( full * time.toHours()  , this.center );
      this.libcanvas.update();
   },
   draw: function () {
      this.libcanvas.ctx
         .stroke( this.shape   , '#c00' )
         .stroke( this.millisec, '#999' )
         .stroke( this.seconds , '#000' )
         .stroke( this.minutes , '#090' );
   }
});

Here what we’ve got.

Conclusion

Yes, the barrier is high. But in its return you get a highly optimized application, extensibility, good architecture and powerful tools. Hopefully, the articles shed a light on the basic notions of LibCanvas.

You might also be interested in..

LibCanvas Basics. The Theory
HTML5 Canvas: Frequently Asked Questions
Creating a Framework For Canvas: Objects and Mouse
Fifteen puzzle in LibCanvas
20 Free HTML5 Games
How to create a Progress bar with HTML5 Canvas
Meet The Future – HTML5 Demos

SHARE THIS POST

Pavel is 21 year old web developer from Ukraine. In his spare time he writes articles about the basics of LibCanvas, AtomJS and JavaScript

Subscribe for the hottest posts

Subscribe to our email newsletter for useful tips and freebies.