API: Objects

rsandor edited this page Aug 9, 2011 · 13 revisions

How Objects Work

Gury uses the term object to denote a JavaScript object that can be rendered to a canvas. Objects come in two varieties: simple functions that draw statically to a canvas, and more complex JavaScript objects that can hold state, update, and draw to the canvas via a .draw() method. Let's get started with a quick example:

// Create a new canvas using Gury with size 100 x 100
$g().size(100, 100)

  // Add a simple rendering function
  .add(function(ctx) {
    ctx.fillStyle = "red";
    ctx.fillRect(10, 10, 80, 80);
  })

  // Place and draw the scene
  .place("#my_container").draw();

The example above illustrates how to use the simpler type of object, a rendering function. The function itself is pretty simple too as it only draws a red square smack dab in the middle of the canvas. Now let's look at more complex example:

// Create a new canvas using Gury with size 100 x 100
$g().size(100, 100)
 
   // Add a slightly more complex object to the canvas
  .add({
    draw: function(ctx, canvas) {
      ctx.fillStyle = "blue";
      ctx.fillRect(10, 10, canvas.width - 20, canvas.height - 20);
    }
  })

  // Place and draw the scene
  .place("#my_container").draw();

In the example above we replaced the simple function-type object for that of a full fledged object with a .draw() method. You'll notice that we passed a second parameter to the function canvas which is given the value of the actual canvas node when the object is drawn. Let's finish up with an even more complex example that uses states:

// Create a new canvas using Gury with size 100 x 100
$g().size(100, 100)
  // Create a new spinning green square
  .add({
    theta: 0,
    draw: function(ctx, canvas) {
      ctx.fillStyle = "green";
      ctx.save();
      ctx.translate(canvas.width / 2, canvas.height / 2);
      ctx.rotate(this.theta);
      ctx.fillRect(-32, -32, 64, 64);
      ctx.restore();
    },
    update: function() {
      this.theta += Math.PI / 120;
    }
  })
  // Place and animate the scene
  .place("#my_container").play(32);

In the example above we use a theta variable in the object to hold it's current rotation and update that value in the .update() method. The .play(32) above tells Gury to animate the canvas and update all objects (via each object's .update() method) and redraw the scene every 32 milliseconds.

How Tags Work

Gury has a built-in tagging system that allows you to tag objects you add to canvases with the .add() method. Most of the time you'll use simple one word tags to keep track of the anonymous objects you create. Here's an example to get you going:

// Create a new canvas using Gury with size 100 x 100
$g().size(100, 100)

  // Add an object with the tag "block"
  .add('block', function(ctx) {
    ctx.fillStyle = "red";
    ctx.fillRect(10, 10, 80, 80);
  })

  // Add an object with the tag "notblock"
  .add('notblock', function(ctx) {
    ctx.fillStyle = "blue";
    ctx.fillRect(10, 10, 80, 80);
  })

  // Finally add another object with the tag "block"
  .add('block', function(ctx) {
    ctx.fillStyle = "red";
    ctx.fillRect(10, 10, 80, 80);
  })

  // And immediately remove all object with the tag "block" from the canvas
  .remove("block");

When executed the above example would create three objects, two of which have the tag "block" and another with the tag "notblock". Then the two objects with the tag "block" would be removed from the scene leaving only the object with tag "notblock". While not particularly useful it does help to illustrate how tags work.

For more examples of using tags see .add(), .each(), .hide(), etc. below in the Methods section and demos/tags.html in the repository.

Methods

Below are listed the Gury methods that deal with adding, removing, and manipulating objects on a canvas.

.add(object)

Adds an object to be rendered on the canvas. The object parameter can be either a function that accepts a single graphics context argument (for quick rendering):

$g('my_canvas').add(function(ctx) {
  ctx.fillStyle = "#f00";
  ctx.drawRect(0, 0, 20, 20);
  // ... 
});

or a full object that contains a draw method which accepts both the context upon which to draw and optionally a reference to the canvas node:

$g('my_canvas').add({
  x: 0, dx: 1,
  draw: function(ctx, canvas) {
    if (this.x >= canvas.width)
      this.dx *= -1;
      //...
  }
});

.add(tag, object)

As with .add(object) this method adds an object to be rendered on the canvas. Additionally it associates a tag name with that object for use with the various object/tag methods described below.

A quick example:

$g('my_canvas')
  .add('players.mario', new Mario())
  .add('players.luigi', new Luigi())
  .toggle('players.mario'); // Luigi finally has his day!

Tags are hierarchical, meaning that if you were to then execute:

  $g('my_canvas').toggle('players')

It would show the Mario object and hide the Luigi object (and Luigi would no longer rule the day, alas). For more information read the section on object tags above and see the tag methods (.each(), .hide(), etc.) below.

.remove(object)

Removes an object from the canvas. If the object is not in the canvas then this method has no effect. Here's an example:

// Add a circle
var circle = new Circle();
$g('my_canvas').add(circle).draw();

// Remove that same circle
$g('my_canvas').remove(circle).draw();

Again, remember that if you are not animating the canvas you will need to call .draw in order for the changes to appear.

.remove(tag)

Removes all objects with the given tag from the canvas. Here's an example:

// Add a box and a circle
$g('my_canvas').add('circle', new Circle()).add('box', new Box()).draw();

// Remove the box
$g('my_canvas').remove('box').draw();

.each(closure)

Executes a closure on each of the objects associated with the canvas. An example explains this a bit better:

$g('my_canvas')
  .add(new Ball())
  .add(new Ball())
  .each(function(object, index) {
    object.x -= 10;
    object.y += 10; 
}).animate(16);

Executing the script above would move each of the objects 10 pixels down and 10 pixels to the left (note that the Ball class is not part of Gury but is used as an example).

.each(tag, closure)

Does the same thing as .each(closure) but only iterates over objects that were added with the provided tag parameter. Let's take a look with an example:

$g('my_canvas')
  .add('red', new Ball('red'))
  .add('red', new Ball('red'))
  .add('green', new Ball('green'))
  .each('red', function(object) {
    object.x -= 10;
    object.y += 10;
}).draw();

In this example only balls that were tagged with red will be moved down and to the left. All other balls (i.e. the green tagged ball) will remain unaffected.

Important: Just changing the properties of objects will not cause the canvas to redraw and display those changes. For static scenes we must explicitly redraw using the .draw() method. Animated scenes tend not to have this problem as they are technically calling .draw() on each animation interval.

Keep this in mind for .each(), .hide(), .show(), or .toggle() methods. This may change in the future, but for now it's the law of the land.

.hide() / .hide(tag)

Prevents objects from drawing and animating. Example:

$g('my_canvas')
  .add('circle', new Circle())
  .add('box', new Box())
  .hide().draw();

The preceding example would hide all objects regardless of their tag. Here's another example:

$g('my_canvas')
  .add('circle', new Circle())
  .add('box', new Box())
  .hide('circle').draw();

which hides only the circle, leaving the box rendering alone (poor lonely box). Again, as with many of these examples, the Box and Circle classes aren't part of Gury but are used as examples.

.show() / .show(tag)

Ensures that objects render and animate. Example:

$g('my_canvas')
  .add('box', new Box())
  .hide('box').draw();
      
// ... Maybe do some other stuff ...
    
$g('my_canvas').show().draw();

In the preceding example we created a box, immediately hid it, and then turned around and decided to show everything anyway. While not practical (or particularly sane) it is illustrative of using .show(). The next example uses tags:

$g('my_canvas')
  .add('box', new Box())
  .add('circle', new Circle)
  .hide()
  .show('circle').animate(32);

In this example we add a box, then a circle, then hide everything, and finally show only the circle by using tags.

.toggle() / .toggle(tag)

What visibility library would be complete without a toggle method? This method basically just toggles objects on and off as it is called. Let's get going with an example:

var gury = $g('my_canvas')
  .add('box', new Box())
  .add('circle', new Circle()).play(16);
      
// Add a little jQuery action...
$('#my_button').click(function() {
  gury.toggle();
});

The example above simply adds a box and a circle and then uses some jQuery magic to bind an event that toggles all of the objects on and off when some element with the id my_button is clicked. A final example should cement the concept:

$('my_canvas')
  .add('box', new Box())
  .add('circle', new Circle())
  .toggle('box').draw();

Simple enough: we just add a box, a circle, then toggle the box off and draw the scene.