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
Download
Current version 0.9
- Development 45 k (8k gzipped)
- Production 30 k (6k gzipped)
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)
colortransparent colordataif 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"]
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
- Artur Reterski/ perski - for wicked insectoid ships
- David Capello for Aseprite - awesome pixelart editor and insane drunk convolution kernel
- Ilmari Heikkinen for great article about image filtering and code for convolutions
- Michael Jackson for color conversion formulas
New documentation is running on node.js