Source: renderers/Canvas.js

/**
 * This is a simple abstraction of the canvas object,
 *   may be used to do some optimizations.
 *
 * @constructor
 */
Grape2D.Canvas = function(options) {
	options = options || {};
	/**
	 * Canvas DOM element.
	 *
	 * @type {!Element}
	 * @private
	 */
	this.canvas = document.createElement("Canvas");
	this.canvas.width = options.width || 300;
	this.canvas.height = options.height || 150;
	/**
	 * Half width of the canvas.
	 *
	 * @type {!number}
	 * @private
	 */
	this.halfWidth = this.canvas.width / 2;
	/**
	 * Half height of the canvas.
	 *
	 * @type {!number}
	 * @private
	 */
	this.halfHeight = this.canvas.height / 2;
	/**
	 * Context of the canvas.
	 *
	 * @type {!CanvasRenderingContext2D}
	 * @private
	 */
	this.context = this.canvas.getContext("2d");
};

Grape2D.Canvas.prototype = {
	/**
	 * Gets canvas width.
	 *
	 * @return {!number} Canvas width.
	 */
	getWidth: function() {
		return this.canvas.width;
	},
	/**
	 * Gets canvas half width.
	 *
	 * @return {!number} Canvas half width.
	 */
	getHalfWidth: function() {
		return this.halfWidth;
	},
	/**
	 * Sets canvas width.
	 *
	 * @param  {!number} width New canvas width.
	 */
	setWidth: function(width) {
		this.canvas.width = width;
		this.halfWidth = width / 2;
	},
	/**
	 * Gets canvas height.
	 *
	 * @return {!number} Canvas height.
	 */
	getHeight: function() {
		return this.canvas.height;
	},
	/**
	 * Gets canvas half height.
	 *
	 * @return {!number} Canvas half height.
	 */
	getHalfHeight: function() {
		return this.halfHeight;
	},
	/**
	 * Sets canvas height.
	 *
	 * @param  {!number} height New canvas height.
	 */
	setHeight: function(height) {
		this.canvas.height = height;
		this.halfHeight = height / 2;
	},
	// Canvas element
	/**
	 * @public
	 */
	toDataURL: function(type, args) {
		return this.canvas.toDataURL(type, args);
	},
	/**
	 * Gets canvas context.
	 *
	 * @return {!CanvasRenderingContext2D} Canvas context.
	 */
	getContext: function() {
		return this.context;
	},
	// 2D Context
	/**
	 * Saves the state of the canvas.
	 *
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	save: function() {
		this.context.save();
		return this;
	},
	/**
	 * Restores a saved state.
	 *
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	restore: function() {
		this.context.restore();
		return this;
	},
	// Transformations
	/**
	 * Scales the canvas. Not the DOM element. Equivalent
	 *   to apply a scale matrix.
	 *
	 * @param  {!number} x X scale.
	 * @param  {!number} y Y scale.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	scale: function(x, y) {
		this.context.scale(x, y);
		return this;
	},
	/**
	 * Rotates the canvas. Not the DOM element. Equivalent
	 *   to apply a rotation matrix.
	 *
	 * @param  {!number} angle Angle to rotate.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	rotate: function(angle) {
		this.context.rotate(angle);
		return this;
	},
	/**
	 * Translate the canvas. Not the DOM element. Equivalent
	 *   to apply a translation matrix.
	 *
	 * @param  {!number} x Translation in the X axis.
	 * @param  {!number} y Translation in the Y axis.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	translate: function(x, y) {
		this.context.translate(x, y);
		return this;
	},
	/**
	 * Sets a transformation matrix.
	 *
	 * @param  {!number} m11 Element.
	 * @param  {!number} m12 Element.
	 * @param  {!number} m21 Element.
	 * @param  {!number} m22 Element.
	 * @param  {!number} dx Element.
	 * @param  {!number} dy Element.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	transform: function(m11, m12, m21, m22, dx, dy) {
		this.context.transform(m11, m12, m21, m22, dx, dy);
		return this;
	},
	// Image drawing
	/**
	 * Draws an image to the canvas.
	 *
	 * @param {!(HTMLImageElement|HTMLCanvasElement|HTMLVideoElement)}
	 *   image Image to draw.
	 * @param {!number} dx Destination x
	 * @param {!number} dy Destination y
	 * @param {!number} dw Destination width
	 * @param {!number} dh Destination height
	 * @param {!number} sx Source x
	 * @param {!number} sy Source y
	 * @param {!number} sw Source width
	 * @param {!number} sh Source height
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	drawImage: function(image, sx, sy, sw, sh, dx, dy, dw, dh) {
		this.context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh);
		return this;
	},
	// Compositing
	/**
	 * Sets the global alpha property.
	 *
	 * @param  {!number} value New alpha value.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setGlobalAlpha: function(value) {
		this.context.globalAlpha = value;
		return this;
	},
	/**
	 * Performs a composition operation, according to a flag. The
	 *   available flags are:
	 *   <ul>
	 *   <li>source-over
	 *   <li>source-in
	 *   <li>source-out
	 *   <li>source-atop
	 *   <li>destination-over
	 *   <li>destination-in
	 *   <li>destination-out
	 *   <li>destination-atop
	 *   <li>lighter
	 *   <li>copy
	 *   <li>xor
	 *
	 * @param  {!string} flag An valid flag.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	globalCompositeOperation: function(flag) {
		this.context.globalCompositeOperation = flag;
		return this;
	},
	// Lines
	/**
	 * Sets the line width
	 *
	 * @param  {!number} value New line width value.s
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setLineWidth: function(value) {
		this.context.lineWidth = value;
		return this;
	},
	/**
	 * Sets the type of line cap. The available options are:
	 *   <ul>
	 *   <li>butt
	 *   <li>round
	 *   <li>square
	 *
	 * @param  {!string} value A valid line cap option.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setLineCap: function(value) {
		this.context.lineCap = value;
		return this;
	},
	/**
	 * Sets the line join. The available options are:
	 *   <ul>
	 *   <li>round
	 *   <li>bevel
	 *   <li>miter
	 *
	 * @param  {!string} value A valid line join option.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setLineJoin: function(value) {
		this.context.lineJoin = value;
		return this;
	},
	/**
	 * Sets the miter limit.
	 *
	 * @param  {!number} value Miter limit value.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setMiterLimit: function(value) {
		this.context.miterLimit = value;
		return this;
	},
	/** Colors **/
	/**
	 * Sets the stroke style.
	 *
	 * @param  {!string} value Stroke color. In a valid CSS3 format.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setStrokeStyle: function(value) {
		this.context.strokeStyle = value;
		return this;
	},
	/**
	 * Sets the fill style.
	 *
	 * @param  {!string} value Fill color. In a valid CSS3 format.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setFillStyle: function(value) {
		this.context.fillStyle = value;
		return this;
	},
	/**
	 * Sets the shadow offset in the x axis.
	 *
	 * @param  {!number} value Shadow offset, at the x axis
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setShadowOffsetX: function(value) {
		this.context.shadowOffsetX = value;
		return this;
	},
	/**
	 * Sets the shadow offset in the y axis.
	 *
	 * @param  {!number} value Shadow offset, at the y axis.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setShadowOffsetY: function(value) {
		this.context.shadowOffsetY = value;
		return this;
	},
	/**
	 * Sets the shadow blur value.
	 *
	 * @param  {!number} value Shadow blur.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setShadowBlur: function(value) {
		this.context.shadowBlur = value;
		return this;
	},
	/**
	 * Sets the shadow color.
	 *
	 * @param  {!string} value Shadow color in a valid CSS3 format.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setShadowColor: function(value) {
		this.context.shadowColor = value;
		return this;
	},
	/**
	 * Creates a line gradient in the canvas.
	 *
	 * @param  {!number} x0 Start x.
	 * @param  {!number} y0 Start y.
	 * @param  {!number} x1 End x.
	 * @param  {!number} y1 End y.
	 * @return {?CanvasGradient} Result gradient.
	 */
	createLinearGradient: function(x0, y0, x1, y1) {
		return this.context.createLinearGradient(x0, y0, x1, y1);
	},
	/**
	 * Creates a radial gradient.
	 *
	 * @param  {!number} x0 X.
	 * @param  {!number} y0 Y.
	 * @param  {!number} r0 Radius.
	 * @param  {!number} x1 X.
	 * @param  {!number} y1 Y.
	 * @param  {!number} r1 Radius.
	 * @return {?CanvasGradient} Result gradient.
	 */
	createRadialGradient: function(x0, y0, r0, x1, y1, r1) {
		return this.context.createRadialGradient(x0, y0, r0, x1, y1, r1);
	},
	/**
	 * Creates a pattern. There are 4 available options:
	 *   <ul>
	 *   <li>repeat
	 *   <li>repeat-x
	 *   <li>repeat-y
	 *   <li>no-repeat
	 *
	 * @param  {?(HTMLImageElement|HTMLCanvasElement)}
	 *   image Image
	 * @param  {!string} repetition Valid repetition.
	 * @return {?CanvasPattern} Result pattern.
	 */
	createPattern: function(image, repetition) {
		return this.context.createPattern(image, repetition);
	},
	// Paths
	/**
	 * Starts a path.
	 *
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	beginPath: function() {
		this.context.beginPath();
		return this;
	},
	/**
	 * Closes a path.
	 *
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	closePath: function() {
		this.context.closePath();
		return this;
	},
	/**
	 * Fills the canvas.
	 *
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	fill: function() {
		this.context.fill();
		return this;
	},
	/**
	 * Stroke the canvas.
	 *
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	stroke: function() {
		this.context.stroke();
		return this;
	},
	/**
	 * Clips the canvas
	 *
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	clip: function() {
		this.context.clip();
		return this;
	},
	/**
	 * Moves to a position to start a line/shape.
	 *
	 * @param  {!number} x X coordinate.
	 * @param  {!number} y Y coordinate.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	moveTo: function(x, y) {
		this.context.moveTo(x, y);
		return this;
	},
	/**
	 * Creates a line to a position.
	 *
	 * @param  {!number} x End x coordinate.
	 * @param  {!number} y End y coordinate.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	lineTo: function(x, y) {
		this.context.lineTo(x, y);
		return this;
	},
	/**
	 * Creates a quadratic curve.
	 *
	 * @param  {!number} cpx CPX.
	 * @param  {!number} cpy CPY
	 * @param  {!number} x X.
	 * @param  {!number} y Y.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	quadraticCurveTo: function(cpx, cpy, x, y) {
		this.context.quadraticCurveTo(cpx, cpy, x, y);
		return this;
	},
	/**
	 * Creates a bezier curve.
	 *
	 * @param  {!number} cp1x CP1X.
	 * @param  {!number} cp1y CP1Y.
	 * @param  {!number} cp2x CP2X.
	 * @param  {!number} cp2y CP2Y.
	 * @param  {!number} x X.
	 * @param  {!number} y Y.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	bezierCurveTo: function(cp1x, cp1y, cp2x, cp2y, x, y) {
		this.context.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
		return this;
	},
	/**
	 * Creates an arc to a position.
	 *
	 * @param  {!number} x1 Start x.
	 * @param  {!number} y1 Start y.
	 * @param  {!number} x2 End x.
	 * @param  {!number} y2 End y.
	 * @param  {!number} radius Radius of the arc.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	arcTo: function(x1, y1, x2, y2, radius) {
		this.context.arcTo(x1, y1, x2, y2, radius);
		return this;
	},
	/**
	 * Creates an arc.
	 *
	 * @param  {!number} x Center x.
	 * @param  {!number} y Center y.
	 * @param  {!number} radius Arc radius.
	 * @param  {!number=} startAngle Start angle.
	 * @param  {!number=} endAngle End angle.
	 * @param  {!boolean=} CCW True for counter clock wise.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	arc: function(x, y, radius, startAngle, endAngle, CCW) {
		this.context.arc(x, y, radius, startAngle || 0, endAngle || Grape2D.Math.PIx2, CCW || false);
		return this;
	},
	/**
	 * Creates a rectangle.
	 *
	 * @param  {!number} x X coordinate of the top left corner.
	 * @param  {!number} y Y coordinate of the top left corner.
	 * @param  {!number} w Width of the rectangle.
	 * @param  {!number} h Height of the rectangle.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	rect: function(x, y, w, h) {
		this.context.rect(x, y, w, h);
		return this;
	},
	/**
	 * Checks if the point is in the current path.
	 *
	 * @param  {!number} x X coordinate.
	 * @param  {!number} y Y coordinate.
	 * @return {!boolean} True if it's in the path.
	 */
	isPointInPath: function(x, y) {
		return this.context.isPointInPath(x, y);
	},
	// Text
	/**
	 * Sets the font type.
	 *
	 * @param  {!string} font New font.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setFont: function(font) {
		this.context.font = font;
		return this;
	},
	/**
	 * Set the text align. The available options are:
	 *   <ul>
	 *   <li>start
	 *   <li>end
	 *   <li>left
	 *   <li>right
	 *   <li>center
	 *
	 * @param  {!string} value A valid align option.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setTextAlign: function(value) {
		this.context.textAlign = value;
		return this;
	},
	/**
	 * Sets the baseline. The available options are:
	 *   <ul>
	 *   <li>top
	 *   <li>hanging
	 *   <li>middle
	 *   <li>alphabetic
	 *   <li>ideographic
	 *   <li>bottom
	 *
	 * @param  {!string} baseline A valid option.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	setTextBaseline: function(baseline) {
		this.context.textBaseline = baseline;
		return this;
	},
	/**
	 * Fills the text.
	 *
	 * @param  {!string} text Text to fill.
	 * @param  {!number} x X.
	 * @param  {!number} y Y.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	fillText: function(text, x, y) {
		this.context.fillText(text, x, y);
		return this;
	},
	/**
	 * Stroke text.
	 *
	 * @param  {!string} text Text to stroke.
	 * @param  {!number} x X.
	 * @param  {!number} y Y.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	strokeText: function(text, x, y) {
		this.context.strokeText(text, x, y);
		return this;
	},
	/**
	 * Measures a text.
	 *
	 * @param  {!string} text Text to measure.
	 * @return {?TextMetrics} Text metrics
	 */
	measureText: function(text) {
		return this.context.measureText(text);
	},
	// Rectangles
	/**
	 * Clears a rectangle.
	 *
	 * @param  {!number} x Start x.
	 * @param  {!number} y Start y.
	 * @param  {!number} w Width.
	 * @param  {!number} h Height.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	clearRect: function(x, y, w, h) {
		this.context.clearRect(x, y, w, h);
		return this;
	},
	/**
	 * Fills a rectangle.
	 *
	 * @param  {!number} x Start x.
	 * @param  {!number} y Start y.
	 * @param  {!number} w Width.
	 * @param  {!number} h Height.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	fillRect: function(x, y, w, h) {
		this.context.fillRect(x, y, w, h);
		return this;
	},
	/**
	 * Strokes a rectangle.
	 *
	 * @param  {!number} x Start x.
	 * @param  {!number} y Start y.
	 * @param  {!number} w Width.
	 * @param  {!number} h Height.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	strokeRect: function(x, y, w, h) {
		this.context.strokeRect(x, y, w, h);
		return this;
	},
	/** Pixel manipulation **/
	/**
	 * Creates an image data.
	 *
	 * @param  {!number} sw Source width.
	 * @param  {!number} sh Source height.
	 * @return {?ImageData} Image data.
	 */
	createImageData: function(sw, sh) {
		return this.context.createImageData(sw, sh);
	},
	/**
	 * Gets canvas data as an image.
	 *
	 * @param  {!number} sx Source x.
	 * @param  {!number} sy Source y.
	 * @param  {!number} sw Source width.
	 * @param  {!number} sh Source height.
	 * @return {?ImageData} Image data.
	 */
	getImageData: function(sx, sy, sw, sh) {
		return this.context.getImageData(sx, sy, sw, sh);
	},
	/**
	 * Puts image data into the canvas.
	 *
	 * @param  {!ImageData} imageData Image data.
	 * @param  {!number} dx Destination x.
	 * @param  {!number} dy Destination y.
	 * @param  {!number} dirtyX Dirty x.
	 * @param  {!number} dirtyY Dirty y.
	 * @param  {!number} dirtyWidth Dirty width.
	 * @param  {!number} dirtyHeight Dirty height.
	 * @return {?Grape2D.Canvas} This canvas.
	 */
	putImageData: function(imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) {
		this.context.putImageData(imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight);
		return this;
	},
	/**
	 * Resizes the canvas.
	 *
	 * @param  {!number} w New width.
	 * @param  {!number} h New height.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	resize: function(w, h) {
		this.setWidth(w);
		this.setHeight(h);
		return this;
	},
	/**
	 * Appends canvas to a DOM element.
	 *
	 * @param  {!Element} on Element to append to.
	 * @return {!Grape2D.Canvas} This canvas.
	 */
	appendOn: function(on) {
		on.appendChild(this.canvas);
		return this;
	},
	/**
	 * Clears the canvas.
	 */
	clear: function() {
		this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
	}
};