UNPKG

canvasimo

Version:

An HTML5 canvas drawing library, with 150+ useful methods, jQuery-like fluent interface, and cross-browser compatibility enhancements.

1,271 lines (1,270 loc) 70.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // tslint:disable-next-line:no-var-requires var VERSION = require('../package.json').version; var constants_1 = require("./constants"); var logger_1 = require("./logger"); var utils_1 = require("./utils"); var unsupportedMethodErrors = []; var logUnsupportedMethodError = function (method) { if (unsupportedMethodErrors.indexOf(method) < 0) { unsupportedMethodErrors.push(method); logger_1.default.warn(method + " is not supported by this browser"); } }; var Canvasimo = /** @class */ (function () { function Canvasimo(element) { var _this = this; this.ctxType = constants_1.CONTEXT_TYPE; this.density = constants_1.DEFAULT_DENSITY; /** * @group Canvas element * @description A collection of methods for getting and setting various properties of the canvas element. */ /** * Get the canvas element. * @alias getElement */ this.getCanvas = function () { return _this.element; }; this.getElement = function () { return _this.getCanvas(); }; /** * Set the canvas pixel density. */ this.setDensity = function (density) { if (_this.density !== density) { var _a = _this.getSize(), prevWidth = _a.width, prevHeight = _a.height; _this.saveContextValues(); _this.density = density; _this.element.width = prevWidth * density; _this.element.height = prevHeight * density; _this.restoreContextValues(); } return _this; }; /** * Get the canvas pixel density. */ this.getDensity = function () { return _this.density; }; /** * Set the canvas dimensions. */ this.setSize = function (width, height) { _this.saveContextValues(); if (typeof width === 'object') { _this.element.width = width.width * _this.density; _this.element.height = width.height * _this.density; } else if (typeof height === 'number') { _this.element.width = width * _this.density; _this.element.height = height * _this.density; } _this.restoreContextValues(); return _this; }; /** * Get the canvas dimensions. */ this.getSize = function () { return ({ width: _this.element.width / _this.density, height: _this.element.height / _this.density, }); }; /** * Set the canvas width. */ this.setWidth = function (width) { _this.saveContextValues(); _this.element.width = width * _this.density; _this.restoreContextValues(); return _this; }; /** * Get the canvas width. */ this.getWidth = function () { return _this.element.width / _this.density; }; /** * Set the canvas height. */ this.setHeight = function (height) { _this.saveContextValues(); _this.element.height = height * _this.density; _this.restoreContextValues(); return _this; }; /** * Get the canvas height. */ this.getHeight = function () { return _this.element.height / _this.density; }; /** * Get the canvas size & position on screen. */ this.getBoundingClientRect = function () { return _this.element.getBoundingClientRect(); }; /** * @group Context * @description 'A collection of methods for retrieving a canvas context or information about the context. */ /** * Get the standard canvas context (used for drawing). */ this.getContext = function (type, contextAttributes) { return _this.element.getContext(type, contextAttributes); }; /** * Get canvas context used by Canvasimo (2d). */ this.getCurrentContext = function () { return _this.ctx; }; /** * Get the context type used by Canvasimo ('2d', 'webgl', etc). */ this.getCurrentContextType = function () { return _this.ctxType; }; /** * Get the context attributes used. */ this.getContextAttributes = function () { if (typeof _this.ctx.getContextAttributes !== 'function') { logUnsupportedMethodError('getContextAttributes'); return null; } return _this.ctx.getContextAttributes(); }; /** * @group Solid Shapes * @description A collection of methods for plotting or drawing solid shapes - * those that create a new shape when invoked, and are self closing. */ // plotRect', /** * Plot a rectangle that can then have a fill or stroke applied to it. * @alias rect */ this.plotRect = function (x, y, width, height) { return _this.rect(x, y, width, height); }; this.rect = function (x, y, width, height) { _this.ctx.rect(x * _this.density, y * _this.density, width * _this.density, height * _this.density); return _this; }; /** * Plot a rectangle and apply a stroke to it. */ this.strokeRect = function (x, y, width, height, color) { if (typeof color !== 'undefined') { _this.setStroke(color); } _this.ctx.strokeRect(x * _this.density, y * _this.density, width * _this.density, height * _this.density); return _this; }; /** * Plot a rectangle and apply a fill to it. */ this.fillRect = function (x, y, width, height, color) { if (typeof color !== 'undefined') { _this.setFill(color); } _this.ctx.fillRect(x * _this.density, y * _this.density, width * _this.density, height * _this.density); return _this; }; /** * Plot a rounded rectangle that can then have a fill or stroke applied to it. */ this.plotRoundedRect = function (x, y, width, height, radius) { var minRadius = Math.min(width / 2, height / 2, radius); return _this .beginPath() .moveTo(x + minRadius, y) .lineTo(x + width - minRadius, y) .arcTo(x + width, y, x + width, y + minRadius, minRadius) .lineTo(x + width, y + height - minRadius) .arcTo(x + width, y + height, x + width - minRadius, y + height, minRadius) .lineTo(x + minRadius, y + height) .arcTo(x, y + height, x, y + height - minRadius, minRadius) .lineTo(x, y + minRadius) .arcTo(x, y, x + minRadius, y, minRadius) .closePath(); }; /** * Plot a rounded rectangle and apply a stroke to it. */ this.strokeRoundedRect = function (x, y, width, height, radius, color) { return _this .plotRoundedRect(x, y, width, height, radius) .stroke(color); }; /** * Plot a rounded rectangle and apply a fill to it. */ this.fillRoundedRect = function (x, y, width, height, radius, color) { return _this .plotRoundedRect(x, y, width, height, radius) .fill(color); }; /** * Plot a circle that can then have a stroke or fill applied to it. */ this.plotCircle = function (x, y, radius, anticlockwise) { return _this .beginPath() .plotArc(x, y, radius, 0, Math.PI * 2, anticlockwise) .closePath(); }; /** * Plot a circle and apply a stroke to it. */ this.strokeCircle = function (x, y, radius, anticlockwise, color) { return _this .plotCircle(x, y, radius, anticlockwise) .stroke(color); }; /** * Plot a circle and apply a fill to it. */ this.fillCircle = function (x, y, radius, anticlockwise, color) { return _this .plotCircle(x, y, radius, anticlockwise) .fill(color); }; /** * Plot a polygon that can then have a stroke or fill applied to it. */ this.plotPoly = function (x, y, radius, sides, anticlockwise) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } var direction = anticlockwise ? -1 : 1; var beforeEnd = function (i) { return anticlockwise ? i > -sides : i < sides; }; _this .beginPath() .moveTo(x + radius, y); for (var i = 0; beforeEnd(i); i += direction) { var angle = Math.PI * 2 / sides * i; _this.lineTo(x + radius * Math.cos(angle), y + radius * Math.sin(angle)); } return _this.closePath(); }; /** * Plot a polygon and apply a stoke to it. */ this.strokePoly = function (x, y, radius, sides, anticlockwise, color) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } return _this .plotPoly(x, y, radius, sides, anticlockwise) .stroke(color); }; /** * Plot a polygon and apply a fill to it. */ this.fillPoly = function (x, y, radius, sides, anticlockwise, color) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } return _this .plotPoly(x, y, radius, sides, anticlockwise) .fill(color); }; /** * Plot a star that can then have a stroke or fill applied to it. */ this.plotStar = function (x, y, radius1, sides, anticlockwise) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } else if (sides === 3 || sides === 4) { return _this.plotPoly(x, y, radius1, sides); } sides = sides * 2; var direction = anticlockwise ? -1 : 1; var offset = Math.PI * 2 / sides; var cross = Math.cos(offset * 2) * radius1; var radius2 = cross / Math.cos(offset); var beforeEnd = function (i) { return anticlockwise ? i > -sides : i < sides; }; _this .beginPath() .moveTo(x + radius1, y); for (var i = 0; beforeEnd(i); i += direction) { var angle = offset * i; var radius = i % 2 ? radius2 : radius1; _this.lineTo(x + radius * Math.cos(angle), y + radius * Math.sin(angle)); } return _this.closePath(); }; /** * Plot a star and apply a stoke to it. */ this.strokeStar = function (x, y, radius1, sides, anticlockwise, color) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } return _this .plotStar(x, y, radius1, sides, anticlockwise) .stroke(color); }; /** * Plot a star and apply a fill to it. */ this.fillStar = function (x, y, radius1, sides, anticlockwise, color) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } return _this .plotStar(x, y, radius1, sides, anticlockwise) .fill(color); }; /** * Plot a burst that can then have a stroke or fill applied to it. */ this.plotBurst = function (x, y, radius1, radius2, sides, anticlockwise) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } sides = sides * 2; var direction = anticlockwise ? -1 : 1; var offset = Math.PI * 2 / sides; var beforeEnd = function (i) { return anticlockwise ? i > -sides : i < sides; }; _this .beginPath() .moveTo(x + radius1, y); for (var i = 0; beforeEnd(i); i += direction) { var angle = offset * i; var radius = i % 2 ? radius2 : radius1; _this.lineTo(x + radius * Math.cos(angle), y + radius * Math.sin(angle)); } return _this .closePath(); }; /** * Plot a burst and apply a stoke to it. */ this.strokeBurst = function (x, y, radius1, radius2, sides, anticlockwise, color) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } return _this .plotBurst(x, y, radius1, radius2, sides, anticlockwise) .stroke(color); }; /** * Plot a burst and apply a fill to it. */ this.fillBurst = function (x, y, radius1, radius2, sides, anticlockwise, color) { sides = Math.round(sides); if (!sides || sides < 3) { return _this; } return _this .plotBurst(x, y, radius1, radius2, sides, anticlockwise) .fill(color); }; /** * Plot a single pixel that can then have a stroke or fill applied to it. */ this.plotPixel = function (x, y) { return _this .plotRect(x, y, 1, 1); }; /** * Plot a single pixel and apply a stroke to it. */ this.strokePixel = function (x, y, color) { return _this .strokeRect(x, y, 1, 1, color); }; /** * Plot a single pixel and apply a fill to it. */ this.fillPixel = function (x, y, color) { return _this .fillRect(x, y, 1, 1, color); }; /** * Plot a closed path that can then have a stroke or fill applied to it. */ this.plotClosedPath = function (points) { return _this .beginPath() .plotPath(points) .closePath(); }; /** * Plot a closed path and apply a stroke to it. */ this.strokeClosedPath = function (points, color) { return _this .plotClosedPath(points) .stroke(color); }; /** * Plot a closed path and apply a fill to it. */ this.fillClosedPath = function (points, color) { return _this .plotClosedPath(points) .fill(color); }; /** * @group Open Shapes * @description A collection of methods for plotting or drawing open shapes - * those that create a new shape when invoked, but are not self closing. */ /** * Plot a line that can then have a stroke or fill applied to it. */ this.plotLine = function (x1, y1, x2, y2) { return _this .moveTo(x1, y1) .lineTo(x2, y2); }; /** * Plot a line and apply a stroke to it. */ this.strokeLine = function (x1, y1, x2, y2, color) { return _this .plotLine(x1, y1, x2, y2) .stroke(color); }; /** * Plot a line, by length & angle, that can then have a stroke or fill applied to it. */ this.plotLength = function (x1, y1, length, angle) { var x2 = x1 + length * Math.cos(angle); var y2 = y1 + length * Math.sin(angle); return _this .moveTo(x1, y1) .lineTo(x2, y2); }; /** * Plot a line, by length & angle, and apply a stroke to it. */ this.strokeLength = function (x1, y1, length, angle, color) { return _this .plotLength(x1, y1, length, angle) .stroke(color); }; /** * Plot a path, that is not self closing, that can have a stroke or fill applied to it. */ this.plotPath = function (points) { utils_1.forPoints(points, function (x, y, i) { if (i === 0) { _this.moveTo(x, y); } else { _this.lineTo(x, y); } }); return _this; }; /** * Plot a path, that is not self closing, and apply a stroke to it. */ this.strokePath = function (points, color) { return _this .plotPath(points) .stroke(color); }; /** * Plot a path, that is not self closing, and apply a fill to it. */ this.fillPath = function (points, color) { return _this .plotPath(points) .fill(color); }; /** * @group Paths * @description A collection of methods for plotting or drawing paths - * shapes that can be connected to create more complex shapes. */ /** * Plot an arc that can have a stroke or fill applied to it. * @alias arc */ this.plotArc = function (x, y, radius, startAngle, endAngle, anticlockwise) { return _this.arc(x, y, radius, startAngle, endAngle, anticlockwise); }; this.arc = function (x, y, radius, startAngle, endAngle, anticlockwise) { _this.ctx.arc(x * _this.density, y * _this.density, radius * _this.density, startAngle, endAngle, anticlockwise || false); return _this; }; /** * Plot an arc and apply a stroke to it. */ this.strokeArc = function (x, y, radius, startAngle, endAngle, anticlockwise, color) { return _this .plotArc(x, y, radius, startAngle, endAngle, anticlockwise) .stroke(color); }; /** * Plot an arc and apply a fill to it. */ this.fillArc = function (x, y, radius, startAngle, endAngle, anticlockwise, color) { return _this .plotArc(x, y, radius, startAngle, endAngle, anticlockwise) .fill(color); }; /** * Plot an ellipse that can then have a stroke or fill applied to it. * @alias ellipse */ this.plotEllipse = function (x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise) { return _this.ellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise); }; this.ellipse = function (x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise) { // tslint:disable-next-line:strict-type-predicates if (typeof _this.ctx.ellipse === 'function') { _this.ctx.ellipse(x * _this.density, y * _this.density, radiusX * _this.density, radiusY * _this.density, rotation, startAngle, endAngle, anticlockwise || false); return _this; } return _this .save() .translate(x, y) .rotate(rotation) .scale(1, radiusY / radiusX) .plotArc(0, 0, radiusX, startAngle, endAngle, anticlockwise) .restore(); }; /** * Plot an ellipse and apply a stroke to it. */ this.strokeEllipse = function (x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise, color) { return _this .plotEllipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise) .stroke(color); }; /** * Plot an ellipse and apply a fill to it. */ this.fillEllipse = function (x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise, color) { return _this .plotEllipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, anticlockwise) .fill(color); }; /** * @group Text * @description A collection of methods for drawing text, * and getting and setting properties related to text rendering. */ /** * Draw a text with a stroke. */ this.strokeText = function (text, x, y, maxWidth, color) { if (typeof color !== 'undefined') { _this.setStroke(color); } if (typeof maxWidth !== 'number') { _this.ctx.strokeText(text, x * _this.density, y * _this.density); } else { _this.ctx.strokeText(text, x * _this.density, y * _this.density, maxWidth * _this.density); } return _this; }; /** * Draw a text with a fill. */ this.fillText = function (text, x, y, maxWidth, color) { if (typeof color !== 'undefined') { _this.setFill(color); } // If max width is not a number (e.g. undefined) then iOS does not draw anything if (typeof maxWidth !== 'number') { _this.ctx.fillText(text, x * _this.density, y * _this.density); } else { _this.ctx.fillText(text, x * _this.density, y * _this.density, maxWidth * _this.density); } return _this; }; /** * Draw text with a stroke, wrapped at newlines and automatically wrapped if the text exceeds the maxWidth. * If no maxWidth is specified text will only wrap at newlines (wordBreak is ignore). * Words will not break by default (normal) and therefore may overflow. * break-all will break words wherever possible, and break-word will only break words if there is not enough room. * The lineHeight parameter is a multiplier for the font size, and defaults to 1. */ this.strokeTextMultiline = function (text, x, y, maxWidth, wordBreak, lineHeight, color) { return _this.textMultiline(_this.strokeText, text, x, y, maxWidth, wordBreak, lineHeight, color); }; /** * Draw text with a fill, wrapped at newlines and automatically wrapped if the text exceeds the maxWidth. * If no maxWidth is specified text will only wrap at newlines (wordBreak is ignore). * Words will not break by default (normal) and therefore may overflow. * break-all will break words wherever possible, and break-word will only break words if there is not enough room. * The lineHeight parameter is a multiplier for the font size, and defaults to 1. */ this.fillTextMultiline = function (text, x, y, maxWidth, wordBreak, lineHeight, color) { return _this.textMultiline(_this.fillText, text, x, y, maxWidth, wordBreak, lineHeight, color); }; /** * Get information about the size text will be drawn. * @alias measureText */ this.getTextSize = function (text) { return _this.measureText(text); }; this.measureText = function (text) { var metrics = _this.ctx.measureText(text); return { width: (metrics.width || 0) / _this.density, }; }; /** * Set the horizontal text alignment. */ this.setTextAlign = function (value) { return _this.setCanvasProperty('textAlign', value); }; /** * Get the horizontal text alignment. */ this.getTextAlign = function () { return _this.getCanvasProperty('textAlign'); }; /** * Set the vertical text alignment. */ this.setTextBaseline = function (value) { return _this.setCanvasProperty('textBaseline', value); }; /** * Get the vertical text alignment. */ this.getTextBaseline = function () { return _this.getCanvasProperty('textBaseline'); }; /** * @group Fonts * @description A collection of methods for getting and setting font styles and variations. */ /** * Set the font to use. */ this.setFont = function (font) { _this.ctx.font = utils_1.formatFont(font, _this.density, false); return _this; }; /** * Get the font that is being used. * This returns the exact CanvasRenderingContext2D.font string. */ this.getFont = function () { return utils_1.formatFont(_this.ctx.font, _this.density, true); }; /** * Set the font family to use. */ this.setFontFamily = function (family) { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return _this.setFont(''); } parts[4] = family || constants_1.DEFAULT_FONT_PARTS[4]; _this.ctx.font = utils_1.formatFont(parts.join(' '), _this.density, false); return _this; }; /** * Get the font that is being used. */ this.getFontFamily = function () { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return null; } return parts[4]; }; /** * Set the font size to use. */ this.setFontSize = function (size) { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return _this.setFont(''); } parts[3] = (typeof size === 'number' ? size + 'px' : size) || constants_1.DEFAULT_FONT_PARTS[3]; _this.ctx.font = utils_1.formatFont(parts.join(' '), _this.density, false); return _this; }; /** * Get the font size that is being used. * Returns null if using a special font e.g. caption, icon, menu. */ this.getFontSize = function () { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return null; } return parseFloat(parts[3]); }; /** * Set the font style to use. */ this.setFontStyle = function (style) { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return _this.setFont(''); } parts[0] = style || constants_1.DEFAULT_FONT_PARTS[0]; _this.ctx.font = utils_1.formatFont(parts.join(' '), _this.density, false); return _this; }; /** * Get the font style that is being used. * Returns null if using a special font e.g. caption, icon, menu. */ this.getFontStyle = function () { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return null; } return parts[0]; }; /** * Set the font variant to use. */ this.setFontVariant = function (variant) { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return _this.setFont(''); } parts[1] = variant || constants_1.DEFAULT_FONT_PARTS[1]; _this.ctx.font = utils_1.formatFont(parts.join(' '), _this.density, false); return _this; }; /** * Get the font variant that is being used. * Returns null if using a special font e.g. caption, icon, menu. */ this.getFontVariant = function () { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return null; } return parts[1]; }; /** * Set the font weight to use. */ this.setFontWeight = function (weight) { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return _this.setFont(''); } parts[2] = weight.toString() || constants_1.DEFAULT_FONT_PARTS[2]; _this.ctx.font = utils_1.formatFont(parts.join(' '), _this.density, false); return _this; }; /** * Get the font weight that is being used. * Returns null if using a special font e.g. caption, icon, menu. */ this.getFontWeight = function () { var parts = utils_1.getFontParts(_this.ctx.font, _this.density, true); if (parts.length < 5) { return null; } return parts[2]; }; /** * @group Stroke Styles * @description A collection of methods for getting and setting stroke styles, * and applying strokes to existing shapes. */ /** * Apply a stroke to the current shape. */ this.stroke = function (color, path) { if (typeof color === 'string') { _this.setStroke(color); // tslint:disable-next-line:strict-type-predicates if (path && typeof path === 'object') { _this.ctx.stroke(path); } else { _this.ctx.stroke(); } // tslint:disable-next-line:strict-type-predicates } else if (color && typeof color === 'object') { _this.ctx.stroke(color); // tslint:disable-next-line:strict-type-predicates } else if (path && typeof path === 'object') { _this.ctx.stroke(path); } else { _this.ctx.stroke(); } return _this; }; /** * Set the stroke style to use. * @alias setStrokeStyle */ this.setStroke = function (value) { return _this.setStrokeStyle(value); }; this.setStrokeStyle = function (value) { return _this.setCanvasProperty('strokeStyle', value); }; /** * Get the stroke style that is being used. * @alias getStrokeStyle */ this.getStroke = function () { return _this.getStrokeStyle(); }; this.getStrokeStyle = function () { return _this.getCanvasProperty('strokeStyle'); }; /** * Set the stroke cap to use. * @alias setLineCap */ this.setStrokeCap = function (value) { return _this.setLineCap(value); }; this.setLineCap = function (value) { return _this.setCanvasProperty('lineCap', value); }; /** * Get the stroke cap that is being used. * @alias getLineCap */ this.getStrokeCap = function () { return _this.getLineCap(); }; this.getLineCap = function () { return _this.getCanvasProperty('lineCap'); }; /** * Set the stroke dash to use. * @alias setLineDash */ this.setStrokeDash = function (segments) { return _this.setLineDash(segments); }; this.setLineDash = function (segments) { // tslint:disable-next-line:strict-type-predicates if (typeof _this.ctx.setLineDash !== 'function') { logUnsupportedMethodError('setLineDash'); return _this; } _this.ctx.setLineDash(segments.map(function (segment) { return segment * _this.density; })); return _this; }; /** * Get the stroke dash that is being used. * @alias getLineDash */ this.getStrokeDash = function () { return _this.getLineDash(); }; this.getLineDash = function () { // tslint:disable-next-line:strict-type-predicates if (typeof _this.ctx.getLineDash !== 'function') { logUnsupportedMethodError('getLineDash'); return []; } return (_this.ctx.getLineDash() || []).map(function (value) { return value / _this.density; }); }; /** * Set the stroke dash offset to use. * @alias setLineDashOffset */ this.setStrokeDashOffset = function (value) { return _this.setLineDashOffset(value); }; this.setLineDashOffset = function (value) { return _this.setCanvasProperty('lineDashOffset', value * _this.density); }; /** * Get the stroke dash offset that is being used. * @alias getLineDashOffset */ this.getStrokeDashOffset = function () { return _this.getLineDashOffset(); }; this.getLineDashOffset = function () { return _this.getCanvasProperty('lineDashOffset') / _this.density; }; /** * Set the stroke join to use. * @alias setLineJoin */ this.setStrokeJoin = function (value) { return _this.setLineJoin(value); }; this.setLineJoin = function (value) { return _this.setCanvasProperty('lineJoin', value); }; /** * Get the stroke join that is being used. * @alias getLineJoin */ this.getStrokeJoin = function () { return _this.getLineJoin(); }; this.getLineJoin = function () { return _this.getCanvasProperty('lineJoin'); }; /** * Set the stroke width to use. * @alias setLineWidth */ this.setStrokeWidth = function (value) { return _this.setLineWidth(value); }; this.setLineWidth = function (value) { return _this.setCanvasProperty('lineWidth', value * _this.density); }; /** * Get the stroke width that is being used. * @alias getLineWidth */ this.getStrokeWidth = function () { return _this.getLineWidth(); }; this.getLineWidth = function () { return _this.getCanvasProperty('lineWidth') / _this.density; }; /** * Set the miter limit to use. */ this.setMiterLimit = function (value) { return _this.setCanvasProperty('miterLimit', value * _this.density); }; /** * Get the miter limit that is being used. */ this.getMiterLimit = function () { return _this.getCanvasProperty('miterLimit') / _this.density; }; /** * @group Fill styles * @description A collection of methods for getting and setting fill styles, * and applying fills to existing shapes. */ /** * Apply a fill to the current shape. */ this.fill = function (color, fillRule) { if (utils_1.isFillRule(color)) { _this.ctx.fill(color); } else if (typeof color === 'string') { _this.setFill(color); if (fillRule) { _this.ctx.fill(fillRule); } else { _this.ctx.fill(); } } else { _this.ctx.fill(fillRule); } return _this; }; /** * Apply a fill to the entire canvas area. */ this.fillCanvas = function (color) { return _this .resetTransform() .fillRect(0, 0, _this.getWidth(), _this.getHeight(), color); }; /** * Clear the entire canvas area */ this.clearCanvas = function () { return _this.setWidth(_this.getWidth()); }; /** * Clear a rectangular area of the canvas. */ this.clearRect = function (x, y, width, height) { _this.ctx.clearRect(x * _this.density, y * _this.density, width * _this.density, height * _this.density); return _this; }; /** * Set the fill to use. * @alias setFillStyle */ this.setFill = function (value) { return _this.setFillStyle(value); }; this.setFillStyle = function (value) { return _this.setCanvasProperty('fillStyle', value); }; /** * Get the fill that is being used. * @alias getFillStyle */ this.getFill = function () { return _this.getFillStyle(); }; this.getFillStyle = function () { return _this.getCanvasProperty('fillStyle'); }; /** * Create a linear gradient to use as a fill. */ this.createLinearGradient = function (x0, y0, x1, y1) { return _this.ctx.createLinearGradient(x0 * _this.density, y0 * _this.density, x1 * _this.density, y1 * _this.density); }; /** * Create a radial gradient to use as a fill. */ this.createRadialGradient = function (x0, y0, r0, x1, y1, r1) { return _this.ctx.createRadialGradient(x0 * _this.density, y0 * _this.density, r0 * _this.density, x1 * _this.density, y1 * _this.density, r1 * _this.density); }; /** * Create a pattern to be used as a fill. */ this.createPattern = function (image, repetition) { return _this.ctx.createPattern(image, repetition); }; /** * Draw an image to the canvas. * If the second position / size arguments are supplied, the first will be used for cropping the image, * and the second for the position and size it will be drawn. */ this.drawImage = function (image, srcX, srcY, srcW, srcH, dstX, dstY, dstW, dstH) { if (typeof srcW !== 'undefined' && typeof srcH !== 'undefined') { if (typeof dstX !== 'undefined' && typeof dstY !== 'undefined' && typeof dstW !== 'undefined' && typeof dstH !== 'undefined') { _this.ctx.drawImage(image, srcX * _this.density, srcY * _this.density, srcW * _this.density, srcH * _this.density, dstX * _this.density, dstY * _this.density, dstW * _this.density, dstH * _this.density); } else { _this.ctx.drawImage(image, srcX * _this.density, srcY * _this.density, srcW * _this.density, srcH * _this.density); } } else { _this.ctx.drawImage(image, srcX * _this.density, srcY * _this.density); } return _this; }; /** * @group Image Data * @description A collection of methods for creating, putting, or getting image data about the canvas. */ /** * Get a data URL of the current canvas state. */ this.getDataURL = function (type) { var args = []; for (var _i = 1; _i < arguments.length; _i++) { args[_i - 1] = arguments[_i]; } var _a; return (_a = _this.element).toDataURL.apply(_a, [type].concat(args)); }; /** * Create image data with either the width and height specified, * or with the width and height of a the image data supplied. */ this.createImageData = function (width, height) { if (typeof width !== 'number') { return _this.ctx.createImageData(width); } return _this.ctx.createImageData(width * _this.density, height || 0 * _this.density); }; /** * Get the image data from an area of the canvas. */ this.getImageData = function (sx, sy, sw, sh) { return _this.ctx.getImageData(sx * _this.density, sy * _this.density, sw * _this.density, sh * _this.density); }; /** * Draw image data onto the canvas. */ this.putImageData = function (imagedata, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight) { if (typeof dirtyX === 'undefined' || typeof dirtyY === 'undefined' || typeof dirtyWidth === 'undefined' || typeof dirtyHeight === 'undefined') { _this.ctx.putImageData(imagedata, dx * _this.density, dy * _this.density); } else { _this.ctx.putImageData(imagedata, dx * _this.density, dy * _this.density, dirtyX * _this.density, dirtyY * _this.density, dirtyWidth * _this.density, dirtyHeight * _this.density); } return _this; }; /** * Get image data about a specific pixel. */ this.getPixelData = function (x, y) { return _this.getImageData(x, y, 1, 1).data; }; /** * Get the color of a specific pixel. */ this.getPixelColor = function (x, y) { var data = _this.getImageData(x, y, 1, 1).data; return _this.createRGBA(data[0], data[1], data[2], data[3]); }; /** * @group Color Helpers * @description A collection of methods to help with creating color strings. */ /** * Create an HSL color string from the given values. */ this.createHSL = function (h, s, l) { return 'hsl(' + h + ',' + s + '%,' + l + '%)'; }; /** * Create an HSLA color string from the given values. */ this.createHSLA = function (h, s, l, a) { return 'hsla(' + h + ',' + s + '%,' + l + '%,' + a + ')'; }; /** * Create an RGB color string from the given values. */ this.createRGB = function (r, g, b) { return 'rgb(' + r + ',' + g + ',' + b + ')'; }; /** * Create an RGBA color string from the given values. */ this.createRGBA = function (r, g, b, a) { return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')'; }; /** * Return an HSL color string from the given HSLA color string. */ this.getHSLFromHSLA = function (color) { return _this.getRGBFromRGBA(color); }; /** * Return an RGB color string from the given RGBA color string. */ this.getRGBFromRGBA = function (color) { var lastCommaIndex = color.lastIndexOf(','); return color.replace(/^(\w{3})a/, '$1').substring(0, lastCommaIndex - 1) + ')'; }; /** * @group Converting Sizes * @description A collection of methods to help with calculating and converting sizes, and distances. */ /** * Get a fraction from the provided percent value e.g. 80 returns 0.8. */ this.getFractionFromPercent = function (percent) { return (percent / 100); }; /** * Get a percent from the provided fraction value e.g. 0.7 returns 70. */ this.getPercentFromFraction = function (fraction) { return (fraction * 100); }; /** * Returns the actual value of a fraction of the canvas width e.g. * a canvas with a width of 200 returns 100 if the provided value is 0.5. */ this.getFractionOfWidth = function (fraction) { return _this.getWidth() * fraction; }; /** * Returns the actual value of a fraction of the canvas height e.g. * a canvas with a height of 100 returns 20 if the provided value is 0.2. */ this.getFractionOfHeight = function (fraction) { return _this.getHeight() * fraction; }; /** * Returns the actual value of a percentage of the canvas width e.g. * a canvas with a width of 200 returns 100 if the provided value is 50. */ this.getPercentOfWidth = function (percent) { return _this.getWidth() / 100 * percent; }; /** * Returns the actual value of a percentage of the canvas height e.g. * a canvas with a height of 100 returns 20 if the provided value is 20. */ this.getPercentOfHeight = function (percent) { return _this.getHeight() / 100 * percent; }; /** * Returns the distance between 2 points. */ this.getDistance = function (x1, y1, x2, y2) { return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); }; /** * @group Converting Angles * @description A collection of methods to help with calculating and converting angles. */ /** * Get a radian value from the provided degrees e.g. 90 returns 1.5708. */ this.getRadiansFromDegrees = function (degrees) { return degrees * Math.PI / 180; }; /** * Get a degree value from the provided radians e.g. 3.14159 returns 180. */ this.getDegreesFromRadians = function (radians) { return radians * 180 / Math.PI; }; /** * Get the angle (in radians) between 2 or 3 points. */ this.getAngle = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!args.length || !(args.length === 4 || args.length === 6)) { throw new Error(constants_1.INCORRECT_GET_ANGLE_ARGUMENTS); } var x1 = args[0]; var y1 = args[1]; var x2 = args[2]; var y2 = args[3]; if (args.length === 4) { return Math.atan2(y2 - y1, x2 - x1); } var x3 = args[4]; var y3 = args[5]; var a = _this.getAngle(x1, y1, x2, y2); var b = _this.getAngle(x2, y2, x3, y3); var c = b - a; if (c >= 0) { return Math.PI - c; } return -Math.PI - c; }; /** * @group Path Plotting * @description A collection of methods for path drawing. */ /** * Begin a new path (shape). */ this.beginPath = function () { _this.ctx.beginPath(); return _this; }; /** * Close the current path (shape). */ this.closePath = function () { _this.ctx.closePath(); return _this; }; /** * Move the starting point of a the next sub-path. */ this.moveTo = function (x, y) { _this.ctx.moveTo(x * _this.density, y * _this.density); return _this; }; /** * Connect the last point to the provided coordinates. */ this.lineTo = function (x, y) { _this.ctx.lineTo(x * _this.density, y * _this.density); return _this; }; /** * Arc from one point to another. */ this.arcTo = function (x1, y1, x2, y2, radius) { _this.ctx.arcTo(x1 * _this.density, y1 * _this.density, x2 * _this.density, y2 * _this.density, radius * _this.density); return _this; }; /** * Connect the last point to the provided coordinates with a bezier curve (2 control points). */ this.bezierCurveTo = function (cp1x, cp1y, cp2x, cp2y, x, y) { _this.ctx.bezierCurveTo(cp1x * _this.density, cp1y * _this.density, cp2x * _this.density, cp2y * _this.density, x * _this.density, y * _this.density); return _this; }; /** * Connect the last point to the provided coordinates with a quadratic curve (1 control point). */ this.quadraticCurveTo = function (cpx, cpy, x, y) { _this.ctx.quadraticCurveTo(cpx * _this.density, cpy * _this.density, x * _this.density, y * _this.density); return _this; }; /** * @group Canvas State * @description A collection of methods to save, restore, or transform the canvas state. */ /** * Push the current state of the canvas into a stack that can later be restored. */ this.save = function () { _this.ctx.save(); return _this; }; /** * Restore the most recent state of the canvas that was saved. */ this.restore = function () { _this.ctx.restore(); return _this; }; /** * Add rotation (in radians) to the transform matrix so that shapes can be drawn at an angle. */ this.rotate = function (angle) { _this.ctx.rotate(angle); return _this; }; /** * Scale the transform matrix so that shapes can be drawn at the provided scale. */ this.scale = function (x, y) { _this.ctx.scale(x, y); return _this; }; /** * Move the canvas origin.