Created
July 22, 2013 06:00
-
-
Save IceCreamYou/6051592 to your computer and use it in GitHub Desktop.
A Layer object (basically a utility canvas, useful for caching intermediate graphics buffers). Adapted from https://github.com/IceCreamYou/HTML5-Canvas-Game-Boilerplate/blob/gh-pages/js/boilerplate/drawing.js#L7
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* The Layer object (basically a new, utility canvas). | |
* | |
* Layers allow efficient rendering of complex scenes by acting as caches for | |
* parts of the scene that are grouped together. For example, it is recommended | |
* to create a Layer for your canvas's background so that you can render the | |
* background once and then draw the completely rendered background onto the | |
* main canvas in each frame instead of re-computing the background for each | |
* frame. This can significantly speed up animation. | |
* | |
* In general you should create a layer for any significant grouping of items | |
* if that grouping moves together when animated. It is more memory-efficient | |
* to specify a smaller layer size if possible; otherwise the layer will | |
* default to the size of the whole canvas. | |
* | |
* Draw onto a Layer by using its "context" property, which is a | |
* {@link CanvasRenderingContext2D canvas graphics context}. | |
* | |
* @param {Object} [options] | |
* A set of options. | |
* @param {Number} [options.x=0] | |
* The x-coordinate of the top-left corner of the Layer. | |
* @param {Number} [options.y=0] | |
* The y-coordinate of the top-left corner of the Layer. | |
* @param {Number} [options.width] | |
* The width of the Layer. | |
* @param {Number} [options.height] | |
* The height of the Layer. | |
* @param {Number} [options.opacity=1] | |
* A fractional percentage [0, 1] indicating the opacity of the Layer. | |
* 0 (zero) means fully transparent; 1 means fully opaque. This value is | |
* applied when {@link Layer#draw drawing} the layer. | |
* @param {Number} [options.parallax=1] | |
* A fractional percentage indicating how much to {@link Layer#scroll scroll} | |
* the Layer relative to the viewport's movement. | |
* @param {Mixed} [options.src] | |
* Anything that can be passed to the `src` parameter of | |
* {@link CanvasRenderingContext2D#drawImage drawImage()}. This will be used | |
* to draw an image stretched over the whole Layer as a convenience. | |
* @param {HTMLElement} [options.canvas] | |
* A Canvas element in which to hold the Layer. If not specified, a new, | |
* invisible canvas is created. Careful; if width and height are specified, | |
* the canvas will be resized (and therefore cleared). This is mainly for | |
* internal use. | |
*/ | |
function Layer(options) { | |
options = options || {}; | |
/** | |
* @property {HTMLElement} canvas | |
* The canvas backing the Layer. | |
* @readonly | |
*/ | |
this.canvas = options.canvas || document.createElement('canvas'); | |
/** | |
* @property {CanvasRenderingContext2D} context | |
* The Layer's graphics context. Use this to draw onto the Layer. | |
* @readonly | |
*/ | |
this.context = this.canvas.getContext('2d'); | |
this.context.__layer = this; | |
/** | |
* @property {Number} width | |
* The width of the Layer. | |
* @readonly | |
*/ | |
this.width = options.width || this.canvas.width; | |
/** | |
* @property {Number} height | |
* The height of the Layer. | |
* @readonly | |
*/ | |
this.height = options.height || this.canvas.height; | |
/** | |
* @property {Number} x | |
* The x-coordinate on the {@link global#canvas global canvas} of the | |
* upper-left corner of the Layer. | |
*/ | |
this.x = options.x || 0; | |
/** | |
* @property {Number} y | |
* The y-coordinate on the {@link global#canvas global canvas} of the | |
* upper-left corner of the Layer. | |
*/ | |
this.y = options.y || 0; | |
/** | |
* @property {Number} opacity | |
* A fractional percentage [0, 1] indicating the opacity of the Layer. | |
* 0 (zero) means fully transparent; 1 means fully opaque. This value is | |
* applied when {@link Layer#draw drawing} the layer. | |
*/ | |
this.opacity = options.opacity || 1; | |
/** | |
* @property {Number} parallax | |
* A fractional percentage indicating how much to | |
* {@link Layer#scroll scroll} the Layer relative to the viewport's | |
* movement. | |
*/ | |
this.parallax = options.parallax || 1; | |
if (this.canvas.width != this.width) { | |
this.canvas.width = this.width; | |
} | |
if (this.canvas.height != this.height) { | |
this.canvas.height = this.height; | |
} | |
/** | |
* @property {Number} xOffset | |
* The horizontal distance in pixels that the Layer has | |
* {@link Layer#scroll scrolled}. | |
*/ | |
this.xOffset = 0; | |
/** | |
* @property {Number} yOffset | |
* The vertical distance in pixels that the Layer has | |
* {@link Layer#scroll scrolled}. | |
*/ | |
this.yOffset = 0; | |
if (options.src) { | |
this.context.drawImage(options.src, 0, 0, this.width, this.height); | |
} | |
/** | |
* Draw the Layer. | |
* | |
* @param {CanvasRenderingContext2D} ctx | |
* A canvas graphics context onto which this Layer should be drawn. This is | |
* useful for drawing onto other Layers. | |
* @param {Number} [x] | |
* An x-coordinate on the canvas specifying where to draw the upper-left | |
* corner of the Layer. Defaults to the | |
* {@link Layer#x Layer's "x" property} (which defaults to 0 [zero]). | |
* @param {Number} [y] | |
* A y-coordinate on the canvas specifying where to draw the upper-left | |
* corner of the Layer. Defaults to the | |
* {@link Layer#y Layer's "y" property} (which defaults to 0 [zero]). | |
*/ | |
this.draw = function(ctx, x, y) { | |
x = typeof x === 'undefined' ? this.x : x; | |
y = typeof y === 'undefined' ? this.y : y; | |
ctx.save(); | |
ctx.globalAlpha = this.opacity; | |
if (this.xOffset || this.yOffset) { | |
ctx.translate(this.xOffset, this.yOffset); | |
} | |
ctx.drawImage(this.canvas, x, y); | |
ctx.restore(); | |
return this; | |
}; | |
/** | |
* Clear the layer. | |
*/ | |
this.clear = function() { | |
this.context.clearRect(this.xOffset, this.yOffset, this.canvas.width, this.canvas.height); | |
return this; | |
}; | |
/** | |
* Scroll the Layer. | |
* | |
* @param {Number} x | |
* The horizontal distance the target has shifted. | |
* @param {Number} y | |
* The vertical distance the target has shifted. | |
* @param {Number} [p] | |
* The parallax factor. Defaults to {@link Layer#parallax this.parallax}. | |
*/ | |
this.scroll = function(x, y, p) { | |
p = p || this.parallax; | |
this.xOffset += -x*p; | |
this.yOffset += -y*p; | |
return this; | |
}; | |
/** | |
* Position the Layer's canvas over the primary canvas. | |
* | |
* This is an alternative to drawing the Layer directly onto the primary | |
* canvas. Since it is literally in front of the primary canvas, any other | |
* Layers that need to be drawn in front of this one must also be positioned | |
* over the primary canvas instead of drawn directly onto it. | |
* | |
* @param {HTMLElement} canvas | |
* The primary canvas over which to position the Layer. | |
* | |
* @return {HTMLElement} | |
* A jQuery representation of a div containing the Layer's canvas. | |
*/ | |
this.positionOverCanvas = function(canvas) { | |
if (typeof jQuery === 'undefined') { | |
if (window.console && console.error) { | |
console.error('Layer#positionOverCanvas() requires jQuery, but jQuery is not available.'); | |
} | |
return; | |
} | |
var $d = jQuery('<div></div>'); | |
var o = $(canvas).offset(); | |
$d.css({ | |
left: o.left, | |
pointerEvents: 'none', | |
position: 'absolute', | |
top: o.top, | |
}); | |
var $c = jQuery(this.canvas); | |
$c.css({ | |
backgroundColor: 'transparent', | |
margin: '0 auto', | |
overflow: 'hidden', | |
pointerEvents: 'none', | |
position: 'absolute', | |
'z-index': 50, | |
}); | |
$d.append($c); | |
jQuery('body').append($d); | |
return $d; | |
}; | |
/** | |
* Display this Layer's canvas in an overlay (for debugging purposes). | |
* | |
* Clicking the overlay will remove it. | |
* | |
* @return {HTMLElement} | |
* A jQuery representation of a div containing the Layer's canvas. | |
*/ | |
this.showCanvasOverlay = function() { | |
if (typeof jQuery === 'undefined') { | |
if (window.console && console.error) { | |
console.error('Layer#showCanvasOverlay() requires jQuery, but jQuery is not available.'); | |
} | |
return; | |
} | |
var $d = jQuery('<div></div>'); | |
$d.css({ | |
cursor: 'pointer', | |
display: 'block', | |
height: '100%', | |
left: 0, | |
position: 'absolute', | |
top: 0, | |
width: '100%', | |
}); | |
var $c = jQuery(this.canvas); | |
$c.css({ | |
border: '1px solid black', | |
display: 'block', | |
margin: '0 auto', | |
position: 'absolute', | |
'z-index': 100, | |
}).click(function() { | |
$d.remove(); | |
}); | |
$d.append($c); | |
jQuery('body').append($d); | |
$d.click(function(e) { | |
if (e.which != 3) { // Don't intercept right-click events | |
$d.remove(); | |
} | |
}); | |
return $d; | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment