UNPKG

html2canvas

Version:
255 lines (222 loc) 11.2 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _Path = require('../drawing/Path'); var _textDecoration = require('../parsing/textDecoration'); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var addColorStops = function addColorStops(gradient, canvasGradient) { var maxStop = Math.max.apply(null, gradient.colorStops.map(function (colorStop) { return colorStop.stop; })); var f = 1 / Math.max(1, maxStop); gradient.colorStops.forEach(function (colorStop) { canvasGradient.addColorStop(f * colorStop.stop, colorStop.color.toString()); }); }; var CanvasRenderer = function () { function CanvasRenderer(canvas) { _classCallCheck(this, CanvasRenderer); this.canvas = canvas ? canvas : document.createElement('canvas'); } _createClass(CanvasRenderer, [{ key: 'render', value: function render(options) { this.ctx = this.canvas.getContext('2d'); this.options = options; this.canvas.width = Math.floor(options.width * options.scale); this.canvas.height = Math.floor(options.height * options.scale); this.canvas.style.width = options.width + 'px'; this.canvas.style.height = options.height + 'px'; this.ctx.scale(this.options.scale, this.options.scale); this.ctx.translate(-options.x, -options.y); this.ctx.textBaseline = 'bottom'; options.logger.log('Canvas renderer initialized (' + options.width + 'x' + options.height + ' at ' + options.x + ',' + options.y + ') with scale ' + this.options.scale); } }, { key: 'clip', value: function clip(clipPaths, callback) { var _this = this; if (clipPaths.length) { this.ctx.save(); clipPaths.forEach(function (path) { _this.path(path); _this.ctx.clip(); }); } callback(); if (clipPaths.length) { this.ctx.restore(); } } }, { key: 'drawImage', value: function drawImage(image, source, destination) { this.ctx.drawImage(image, source.left, source.top, source.width, source.height, destination.left, destination.top, destination.width, destination.height); } }, { key: 'drawShape', value: function drawShape(path, color) { this.path(path); this.ctx.fillStyle = color.toString(); this.ctx.fill(); } }, { key: 'fill', value: function fill(color) { this.ctx.fillStyle = color.toString(); this.ctx.fill(); } }, { key: 'getTarget', value: function getTarget() { this.canvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0); return Promise.resolve(this.canvas); } }, { key: 'path', value: function path(_path) { var _this2 = this; this.ctx.beginPath(); if (Array.isArray(_path)) { _path.forEach(function (point, index) { var start = point.type === _Path.PATH.VECTOR ? point : point.start; if (index === 0) { _this2.ctx.moveTo(start.x, start.y); } else { _this2.ctx.lineTo(start.x, start.y); } if (point.type === _Path.PATH.BEZIER_CURVE) { _this2.ctx.bezierCurveTo(point.startControl.x, point.startControl.y, point.endControl.x, point.endControl.y, point.end.x, point.end.y); } }); } else { this.ctx.arc(_path.x + _path.radius, _path.y + _path.radius, _path.radius, 0, Math.PI * 2, true); } this.ctx.closePath(); } }, { key: 'rectangle', value: function rectangle(x, y, width, height, color) { this.ctx.fillStyle = color.toString(); this.ctx.fillRect(x, y, width, height); } }, { key: 'renderLinearGradient', value: function renderLinearGradient(bounds, gradient) { var linearGradient = this.ctx.createLinearGradient(bounds.left + gradient.direction.x1, bounds.top + gradient.direction.y1, bounds.left + gradient.direction.x0, bounds.top + gradient.direction.y0); addColorStops(gradient, linearGradient); this.ctx.fillStyle = linearGradient; this.ctx.fillRect(bounds.left, bounds.top, bounds.width, bounds.height); } }, { key: 'renderRadialGradient', value: function renderRadialGradient(bounds, gradient) { var _this3 = this; var x = bounds.left + gradient.center.x; var y = bounds.top + gradient.center.y; var radialGradient = this.ctx.createRadialGradient(x, y, 0, x, y, gradient.radius.x); if (!radialGradient) { return; } addColorStops(gradient, radialGradient); this.ctx.fillStyle = radialGradient; if (gradient.radius.x !== gradient.radius.y) { // transforms for elliptical radial gradient var midX = bounds.left + 0.5 * bounds.width; var midY = bounds.top + 0.5 * bounds.height; var f = gradient.radius.y / gradient.radius.x; var invF = 1 / f; this.transform(midX, midY, [1, 0, 0, f, 0, 0], function () { return _this3.ctx.fillRect(bounds.left, invF * (bounds.top - midY) + midY, bounds.width, bounds.height * invF); }); } else { this.ctx.fillRect(bounds.left, bounds.top, bounds.width, bounds.height); } } }, { key: 'renderRepeat', value: function renderRepeat(path, image, imageSize, offsetX, offsetY) { this.path(path); this.ctx.fillStyle = this.ctx.createPattern(this.resizeImage(image, imageSize), 'repeat'); this.ctx.translate(offsetX, offsetY); this.ctx.fill(); this.ctx.translate(-offsetX, -offsetY); } }, { key: 'renderTextNode', value: function renderTextNode(textBounds, color, font, textDecoration, textShadows) { var _this4 = this; this.ctx.font = [font.fontStyle, font.fontVariant, font.fontWeight, font.fontSize, font.fontFamily].join(' '); textBounds.forEach(function (text) { _this4.ctx.fillStyle = color.toString(); if (textShadows && text.text.trim().length) { textShadows.slice(0).reverse().forEach(function (textShadow) { _this4.ctx.shadowColor = textShadow.color.toString(); _this4.ctx.shadowOffsetX = textShadow.offsetX * _this4.options.scale; _this4.ctx.shadowOffsetY = textShadow.offsetY * _this4.options.scale; _this4.ctx.shadowBlur = textShadow.blur; _this4.ctx.fillText(text.text, text.bounds.left, text.bounds.top + text.bounds.height); }); } else { _this4.ctx.fillText(text.text, text.bounds.left, text.bounds.top + text.bounds.height); } if (textDecoration !== null) { var textDecorationColor = textDecoration.textDecorationColor || color; textDecoration.textDecorationLine.forEach(function (textDecorationLine) { switch (textDecorationLine) { case _textDecoration.TEXT_DECORATION_LINE.UNDERLINE: // Draws a line at the baseline of the font // TODO As some browsers display the line as more than 1px if the font-size is big, // need to take that into account both in position and size var _options$fontMetrics$ = _this4.options.fontMetrics.getMetrics(font), baseline = _options$fontMetrics$.baseline; _this4.rectangle(text.bounds.left, Math.round(text.bounds.top + baseline), text.bounds.width, 1, textDecorationColor); break; case _textDecoration.TEXT_DECORATION_LINE.OVERLINE: _this4.rectangle(text.bounds.left, Math.round(text.bounds.top), text.bounds.width, 1, textDecorationColor); break; case _textDecoration.TEXT_DECORATION_LINE.LINE_THROUGH: // TODO try and find exact position for line-through var _options$fontMetrics$2 = _this4.options.fontMetrics.getMetrics(font), middle = _options$fontMetrics$2.middle; _this4.rectangle(text.bounds.left, Math.ceil(text.bounds.top + middle), text.bounds.width, 1, textDecorationColor); break; } }); } }); } }, { key: 'resizeImage', value: function resizeImage(image, size) { if (image.width === size.width && image.height === size.height) { return image; } var canvas = this.canvas.ownerDocument.createElement('canvas'); canvas.width = size.width; canvas.height = size.height; var ctx = canvas.getContext('2d'); ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, size.width, size.height); return canvas; } }, { key: 'setOpacity', value: function setOpacity(opacity) { this.ctx.globalAlpha = opacity; } }, { key: 'transform', value: function transform(offsetX, offsetY, matrix, callback) { this.ctx.save(); this.ctx.translate(offsetX, offsetY); this.ctx.transform(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); this.ctx.translate(-offsetX, -offsetY); callback(); this.ctx.restore(); } }]); return CanvasRenderer; }(); exports.default = CanvasRenderer;