UNPKG

cdf

Version:

A library for creating oldschool demo-like animations with JavaScript

263 lines (241 loc) 8.55 kB
var utils = require('utils'); var defaults = require('defaults'); var total_canvas = 0; var createCanvasElement = function(){ var canvas = document.createElement('canvas'); canvas.style.className = 'cdf_canvas cdf_canvas'+total_canvas++; return canvas; } /** * Constructor for cdf canvas element * @param width Canvas width in pixels * @param height Canvas height in pixels * @param {Node|0} parent Parent element, to which the canvas will be assigned. If nothing is passed - the canvas will * be "virtual" - it will exist only in memory. Be careful creating multiple canvas - it may eat all the memory quickly. * @constructor */ var Canvas = function (width, height, parent){ if(width.length){ parent = height; height = width[1]; width = width[1]; } this.element = createCanvasElement(); this.ctx = this.element.getContext('2d'); this.style = this.element.style; this .attach(parent) .size(width,height) .handle(0,0); } Canvas.prototype = { /** * Attaches the canvas to DOM element * @param {Node} element * @returns {Canvas} */ attach: function(element){ if(element === 0) element = document.body; if(element === undefined || element === false) return this; element.appendChild(this.element); this.parent = element; return this; }, /** * Sets canvas size. Note that this will clear the canvas. * @param width Width in pixels * @param height Height in pixels * @returns {Canvas} Returns itself */ size: function(width, height){ if(width && width.length){ height = width[1]; width = width[0]; } this.width = this.w = width; this.height = this.h = height; this.cx = width/2; this.cy = width/2; this.center = [this.cx, this.cy]; this.ss = width>height?height:width; this.element.setAttribute('width', width); this.element.setAttribute('height', height); return this.trigger('resize',[width, height]); }, /** * Sets canvas handle. Canvas are rotated around the handle and are placed at this candle on other canvas. If you * Sets canvas handle. Canvas are rotated around the handle and are placed at this candle on other canvas. If you * pass no parameters the handle will be centered; * @param x Coordinate in pixels * @param y Coordinate in pixels * @returns {Canvas} */ handle: function(xyPair){ this.__handle = utils.coordPair(xyPair, this.center); return this; }, /** * Clears canvas transparent. Uses clearRect * @return {Canvas} */ clear: function () { this.ctx.clearRect(0, 0, this.w, this.h); return this; }, /** * Fills canvas with fillStyle. Uses fillRect. * @param fillStyle * @return {Canvas} */ fill: function (fillStyle) { this.ctx.fillStyle = fillStyle; this.ctx.fillRect(0, 0, this.w, this.h); return this; }, /** * Draws a polygon on canvas. * @param {ArrayLike|Points} dots An array of arrays of coordinates, like [[x,y], [x,y]]. * You can also use Points class. * @param fillStyle Style to fill the polygon * @param lineWidth Width of the stroke * @param strokeStyle Style of the stroke * @param closePath Set true to close the path * @param {string} lineCap A line cap. "butt", "round" or "square". * @return {Canvas} */ poly: function(dots,fillStyle,lineWidth,strokeStyle,closePath,lineCap){ if(lineCap)this.ctx.lineCap=lineCap; this.ctx.beginPath(); this.ctx.moveTo(dots[0][0], dots[0][1]); for(var i = 1; i<dots.length; i++){ this.ctx.lineTo(dots[i][0], dots[i][1]); } utils.strokeFill(this,fillStyle,lineWidth,strokeStyle,closePath); return this; }, /** * Just a shorthand for ctx.fillRect with option to set a color. * @param xyPair Pair of coordinates, as array * @param whPair Pair of width and height, as array * @param color fillStyle for rectangle * @return {Canvas} */ rect: function(xyPair, whPair, color){ this.ctx.fillStyle = color; xyPair = utils.coordPair(xyPair); whPair = utils.coordPair(whPair); this.ctx.fillRect(xyPair[0], xyPair[1], whPair[0], whPair[1]); return this; }, /** * A shorthand to draw a line through two coulpes of coordinates * @param {Array} p1 * @param {Array} p2 * @param strokeSize * @param strokeStyle * @return {*|Canvas} */ line: function (p1, p2, strokeSize, strokeStyle) { return this.poly([utils.coordPair(p1),utils.coordPair(p2)],undefined,strokeSize,strokeStyle); }, /** * Just a shorthand for ctx.arc with stroke and fill. The arc will not be closed. * @param {Array} xyPair * @param {number} r Radius * @param fillStyle Fill style * @param lineWidth Line width * @param strokeStyle Stroke style * @param sa Starting angle * @param ea Ending angle * @return {Canvas} */ circle: function(xyPair,r,fillStyle,lineWidth,strokeStyle,sa,ea){ xyPair = utils.coordPair(xyPair); this.ctx.beginPath(); this.ctx.arc(xyPair[0],xyPair[1],r,sa||0,ea===undefined?360:+ea); utils.strokeFill(this,fillStyle,lineWidth,strokeStyle,false); return this; }, /** * Shorthand to place a point at coordinates. The point is actually a fillRect. Not the fastest option: if you need * thousands of points you probably should use Buffer class. * @param {ArrayLike} xyPair An array of [x,y] * @param color fillStyle for the point * @param width Width of a dot. Default will be just a point of 1 px at coordinates. * @return {*} */ plot: function (xyPair, color, width) { if(color)this.ctx.fillStyle = color; var wc = width === 1? 0 : width/2; this.ctx.fillRect(xyPair[0]-wc, xyPair[1]-wc, width, width); return this; }, /** * Converts canvas to base64 url. toDataUrl with image/png is used * @param quality conversion quality. Default is 0.92 * @param type type. Default is image/png * @return {*} */ toBase64: function(quality, type){ return this.element.toDataURL(type || 'image/png',quality || 0.92); }, /** * Draws canvas onto another canvas at handle * @param {HTMLCanvasElement|Canvas} dest * @param {Array} [pos] * @param {Number} [rot] * @param {Array} [scale] * @param {Number} [alpha] * @param {Array} [partPos] Position of the canvas to start drawing from * @param {Array} [partSize] Width of the canvas area to be drawn * // TODO: Make reasonable handling of handle on this * @return {Canvas} */ draw: function(dest, pos, rot,scale,alpha, partPos, partSize){ if(dest.ctx)dest = dest.ctx; dest.save(); pos = utils.coordPair(pos); partPos = utils.coordPair(partPos); partSize = utils.coordPair(partSize,[this.w-partPos[0], this.h-partPos[1]]); if(alpha!==undefined) dest.globalAlpha = alpha; dest.translate(pos[0],pos[1]); if(rot!==undefined)dest.rotate(rot*utils.DEG_TO_RAD); scale = utils.coordPair(scale, [1,1]); dest.scale(scale[0],scale[1]); dest.translate(-this.__handle[0], -this.__handle[1]); dest.drawImage(this.element, partPos[0], partPos[1], partSize[0], partSize[1],0,0,partSize[0], partSize[1]); dest.restore(); return this; }, /** * Draws text on canvas. The text does not have word wrapping. * @param {string} text Text to draw * @param {Array} xyPair Coordinates where to draw text. Text is drawn from upper left corner by default. * @param fillStyle Fillstyle for text. Or color. * @param {string} font Font for text. Default is '12px sans-serif' * @param {string} align Text align. Values are: start,end,left,right,center,justify,match-parent,justify-all * @param {string} baseline Text baseline. Values are: alphabetic,top,hanging,middle,ideographic,bottom * @return {Canvas} */ text: function (text, xyPair, fillStyle, font, align, baseline) { xyPair = xyPair===undefined?defaults.fontPos:utils.coordPair(xyPair); if(fillStyle!==undefined) this.ctx.fillStyle = fillStyle; this.ctx.textAlign = align || defaults.fontAlign; this.ctx.textBaseline = baseline || defaults.fontBaseline; this.ctx.font = font || defaults.font; this.ctx.fillText(text, xyPair[0], xyPair[1]); return this; }, /** * Measure text using measuretext. * @param text Text to measure * @param font Font * @return {*} */ textWidth: function(text,font){ this.ctx.font = font || defaults.font; return this.ctx.measureText(text); } }; utils.eventer(Canvas.prototype); module.exports = Canvas;