Canvas Query

  • Extended canvas for gamedevelopers
  • Methods chaining
  • Easy setup for a logic loop, rendering, mouse, touch, gamepad and keyboard
cq(640, 480)
  .drawImage(image, 0, 0)
  .fillStyle("#ff0000")
  .fillRect(64, 64, 32, 32)
  .appendTo("body");

Important changes

These are changes that can impact your current code:

  • Effects has been removed as a useles feature
  • Framework events has been lowercased in order to keep up with js naming conventions
  • Framework has been moved to a plugin canvasquery.framework.js

Overviews

0.9 0.8 0.7

Download

Current version 0.9

Getting started

You can try the code using button playground

Creating wrapper

From existing canvas

var canvas = document.create("canvas");
var canvas = document.getElementById("something");

cq(canvas);

From image

var image = new Image;
var image = document.getElementById("something");

cq(image);

From CSS Selector

cq("#canvas");
cq(".image");

Empty

cq(320, 240);

Fullscreen

cq();
  • Wrapper will have all original Canvas2DContext methods and properties.
  • For reference print this and learn this

You can still access original context and canvas element

cq("#something").canvas;
cq("#something").context;

Chaining

CanvasQuery provides methods chaining similar to jQuery:

cq().fillStyle("#ff0000").fillRect(0, 0, 640, 480).drawImage(image, 0, 0).blur();

All setters/getters has been transformed to functions:

cq().fillStyle("#ff0000").globalAlpha(0.2).lineWidth(6);

However sometimes it is more convenient to use .set() method

cq().set({
  fillStyle: "#ff0000",
  globalAlpha: 0.2,
  lineWidth: 6
});

Clone

Any change done to the wrapper will be applied to the original provided (or created) canvas element. Whenever you want to break the chain reaction and get a fresh copy use .clone() method:

cq().clone().setHsl(...);

Appending

If you want to insert your canvas to document body use .appendTo() method:

cq(320, 240).fillStyle("#00ff00").fill(0, 0).appendTo("body");

You can use either css selector or provide a DOM element.

Help

If you have any question ask it here or on stackoverlow

Extensions

The main point of Canvas Query is to provide methods to solve common canvas problems - these are called context extensions:

  var myScreen = cq(320, 240);

  myScreen.drawImage(image, 32, 64);
  myScreen.setHsl(1.0, 0.5, 0.5);

Basic

clear

.clear (color = null)

Clears the canvas using clearRect or fillRect if the color is specified.

crop

.crop (x, y, width, height)

Crops the canvas to specified rect.

trim

.trim (color = false, data)

  • color transparent color
  • data if an object is provided it will contain trim boundaries

Automatically trims the image. If no color is provided transparent pixels will be used to determine boundaries.

var boundaries = { };

/* trim transparent pixels and save boundaries */
cq(someImage).trim(null, boundaries);

resizePixel(size)

.resizePixel (size)

Scales each pixel to match new size. Aka resize without bluring.

roundRect

.roundRect (x, y, width, height, radius)

Rounded rectangle. Equivalent of border-radius in css. Remember that it's a path, so requires calling .fill or .stroke right after.

paperBag

.paperBag (x, y, width, height, modX, modY)

  • modX, modY [0.0 - 1.0]

Creates useless paper bag shape. Remember that it's a path, so requires calling .fill or .stroke right after.

borderImage

.borderImage (image, x, y, top, right, bottom, left, fill)

Create expandable widgets (buttons, frames, e.t.c) - fill can be set to false, true, or color as a string.

Blending

Blending is mixing two images/canvases using a special function like in gimp/photoshop - explanation

Canvas query blend modes example

use .blend (above, mode, mix)

Allows you to blend two layers using a blend mode like in gimp/photoshop. Wrapper will be used as a bottom layer. All changes are applied to the bottom layer.

  • above [canvas, image, cq, color] - top layer to be mixed - you can even provide a color.
  • mode [addition, burn, color, darkenOnly, difference, divide, dodge, grainExtract, grainMerge, hardLight, hue, lightenOnly, multiply, normal, overlay, saturation, screen, softLight, substract, value]
  • mix [0 - 1] - blending ammount
cq(someImage).blend(anotherImage, "hardLight", 0.6);
cq(someImage).blend("#ff0000", "hue", 1.0);

Colors

cq.color

Creates Canvas Query color object which can be used to convert color throught variety of formats. It is CQ's internal property - not a context extension

var color = cq.color(arguments);

cq.color(128, 64, 32, 0.5);
cq.color("#ff00aa");
cq.color("rgb(32, 64, 128)");
cq.color("rgba(32, 64, 128, 0.5)");
cq.color("hsl(0.5, 1.0, 0.2)");
cq.color("hsv(0.1, 0.4, 0.5)");

conversions

var color = cq.color(128, 64, 32, 0.5);

color.toArray() // [128, 64, 32, 0.5]
color.toRgb()   // "rgb(128, 64, 32)"
color.toRgba()  // "rgba(128, 64, 32, 0.5)"
color.toHex()   // "#804020"
color.toHsl()   // [0.05, 0.6, 0.31]
color.toHsv()   // [0.05, 0.75, 0.5]

setHsl

Very useful for coloring units and bullets

.setHsl (hue, saturation, lighting)

Filters canvas setting HSL values for each pixel. Values are between 0 and 1. If you don't want to change the value provide null as an argument.

cq().setHsl(0.5, null, null); // changes Hue only

shiftHsl

.shiftHsl (hue, saturation, lighting)

Same as .setHsl but instead of being set each component is shifted in positive or negative direction between -1 and 1;

cq().adjustHsl(null, -1.0, null); // completly desaturate image

grayscaleToAlpha

.grayscaleToAlpha ()

Convert grayscale of an image to its transparency. Light pixels become opaque. Dark - transparent.

getPalette

.getPalette ()

Returns an array with all colors of an image in hex represantation.

matchPalette

.matchPalette (palette)

Reduces colors to a certain palette. Palette is in array of hex colors ["#ffaa00", "#844223"]

example

Text

textBoundaries

.textBoundaries (text, x, y, maxWidth)

Gets boundaries { width, height } of a wrapped text.

wrappedText

.wrappedText (text, x, y, maxWidth)

Fills word wrapped text

gradientText

.gradientText (text, x, y, maxWidth, gradient)

Fills text with a gradient. For best crossbrowser experience text baseline should be set to top before using this method.

Gradient is an array of color stops and values:

cq()
  .textBaseline("top")
  .gradientText("some text", 32, 32, 160, [
    0.0, "#ff0000",
    0.5, "#ffff00",
    0.8, "#00aaaa"
  ]);

Masking

grayscaleToMask

.grayscaleToMask ()

Creates [byte] mask from grayscale values. So if you have pixel [96, 96, 96] it is pushed to the array as [96]

colorToMask

.colorToMask (transparentColor, inverted)

  • inverted [false/true] wether the transparent pixel should be pushed as false or true

Create [boolean] mask. Selected color will be treated as transparent.

For example using following code on image with red background:

cq(image).colorToMask("#ff0000");

Will result in boolean array [true, false false, true, ... ] where all red pixels become false.

applyMask

.applyMask (mask)

Applies [boolean] mask to a canvas - false pixels become transparent.

fillMask

.fillMask (mask, color)

Fill [boolean or byte] mask with given color.

.fillMask (mask, colorA, colorB)

Fill [boolean or byte] mask using a gradient before colorA and colorB.

Check out using mask and game-icons

Framework

Micro framework which allows you to quickly deploy bare bones canvas application with mouse and keyboard. Especially useful for javascript playgrounds.

You need to include framework plugin first:

<script src="http://canvasquery.com/canvasquery.framework.js"></script>

Check out example usage

Setup

cq().framework({

/* game logic loop */
  onstep: function(delta, time) { },

  /* rendering loop */
  onrender: function(delta, time) { },

  /* window resize */
  onresize: function(width, height) { },

  /* mouse and touch events */
  onousedown: function(x, y) { },
  onmouseup: function(x, y) { },
  onmousemove: function(x, y) { },

  /* keyboard events */
  onkeydown: function(key) { },
  onkeyup: function(key) { },

  /* gamepad events (chrome only) */
  ongamepaddown: function(button, gamepad) { },
  ongamepadup: function(button, gamepad) { },
  ongamepadmove: function(xAxis, yAxis, gamepad) { },

  /* user drops image from disk */
  ondropimage: function(image) { }

}).appendTo("body");

Within the framework - if context is not specified this becomes a reference to the canvas wrapper which was used to call the framework method. It is explained later under advanced usage

Game loop

onstep is internally a setInterval - it should be used to update game logic - as it does NOT pause when user changes tab.

Provided delta argument is a difference of time between current and last frame in miliseconds. You should use it in your calculations to ensure same game speed on different machines:

onstep: function(delta) {

  player.x = player.speed * delta / 1000;
}

You can also provide interval property which is 25 by default

Rendering loop

onRender is a shortcut for requestAnimationFrame. You should use it to draw your game as it IS paused when user changes tab - which saves users CPU and battery.

Keyboard

in keyboard events key is translated to string ex. "escape", "a", "f4", "pagedown"

Mouse

on mobile devices:

  • onmousemove becomes ontouchmove
  • onmousedown becomes ontouchstart
  • onmouseup becomes ontouchend

You can disable this feature by providing touchToMouse: false argument.

Touch

If you want to handle mouse and touch events separately you can use these events:

  • ontouchstart
  • ontouchend
  • ontouchmove

Remember to disable touch to mouse event translation by providing touchToMouse: false argument. Also you can enable multitouch prevention preventMultitouch: true.

Drop image

Provides a way to quickly deploy an application which expects image from users disk. Check the following example:

http://cssdeck.com/labs/html5-drag-and-drop-image-tool-with-canvasquery

Fit to screen

CanvasQuery can follow window size changes and adjust size of the viewport to the screen keeping the proportions. In order to do that three arguments must be provided:

{
  width: 640,
  height: 480,  
  fitToScreen: true
}

Advanced usage

In fact framework method takes two arguments .framework(events, context) first one is set of events to be applied the other is context which defaults to the canvas wrapper.

Professional application could be built like this:

var game = {

  setup: function() {  

    this.layer = cq().framework(this, this);    
    this.layer.appendTo("body");
  },

  onstep: function(delta) {

    this.entities.step(delta);
  },

  onrender: function() {

      this.entities.render(this.layer);
  }

}

game.setup();

Plugins API

Similar to jQuery - however uses no shorthands.

Extending the wrapper

CanvasQuery.Wrapper.prototype.newMethod = function() { ... }

is equal to jQuery:

jQuery.fn.newMethod = function() { ... }

Extending CanvasQuery itself

CanvasQuery.newMethod = function() { ... }

Example plugin

CanvasQuery.Wrapper.prototype.fillWithColor = function(color) {
  this.context.fillStyle = color;
  this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
  return this;
}

Please let me know if you write any plugin.

Credits

Main contributors

Thanks to

New documentation is running on node.js