UNPKG

highcharts

Version:
2,079 lines (1,660 loc) 130 kB
/** * Modules in this bundle * @license * * svg2pdf.js: * license: MIT (http://opensource.org/licenses/MIT) * author: yFiles for HTML Support Team <yfileshtml@yworks.com> * homepage: https://github.com/yWorks/svg2pdf.js#readme * version: 1.3.1 * * cssesc: * license: MIT (http://opensource.org/licenses/MIT) * author: Mathias Bynens * homepage: https://mths.be/cssesc * version: 2.0.0 * * font-family: * license: MIT (http://opensource.org/licenses/MIT) * author: Taro Hanamura <m@hanamurataro.com> * homepage: https://github.com/hanamura/font-family * version: 0.2.0 * * svgpath: * license: MIT (http://opensource.org/licenses/MIT) * homepage: https://github.com/fontello/svgpath#readme * version: 2.2.1 * * This header is generated by licensify (https://github.com/twada/licensify) */ (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.svg2pdf = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ 'use strict'; module.exports = require('./lib/svgpath'); },{"./lib/svgpath":6}],2:[function(require,module,exports){ // Convert an arc to a sequence of cubic bézier curves // 'use strict'; var TAU = Math.PI * 2; /* eslint-disable space-infix-ops */ // Calculate an angle between two vectors // function vector_angle(ux, uy, vx, vy) { var sign = (ux * vy - uy * vx < 0) ? -1 : 1; var umag = Math.sqrt(ux * ux + uy * uy); var vmag = Math.sqrt(ux * ux + uy * uy); var dot = ux * vx + uy * vy; var div = dot / (umag * vmag); // rounding errors, e.g. -1.0000000000000002 can screw up this if (div > 1.0) { div = 1.0; } if (div < -1.0) { div = -1.0; } return sign * Math.acos(div); } // Convert from endpoint to center parameterization, // see http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes // // Return [cx, cy, theta1, delta_theta] // function get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi) { // Step 1. // // Moving an ellipse so origin will be the middlepoint between our two // points. After that, rotate it to line up ellipse axes with coordinate // axes. // var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2; var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2; var rx_sq = rx * rx; var ry_sq = ry * ry; var x1p_sq = x1p * x1p; var y1p_sq = y1p * y1p; // Step 2. // // Compute coordinates of the centre of this ellipse (cx', cy') // in the new coordinate system. // var radicant = (rx_sq * ry_sq) - (rx_sq * y1p_sq) - (ry_sq * x1p_sq); if (radicant < 0) { // due to rounding errors it might be e.g. -1.3877787807814457e-17 radicant = 0; } radicant /= (rx_sq * y1p_sq) + (ry_sq * x1p_sq); radicant = Math.sqrt(radicant) * (fa === fs ? -1 : 1); var cxp = radicant * rx/ry * y1p; var cyp = radicant * -ry/rx * x1p; // Step 3. // // Transform back to get centre coordinates (cx, cy) in the original // coordinate system. // var cx = cos_phi*cxp - sin_phi*cyp + (x1+x2)/2; var cy = sin_phi*cxp + cos_phi*cyp + (y1+y2)/2; // Step 4. // // Compute angles (theta1, delta_theta). // var v1x = (x1p - cxp) / rx; var v1y = (y1p - cyp) / ry; var v2x = (-x1p - cxp) / rx; var v2y = (-y1p - cyp) / ry; var theta1 = vector_angle(1, 0, v1x, v1y); var delta_theta = vector_angle(v1x, v1y, v2x, v2y); if (fs === 0 && delta_theta > 0) { delta_theta -= TAU; } if (fs === 1 && delta_theta < 0) { delta_theta += TAU; } return [ cx, cy, theta1, delta_theta ]; } // // Approximate one unit arc segment with bézier curves, // see http://math.stackexchange.com/questions/873224 // function approximate_unit_arc(theta1, delta_theta) { var alpha = 4/3 * Math.tan(delta_theta/4); var x1 = Math.cos(theta1); var y1 = Math.sin(theta1); var x2 = Math.cos(theta1 + delta_theta); var y2 = Math.sin(theta1 + delta_theta); return [ x1, y1, x1 - y1*alpha, y1 + x1*alpha, x2 + y2*alpha, y2 - x2*alpha, x2, y2 ]; } module.exports = function a2c(x1, y1, x2, y2, fa, fs, rx, ry, phi) { var sin_phi = Math.sin(phi * TAU / 360); var cos_phi = Math.cos(phi * TAU / 360); // Make sure radii are valid // var x1p = cos_phi*(x1-x2)/2 + sin_phi*(y1-y2)/2; var y1p = -sin_phi*(x1-x2)/2 + cos_phi*(y1-y2)/2; if (x1p === 0 && y1p === 0) { // we're asked to draw line to itself return []; } if (rx === 0 || ry === 0) { // one of the radii is zero return []; } // Compensate out-of-range radii // rx = Math.abs(rx); ry = Math.abs(ry); var lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry); if (lambda > 1) { rx *= Math.sqrt(lambda); ry *= Math.sqrt(lambda); } // Get center parameters (cx, cy, theta1, delta_theta) // var cc = get_arc_center(x1, y1, x2, y2, fa, fs, rx, ry, sin_phi, cos_phi); var result = []; var theta1 = cc[2]; var delta_theta = cc[3]; // Split an arc to multiple segments, so each segment // will be less than τ/4 (= 90°) // var segments = Math.max(Math.ceil(Math.abs(delta_theta) / (TAU / 4)), 1); delta_theta /= segments; for (var i = 0; i < segments; i++) { result.push(approximate_unit_arc(theta1, delta_theta)); theta1 += delta_theta; } // We have a bezier approximation of a unit circle, // now need to transform back to the original ellipse // return result.map(function (curve) { for (var i = 0; i < curve.length; i += 2) { var x = curve[i + 0]; var y = curve[i + 1]; // scale x *= rx; y *= ry; // rotate var xp = cos_phi*x - sin_phi*y; var yp = sin_phi*x + cos_phi*y; // translate curve[i + 0] = xp + cc[0]; curve[i + 1] = yp + cc[1]; } return curve; }); }; },{}],3:[function(require,module,exports){ 'use strict'; /* eslint-disable space-infix-ops */ // The precision used to consider an ellipse as a circle // var epsilon = 0.0000000001; // To convert degree in radians // var torad = Math.PI / 180; // Class constructor : // an ellipse centred at 0 with radii rx,ry and x - axis - angle ax. // function Ellipse(rx, ry, ax) { if (!(this instanceof Ellipse)) { return new Ellipse(rx, ry, ax); } this.rx = rx; this.ry = ry; this.ax = ax; } // Apply a linear transform m to the ellipse // m is an array representing a matrix : // - - // | m[0] m[2] | // | m[1] m[3] | // - - // Ellipse.prototype.transform = function (m) { // We consider the current ellipse as image of the unit circle // by first scale(rx,ry) and then rotate(ax) ... // So we apply ma = m x rotate(ax) x scale(rx,ry) to the unit circle. var c = Math.cos(this.ax * torad), s = Math.sin(this.ax * torad); var ma = [ this.rx * (m[0]*c + m[2]*s), this.rx * (m[1]*c + m[3]*s), this.ry * (-m[0]*s + m[2]*c), this.ry * (-m[1]*s + m[3]*c) ]; // ma * transpose(ma) = [ J L ] // [ L K ] // L is calculated later (if the image is not a circle) var J = ma[0]*ma[0] + ma[2]*ma[2], K = ma[1]*ma[1] + ma[3]*ma[3]; // the discriminant of the characteristic polynomial of ma * transpose(ma) var D = ((ma[0]-ma[3])*(ma[0]-ma[3]) + (ma[2]+ma[1])*(ma[2]+ma[1])) * ((ma[0]+ma[3])*(ma[0]+ma[3]) + (ma[2]-ma[1])*(ma[2]-ma[1])); // the "mean eigenvalue" var JK = (J + K) / 2; // check if the image is (almost) a circle if (D < epsilon * JK) { // if it is this.rx = this.ry = Math.sqrt(JK); this.ax = 0; return this; } // if it is not a circle var L = ma[0]*ma[1] + ma[2]*ma[3]; D = Math.sqrt(D); // {l1,l2} = the two eigen values of ma * transpose(ma) var l1 = JK + D/2, l2 = JK - D/2; // the x - axis - rotation angle is the argument of the l1 - eigenvector this.ax = (Math.abs(L) < epsilon && Math.abs(l1 - K) < epsilon) ? 90 : Math.atan(Math.abs(L) > Math.abs(l1 - K) ? (l1 - J) / L : L / (l1 - K) ) * 180 / Math.PI; // if ax > 0 => rx = sqrt(l1), ry = sqrt(l2), else exchange axes and ax += 90 if (this.ax >= 0) { // if ax in [0,90] this.rx = Math.sqrt(l1); this.ry = Math.sqrt(l2); } else { // if ax in ]-90,0[ => exchange axes this.ax += 90; this.rx = Math.sqrt(l2); this.ry = Math.sqrt(l1); } return this; }; // Check if the ellipse is (almost) degenerate, i.e. rx = 0 or ry = 0 // Ellipse.prototype.isDegenerate = function () { return (this.rx < epsilon * this.ry || this.ry < epsilon * this.rx); }; module.exports = Ellipse; },{}],4:[function(require,module,exports){ 'use strict'; // combine 2 matrixes // m1, m2 - [a, b, c, d, e, g] // function combine(m1, m2) { return [ m1[0] * m2[0] + m1[2] * m2[1], m1[1] * m2[0] + m1[3] * m2[1], m1[0] * m2[2] + m1[2] * m2[3], m1[1] * m2[2] + m1[3] * m2[3], m1[0] * m2[4] + m1[2] * m2[5] + m1[4], m1[1] * m2[4] + m1[3] * m2[5] + m1[5] ]; } function Matrix() { if (!(this instanceof Matrix)) { return new Matrix(); } this.queue = []; // list of matrixes to apply this.cache = null; // combined matrix cache } Matrix.prototype.matrix = function (m) { if (m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0) { return this; } this.cache = null; this.queue.push(m); return this; }; Matrix.prototype.translate = function (tx, ty) { if (tx !== 0 || ty !== 0) { this.cache = null; this.queue.push([ 1, 0, 0, 1, tx, ty ]); } return this; }; Matrix.prototype.scale = function (sx, sy) { if (sx !== 1 || sy !== 1) { this.cache = null; this.queue.push([ sx, 0, 0, sy, 0, 0 ]); } return this; }; Matrix.prototype.rotate = function (angle, rx, ry) { var rad, cos, sin; if (angle !== 0) { this.translate(rx, ry); rad = angle * Math.PI / 180; cos = Math.cos(rad); sin = Math.sin(rad); this.queue.push([ cos, sin, -sin, cos, 0, 0 ]); this.cache = null; this.translate(-rx, -ry); } return this; }; Matrix.prototype.skewX = function (angle) { if (angle !== 0) { this.cache = null; this.queue.push([ 1, 0, Math.tan(angle * Math.PI / 180), 1, 0, 0 ]); } return this; }; Matrix.prototype.skewY = function (angle) { if (angle !== 0) { this.cache = null; this.queue.push([ 1, Math.tan(angle * Math.PI / 180), 0, 1, 0, 0 ]); } return this; }; // Flatten queue // Matrix.prototype.toArray = function () { if (this.cache) { return this.cache; } if (!this.queue.length) { this.cache = [ 1, 0, 0, 1, 0, 0 ]; return this.cache; } this.cache = this.queue[0]; if (this.queue.length === 1) { return this.cache; } for (var i = 1; i < this.queue.length; i++) { this.cache = combine(this.cache, this.queue[i]); } return this.cache; }; // Apply list of matrixes to (x,y) point. // If `isRelative` set, `translate` component of matrix will be skipped // Matrix.prototype.calc = function (x, y, isRelative) { var m; // Don't change point on empty transforms queue if (!this.queue.length) { return [ x, y ]; } // Calculate final matrix, if not exists // // NB. if you deside to apply transforms to point one-by-one, // they should be taken in reverse order if (!this.cache) { this.cache = this.toArray(); } m = this.cache; // Apply matrix to point return [ x * m[0] + y * m[2] + (isRelative ? 0 : m[4]), x * m[1] + y * m[3] + (isRelative ? 0 : m[5]) ]; }; module.exports = Matrix; },{}],5:[function(require,module,exports){ 'use strict'; var paramCounts = { a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0 }; var SPECIAL_SPACES = [ 0x1680, 0x180E, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x202F, 0x205F, 0x3000, 0xFEFF ]; function isSpace(ch) { return (ch === 0x0A) || (ch === 0x0D) || (ch === 0x2028) || (ch === 0x2029) || // Line terminators // White spaces (ch === 0x20) || (ch === 0x09) || (ch === 0x0B) || (ch === 0x0C) || (ch === 0xA0) || (ch >= 0x1680 && SPECIAL_SPACES.indexOf(ch) >= 0); } function isCommand(code) { /*eslint-disable no-bitwise*/ switch (code | 0x20) { case 0x6D/* m */: case 0x7A/* z */: case 0x6C/* l */: case 0x68/* h */: case 0x76/* v */: case 0x63/* c */: case 0x73/* s */: case 0x71/* q */: case 0x74/* t */: case 0x61/* a */: case 0x72/* r */: return true; } return false; } function isDigit(code) { return (code >= 48 && code <= 57); // 0..9 } function isDigitStart(code) { return (code >= 48 && code <= 57) || /* 0..9 */ code === 0x2B || /* + */ code === 0x2D || /* - */ code === 0x2E; /* . */ } function State(path) { this.index = 0; this.path = path; this.max = path.length; this.result = []; this.param = 0.0; this.err = ''; this.segmentStart = 0; this.data = []; } function skipSpaces(state) { while (state.index < state.max && isSpace(state.path.charCodeAt(state.index))) { state.index++; } } function scanParam(state) { var start = state.index, index = start, max = state.max, zeroFirst = false, hasCeiling = false, hasDecimal = false, hasDot = false, ch; if (index >= max) { state.err = 'SvgPath: missed param (at pos ' + index + ')'; return; } ch = state.path.charCodeAt(index); if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { index++; ch = (index < max) ? state.path.charCodeAt(index) : 0; } // This logic is shamelessly borrowed from Esprima // https://github.com/ariya/esprimas // if (!isDigit(ch) && ch !== 0x2E/* . */) { state.err = 'SvgPath: param should start with 0..9 or `.` (at pos ' + index + ')'; return; } if (ch !== 0x2E/* . */) { zeroFirst = (ch === 0x30/* 0 */); index++; ch = (index < max) ? state.path.charCodeAt(index) : 0; if (zeroFirst && index < max) { // decimal number starts with '0' such as '09' is illegal. if (ch && isDigit(ch)) { state.err = 'SvgPath: numbers started with `0` such as `09` are ilegal (at pos ' + start + ')'; return; } } while (index < max && isDigit(state.path.charCodeAt(index))) { index++; hasCeiling = true; } ch = (index < max) ? state.path.charCodeAt(index) : 0; } if (ch === 0x2E/* . */) { hasDot = true; index++; while (isDigit(state.path.charCodeAt(index))) { index++; hasDecimal = true; } ch = (index < max) ? state.path.charCodeAt(index) : 0; } if (ch === 0x65/* e */ || ch === 0x45/* E */) { if (hasDot && !hasCeiling && !hasDecimal) { state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')'; return; } index++; ch = (index < max) ? state.path.charCodeAt(index) : 0; if (ch === 0x2B/* + */ || ch === 0x2D/* - */) { index++; } if (index < max && isDigit(state.path.charCodeAt(index))) { while (index < max && isDigit(state.path.charCodeAt(index))) { index++; } } else { state.err = 'SvgPath: invalid float exponent (at pos ' + index + ')'; return; } } state.index = index; state.param = parseFloat(state.path.slice(start, index)) + 0.0; } function finalizeSegment(state) { var cmd, cmdLC; // Process duplicated commands (without comand name) // This logic is shamelessly borrowed from Raphael // https://github.com/DmitryBaranovskiy/raphael/ // cmd = state.path[state.segmentStart]; cmdLC = cmd.toLowerCase(); var params = state.data; if (cmdLC === 'm' && params.length > 2) { state.result.push([ cmd, params[0], params[1] ]); params = params.slice(2); cmdLC = 'l'; cmd = (cmd === 'm') ? 'l' : 'L'; } if (cmdLC === 'r') { state.result.push([ cmd ].concat(params)); } else { while (params.length >= paramCounts[cmdLC]) { state.result.push([ cmd ].concat(params.splice(0, paramCounts[cmdLC]))); if (!paramCounts[cmdLC]) { break; } } } } function scanSegment(state) { var max = state.max, cmdCode, comma_found, need_params, i; state.segmentStart = state.index; cmdCode = state.path.charCodeAt(state.index); if (!isCommand(cmdCode)) { state.err = 'SvgPath: bad command ' + state.path[state.index] + ' (at pos ' + state.index + ')'; return; } need_params = paramCounts[state.path[state.index].toLowerCase()]; state.index++; skipSpaces(state); state.data = []; if (!need_params) { // Z finalizeSegment(state); return; } comma_found = false; for (;;) { for (i = need_params; i > 0; i--) { scanParam(state); if (state.err.length) { return; } state.data.push(state.param); skipSpaces(state); comma_found = false; if (state.index < max && state.path.charCodeAt(state.index) === 0x2C/* , */) { state.index++; skipSpaces(state); comma_found = true; } } // after ',' param is mandatory if (comma_found) { continue; } if (state.index >= state.max) { break; } // Stop on next segment if (!isDigitStart(state.path.charCodeAt(state.index))) { break; } } finalizeSegment(state); } /* Returns array of segments: * * [ * [ command, coord1, coord2, ... ] * ] */ module.exports = function pathParse(svgPath) { var state = new State(svgPath); var max = state.max; skipSpaces(state); while (state.index < max && !state.err.length) { scanSegment(state); } if (state.err.length) { state.result = []; } else if (state.result.length) { if ('mM'.indexOf(state.result[0][0]) < 0) { state.err = 'SvgPath: string should start with `M` or `m`'; state.result = []; } else { state.result[0][0] = 'M'; } } return { err: state.err, segments: state.result }; }; },{}],6:[function(require,module,exports){ // SVG Path transformations library // // Usage: // // SvgPath('...') // .translate(-150, -100) // .scale(0.5) // .translate(-150, -100) // .toFixed(1) // .toString() // 'use strict'; var pathParse = require('./path_parse'); var transformParse = require('./transform_parse'); var matrix = require('./matrix'); var a2c = require('./a2c'); var ellipse = require('./ellipse'); // Class constructor // function SvgPath(path) { if (!(this instanceof SvgPath)) { return new SvgPath(path); } var pstate = pathParse(path); // Array of path segments. // Each segment is array [command, param1, param2, ...] this.segments = pstate.segments; // Error message on parse error. this.err = pstate.err; // Transforms stack for lazy evaluation this.__stack = []; } SvgPath.prototype.__matrix = function (m) { var self = this, i; // Quick leave for empty matrix if (!m.queue.length) { return; } this.iterate(function (s, index, x, y) { var p, result, name, isRelative; switch (s[0]) { // Process 'assymetric' commands separately case 'v': p = m.calc(0, s[1], true); result = (p[0] === 0) ? [ 'v', p[1] ] : [ 'l', p[0], p[1] ]; break; case 'V': p = m.calc(x, s[1], false); result = (p[0] === m.calc(x, y, false)[0]) ? [ 'V', p[1] ] : [ 'L', p[0], p[1] ]; break; case 'h': p = m.calc(s[1], 0, true); result = (p[1] === 0) ? [ 'h', p[0] ] : [ 'l', p[0], p[1] ]; break; case 'H': p = m.calc(s[1], y, false); result = (p[1] === m.calc(x, y, false)[1]) ? [ 'H', p[0] ] : [ 'L', p[0], p[1] ]; break; case 'a': case 'A': // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] // Drop segment if arc is empty (end point === start point) /*if ((s[0] === 'A' && s[6] === x && s[7] === y) || (s[0] === 'a' && s[6] === 0 && s[7] === 0)) { return []; }*/ // Transform rx, ry and the x-axis-rotation var ma = m.toArray(); var e = ellipse(s[1], s[2], s[3]).transform(ma); // flip sweep-flag if matrix is not orientation-preserving if (ma[0] * ma[3] - ma[1] * ma[2] < 0) { s[5] = s[5] ? '0' : '1'; } // Transform end point as usual (without translation for relative notation) p = m.calc(s[6], s[7], s[0] === 'a'); // Empty arcs can be ignored by renderer, but should not be dropped // to avoid collisions with `S A S` and so on. Replace with empty line. if ((s[0] === 'A' && s[6] === x && s[7] === y) || (s[0] === 'a' && s[6] === 0 && s[7] === 0)) { result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ]; break; } // if the resulting ellipse is (almost) a segment ... if (e.isDegenerate()) { // replace the arc by a line result = [ s[0] === 'a' ? 'l' : 'L', p[0], p[1] ]; } else { // if it is a real ellipse // s[0], s[4] and s[5] are not modified result = [ s[0], e.rx, e.ry, e.ax, s[4], s[5], p[0], p[1] ]; } break; case 'm': // Edge case. The very first `m` should be processed as absolute, if happens. // Make sense for coord shift transforms. isRelative = index > 0; p = m.calc(s[1], s[2], isRelative); result = [ 'm', p[0], p[1] ]; break; default: name = s[0]; result = [ name ]; isRelative = (name.toLowerCase() === name); // Apply transformations to the segment for (i = 1; i < s.length; i += 2) { p = m.calc(s[i], s[i + 1], isRelative); result.push(p[0], p[1]); } } self.segments[index] = result; }, true); }; // Apply stacked commands // SvgPath.prototype.__evaluateStack = function () { var m, i; if (!this.__stack.length) { return; } if (this.__stack.length === 1) { this.__matrix(this.__stack[0]); this.__stack = []; return; } m = matrix(); i = this.__stack.length; while (--i >= 0) { m.matrix(this.__stack[i].toArray()); } this.__matrix(m); this.__stack = []; }; // Convert processed SVG Path back to string // SvgPath.prototype.toString = function () { var elements = [], skipCmd, cmd; this.__evaluateStack(); for (var i = 0; i < this.segments.length; i++) { // remove repeating commands names cmd = this.segments[i][0]; skipCmd = i > 0 && cmd !== 'm' && cmd !== 'M' && cmd === this.segments[i - 1][0]; elements = elements.concat(skipCmd ? this.segments[i].slice(1) : this.segments[i]); } return elements.join(' ') // Optimizations: remove spaces around commands & before `-` // // We could also remove leading zeros for `0.5`-like values, // but their count is too small to spend time for. .replace(/ ?([achlmqrstvz]) ?/gi, '$1') .replace(/ \-/g, '-') // workaround for FontForge SVG importing bug .replace(/zm/g, 'z m'); }; // Translate path to (x [, y]) // SvgPath.prototype.translate = function (x, y) { this.__stack.push(matrix().translate(x, y || 0)); return this; }; // Scale path to (sx [, sy]) // sy = sx if not defined // SvgPath.prototype.scale = function (sx, sy) { this.__stack.push(matrix().scale(sx, (!sy && (sy !== 0)) ? sx : sy)); return this; }; // Rotate path around point (sx [, sy]) // sy = sx if not defined // SvgPath.prototype.rotate = function (angle, rx, ry) { this.__stack.push(matrix().rotate(angle, rx || 0, ry || 0)); return this; }; // Skew path along the X axis by `degrees` angle // SvgPath.prototype.skewX = function (degrees) { this.__stack.push(matrix().skewX(degrees)); return this; }; // Skew path along the Y axis by `degrees` angle // SvgPath.prototype.skewY = function (degrees) { this.__stack.push(matrix().skewY(degrees)); return this; }; // Apply matrix transform (array of 6 elements) // SvgPath.prototype.matrix = function (m) { this.__stack.push(matrix().matrix(m)); return this; }; // Transform path according to "transform" attr of SVG spec // SvgPath.prototype.transform = function (transformString) { if (!transformString.trim()) { return this; } this.__stack.push(transformParse(transformString)); return this; }; // Round coords with given decimal precition. // 0 by default (to integers) // SvgPath.prototype.round = function (d) { var contourStartDeltaX = 0, contourStartDeltaY = 0, deltaX = 0, deltaY = 0, l; d = d || 0; this.__evaluateStack(); this.segments.forEach(function (s) { var isRelative = (s[0].toLowerCase() === s[0]); switch (s[0]) { case 'H': case 'h': if (isRelative) { s[1] += deltaX; } deltaX = s[1] - s[1].toFixed(d); s[1] = +s[1].toFixed(d); return; case 'V': case 'v': if (isRelative) { s[1] += deltaY; } deltaY = s[1] - s[1].toFixed(d); s[1] = +s[1].toFixed(d); return; case 'Z': case 'z': deltaX = contourStartDeltaX; deltaY = contourStartDeltaY; return; case 'M': case 'm': if (isRelative) { s[1] += deltaX; s[2] += deltaY; } deltaX = s[1] - s[1].toFixed(d); deltaY = s[2] - s[2].toFixed(d); contourStartDeltaX = deltaX; contourStartDeltaY = deltaY; s[1] = +s[1].toFixed(d); s[2] = +s[2].toFixed(d); return; case 'A': case 'a': // [cmd, rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] if (isRelative) { s[6] += deltaX; s[7] += deltaY; } deltaX = s[6] - s[6].toFixed(d); deltaY = s[7] - s[7].toFixed(d); s[1] = +s[1].toFixed(d); s[2] = +s[2].toFixed(d); s[3] = +s[3].toFixed(d + 2); // better precision for rotation s[6] = +s[6].toFixed(d); s[7] = +s[7].toFixed(d); return; default: // a c l q s t l = s.length; if (isRelative) { s[l - 2] += deltaX; s[l - 1] += deltaY; } deltaX = s[l - 2] - s[l - 2].toFixed(d); deltaY = s[l - 1] - s[l - 1].toFixed(d); s.forEach(function (val, i) { if (!i) { return; } s[i] = +s[i].toFixed(d); }); return; } }); return this; }; // Apply iterator function to all segments. If function returns result, // current segment will be replaced to array of returned segments. // If empty array is returned, current regment will be deleted. // SvgPath.prototype.iterate = function (iterator, keepLazyStack) { var segments = this.segments, replacements = {}, needReplace = false, lastX = 0, lastY = 0, countourStartX = 0, countourStartY = 0; var i, j, newSegments; if (!keepLazyStack) { this.__evaluateStack(); } segments.forEach(function (s, index) { var res = iterator(s, index, lastX, lastY); if (Array.isArray(res)) { replacements[index] = res; needReplace = true; } var isRelative = (s[0] === s[0].toLowerCase()); // calculate absolute X and Y switch (s[0]) { case 'm': case 'M': lastX = s[1] + (isRelative ? lastX : 0); lastY = s[2] + (isRelative ? lastY : 0); countourStartX = lastX; countourStartY = lastY; return; case 'h': case 'H': lastX = s[1] + (isRelative ? lastX : 0); return; case 'v': case 'V': lastY = s[1] + (isRelative ? lastY : 0); return; case 'z': case 'Z': // That make sence for multiple contours lastX = countourStartX; lastY = countourStartY; return; default: lastX = s[s.length - 2] + (isRelative ? lastX : 0); lastY = s[s.length - 1] + (isRelative ? lastY : 0); } }); // Replace segments if iterator return results if (!needReplace) { return this; } newSegments = []; for (i = 0; i < segments.length; i++) { if (typeof replacements[i] !== 'undefined') { for (j = 0; j < replacements[i].length; j++) { newSegments.push(replacements[i][j]); } } else { newSegments.push(segments[i]); } } this.segments = newSegments; return this; }; // Converts segments from relative to absolute // SvgPath.prototype.abs = function () { this.iterate(function (s, index, x, y) { var name = s[0], nameUC = name.toUpperCase(), i; // Skip absolute commands if (name === nameUC) { return; } s[0] = nameUC; switch (name) { case 'v': // v has shifted coords parity s[1] += y; return; case 'a': // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] // touch x, y only s[6] += x; s[7] += y; return; default: for (i = 1; i < s.length; i++) { s[i] += i % 2 ? x : y; // odd values are X, even - Y } } }, true); return this; }; // Converts segments from absolute to relative // SvgPath.prototype.rel = function () { this.iterate(function (s, index, x, y) { var name = s[0], nameLC = name.toLowerCase(), i; // Skip relative commands if (name === nameLC) { return; } // Don't touch the first M to avoid potential confusions. if (index === 0 && name === 'M') { return; } s[0] = nameLC; switch (name) { case 'V': // V has shifted coords parity s[1] -= y; return; case 'A': // ARC is: ['A', rx, ry, x-axis-rotation, large-arc-flag, sweep-flag, x, y] // touch x, y only s[6] -= x; s[7] -= y; return; default: for (i = 1; i < s.length; i++) { s[i] -= i % 2 ? x : y; // odd values are X, even - Y } } }, true); return this; }; // Converts arcs to cubic bézier curves // SvgPath.prototype.unarc = function () { this.iterate(function (s, index, x, y) { var new_segments, nextX, nextY, result = [], name = s[0]; // Skip anything except arcs if (name !== 'A' && name !== 'a') { return null; } if (name === 'a') { // convert relative arc coordinates to absolute nextX = x + s[6]; nextY = y + s[7]; } else { nextX = s[6]; nextY = s[7]; } new_segments = a2c(x, y, nextX, nextY, s[4], s[5], s[1], s[2], s[3]); // Degenerated arcs can be ignored by renderer, but should not be dropped // to avoid collisions with `S A S` and so on. Replace with empty line. if (new_segments.length === 0) { return [ [ s[0] === 'a' ? 'l' : 'L', s[6], s[7] ] ]; } new_segments.forEach(function (s) { result.push([ 'C', s[2], s[3], s[4], s[5], s[6], s[7] ]); }); return result; }); return this; }; // Converts smooth curves (with missed control point) to generic curves // SvgPath.prototype.unshort = function () { var segments = this.segments; var prevControlX, prevControlY, prevSegment; var curControlX, curControlY; // TODO: add lazy evaluation flag when relative commands supported this.iterate(function (s, idx, x, y) { var name = s[0], nameUC = name.toUpperCase(), isRelative; // First command MUST be M|m, it's safe to skip. // Protect from access to [-1] for sure. if (!idx) { return; } if (nameUC === 'T') { // quadratic curve isRelative = (name === 't'); prevSegment = segments[idx - 1]; if (prevSegment[0] === 'Q') { prevControlX = prevSegment[1] - x; prevControlY = prevSegment[2] - y; } else if (prevSegment[0] === 'q') { prevControlX = prevSegment[1] - prevSegment[3]; prevControlY = prevSegment[2] - prevSegment[4]; } else { prevControlX = 0; prevControlY = 0; } curControlX = -prevControlX; curControlY = -prevControlY; if (!isRelative) { curControlX += x; curControlY += y; } segments[idx] = [ isRelative ? 'q' : 'Q', curControlX, curControlY, s[1], s[2] ]; } else if (nameUC === 'S') { // cubic curve isRelative = (name === 's'); prevSegment = segments[idx - 1]; if (prevSegment[0] === 'C') { prevControlX = prevSegment[3] - x; prevControlY = prevSegment[4] - y; } else if (prevSegment[0] === 'c') { prevControlX = prevSegment[3] - prevSegment[5]; prevControlY = prevSegment[4] - prevSegment[6]; } else { prevControlX = 0; prevControlY = 0; } curControlX = -prevControlX; curControlY = -prevControlY; if (!isRelative) { curControlX += x; curControlY += y; } segments[idx] = [ isRelative ? 'c' : 'C', curControlX, curControlY, s[1], s[2], s[3], s[4] ]; } }); return this; }; module.exports = SvgPath; },{"./a2c":2,"./ellipse":3,"./matrix":4,"./path_parse":5,"./transform_parse":7}],7:[function(require,module,exports){ 'use strict'; var Matrix = require('./matrix'); var operations = { matrix: true, scale: true, rotate: true, translate: true, skewX: true, skewY: true }; var CMD_SPLIT_RE = /\s*(matrix|translate|scale|rotate|skewX|skewY)\s*\(\s*(.+?)\s*\)[\s,]*/; var PARAMS_SPLIT_RE = /[\s,]+/; module.exports = function transformParse(transformString) { var matrix = new Matrix(); var cmd, params; // Split value into ['', 'translate', '10 50', '', 'scale', '2', '', 'rotate', '-45', ''] transformString.split(CMD_SPLIT_RE).forEach(function (item) { // Skip empty elements if (!item.length) { return; } // remember operation if (typeof operations[item] !== 'undefined') { cmd = item; return; } // extract params & att operation to matrix params = item.split(PARAMS_SPLIT_RE).map(function (i) { return +i || 0; }); // If params count is not correct - ignore command switch (cmd) { case 'matrix': if (params.length === 6) { matrix.matrix(params); } return; case 'scale': if (params.length === 1) { matrix.scale(params[0], params[0]); } else if (params.length === 2) { matrix.scale(params[0], params[1]); } return; case 'rotate': if (params.length === 1) { matrix.rotate(params[0], 0, 0); } else if (params.length === 3) { matrix.rotate(params[0], params[1], params[2]); } return; case 'translate': if (params.length === 1) { matrix.translate(params[0], 0); } else if (params.length === 2) { matrix.translate(params[0], params[1]); } return; case 'skewX': if (params.length === 1) { matrix.skewX(params[0]); } return; case 'skewY': if (params.length === 1) { matrix.skewY(params[0]); } return; } }); return matrix; }; },{"./matrix":4}],8:[function(require,module,exports){ /*! https://mths.be/cssesc v1.0.1 by @mathias */ 'use strict'; var object = {}; var hasOwnProperty = object.hasOwnProperty; var merge = function merge(options, defaults) { if (!options) { return defaults; } var result = {}; for (var key in defaults) { // `if (defaults.hasOwnProperty(key) { … }` is not needed here, since // only recognized option names are used. result[key] = hasOwnProperty.call(options, key) ? options[key] : defaults[key]; } return result; }; var regexAnySingleEscape = /[ -,\.\/;-@\[-\^`\{-~]/; var regexSingleEscape = /[ -,\.\/;-@\[\]\^`\{-~]/; var regexAlwaysEscape = /['"\\]/; var regexExcessiveSpaces = /(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g; // https://mathiasbynens.be/notes/css-escapes#css var cssesc = function cssesc(string, options) { options = merge(options, cssesc.options); if (options.quotes != 'single' && options.quotes != 'double') { options.quotes = 'single'; } var quote = options.quotes == 'double' ? '"' : '\''; var isIdentifier = options.isIdentifier; var firstChar = string.charAt(0); var output = ''; var counter = 0; var length = string.length; while (counter < length) { var character = string.charAt(counter++); var codePoint = character.charCodeAt(); var value = void 0; // If it’s not a printable ASCII character… if (codePoint < 0x20 || codePoint > 0x7E) { if (codePoint >= 0xD800 && codePoint <= 0xDBFF && counter < length) { // It’s a high surrogate, and there is a next character. var extra = string.charCodeAt(counter++); if ((extra & 0xFC00) == 0xDC00) { // next character is low surrogate codePoint = ((codePoint & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000; } else { // It’s an unmatched surrogate; only append this code unit, in case // the next code unit is the high surrogate of a surrogate pair. counter--; } } value = '\\' + codePoint.toString(16).toUpperCase() + ' '; } else { if (options.escapeEverything) { if (regexAnySingleEscape.test(character)) { value = '\\' + character; } else { value = '\\' + codePoint.toString(16).toUpperCase() + ' '; } // Note: `:` could be escaped as `\:`, but that fails in IE < 8. } else if (/[\t\n\f\r\x0B:]/.test(character)) { if (!isIdentifier && character == ':') { value = character; } else { value = '\\' + codePoint.toString(16).toUpperCase() + ' '; } } else if (character == '\\' || !isIdentifier && (character == '"' && quote == character || character == '\'' && quote == character) || isIdentifier && regexSingleEscape.test(character)) { value = '\\' + character; } else { value = character; } } output += value; } if (isIdentifier) { if (/^_/.test(output)) { // Prevent IE6 from ignoring the rule altogether (in case this is for an // identifier used as a selector) output = '\\_' + output.slice(1); } else if (/^-[-\d]/.test(output)) { output = '\\-' + output.slice(1); } else if (/\d/.test(firstChar)) { output = '\\3' + firstChar + ' ' + output.slice(1); } } // Remove spaces after `\HEX` escapes that are not followed by a hex digit, // since they’re redundant. Note that this is only possible if the escape // sequence isn’t preceded by an odd number of backslashes. output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) { if ($1 && $1.length % 2) { // It’s not safe to remove the space, so don’t. return $0; } // Strip the space. return ($1 || '') + $2; }); if (!isIdentifier && options.wrap) { return quote + output + quote; } return output; }; // Expose default options (so they can be overridden globally). cssesc.options = { 'escapeEverything': false, 'isIdentifier': false, 'quotes': 'single', 'wrap': false }; cssesc.version = '1.0.1'; module.exports = cssesc; },{}],9:[function(require,module,exports){ // parse // ===== // states // ------ var PLAIN = 0; var STRINGS = 1; var ESCAPING = 2; var IDENTIFIER = 3; var SEPARATING = 4; // patterns // -------- var identifierPattern = /[a-z0-9_-]/i; var spacePattern = /[\s\t]/; // --- var parse = function(str) { // vars // ---- var starting = true; var state = PLAIN; var buffer = ''; var i = 0; var quote; var c; // result // ------ var names = []; // parse // ----- while (true) { c = str[i]; if (state === PLAIN) { if (!c && starting) { break; } else if (!c && !starting) { throw new Error('Parse error'); } else if (c === '"' || c === "'") { quote = c; state = STRINGS; starting = false; } else if (spacePattern.test(c)) { } else if (identifierPattern.test(c)) { state = IDENTIFIER; starting = false; i--; } else { throw new Error('Parse error'); } } else if (state === STRINGS) { if (!c) { throw new Error('Parse Error'); } else if (c === "\\") { state = ESCAPING; } else if (c === quote) { names.push(buffer); buffer = ''; state = SEPARATING; } else { buffer += c; } } else if (state === ESCAPING) { if (c === quote || c === "\\") { buffer += c; state = STRINGS; } else { throw new Error('Parse error'); } } else if (state === IDENTIFIER) { if (!c) { names.push(buffer); break; } else if (identifierPattern.test(c)) { buffer += c; } else if (c === ',') { names.push(buffer); buffer = ''; state = PLAIN; } else if (spacePattern.test(c)) { names.push(buffer); buffer = ''; state = SEPARATING; } else { throw new Error('Parse error'); } } else if (state === SEPARATING) { if (!c) { break; } else if (c === ',') { state = PLAIN; } else if (spacePattern.test(c)) { } else { throw new Error('Parse error'); } } i++; } // result // ------ return names; }; // stringify // ========= // pattern // ------- var stringsPattern = /[^a-z0-9_-]/i; // --- var stringify = function(names, options) { // quote // ----- var quote = options && options.quote || '"'; if (quote !== '"' && quote !== "'") { throw new Error('Quote must be `\'` or `"`'); } var quotePattern = new RegExp(quote, 'g'); // stringify // --------- var safeNames = []; for (var i = 0; i < names.length; ++i) { var name = names[i]; if (stringsPattern.test(name)) { name = name .replace(/\\/g, "\\\\") .replace(quotePattern, "\\" + quote); name = quote + name + quote; } safeNames.push(name); } // result // ------ return safeNames.join(', '); }; // export // ====== module.exports = { parse: parse, stringify: stringify, }; },{}],10:[function(require,module,exports){ /** * A class to parse color values * @author Stoyan Stefanov <sstoo@gmail.com> * @link http://www.phpied.com/rgb-color-parser-in-javascript/ * @license Use it if you like it */ (function (global) { function RGBColor(color_string) { this.ok = false; // strip any leading # if (color_string.charAt(0) == '#') { // remove # if any color_string = color_string.substr(1,6); } color_string = color_string.replace(/ /g,''); color_string = color_string.toLowerCase(); // before getting into regexps, try simple matches // and overwrite the input var simple_colors = { aliceblue: 'f0f8ff', antiquewhite: 'faebd7', aqua: '00ffff', aquamarine: '7fffd4', azure: 'f0ffff', beige: 'f5f5dc', bisque: 'ffe4c4', black: '000000', blanchedalmond: 'ffebcd', blue: '0000ff', blueviolet: '8a2be2', brown: 'a52a2a', burlywood: 'deb887', cadetblue: '5f9ea0', chartreuse: '7fff00', chocolate: 'd2691e', coral: 'ff7f50', cornflowerblue: '6495ed', cornsilk: 'fff8dc', crimson: 'dc143c', cyan: '00ffff', darkblue: '00008b', darkcyan: '008b8b', darkgoldenrod: 'b8860b', darkgray: 'a9a9a9', darkgreen: '006400', darkkhaki: 'bdb76b', darkmagenta: '8b008b', darkolivegreen: '556b2f', darkorange: 'ff8c00', darkorchid: '9932cc', darkred: '8b0000', darksalmon: 'e9967a', darkseagreen: '8fbc8f', darkslateblue: '483d8b', darkslategray: '2f4f4f', darkturquoise: '00ced1', darkviolet: '9400d3', deeppink: 'ff1493', deepskyblue: '00bfff', dimgray: '696969', dodgerblue: '1e90ff', feldspar: 'd19275', firebrick: 'b22222', floralwhite: 'fffaf0', forestgreen: '228b22', fuchsia: 'ff00ff', gainsboro: 'dcdcdc', ghostwhite: 'f8f8ff', gold: 'ffd700', goldenrod: 'daa520', gray: '808080', green: '008000', greenyellow: 'adff2f', honeydew: 'f0fff0', hotpink: 'ff69b4', indianred : 'cd5c5c', indigo : '4b0082', ivory: 'fffff0', khaki: 'f0e68c', lavender: 'e6e6fa', lavenderblush: 'fff0f5', lawngreen: '7cfc00', lemonchiffon: 'fffacd', lightblue: 'add8e6', lightcoral: 'f08080', lightcyan: 'e0ffff', lightgoldenrodyellow: 'fafad2', lightgrey: 'd3d3d3', lightgreen: '90ee90', lightpink: 'ffb6c1', lightsalmon: 'ffa07a', lightseagreen: '20b2aa', lightskyblue: '87cefa', lightslateblue: '8470ff', lightslategray: '778899', lightsteelblue: 'b0c4de', lightyellow: 'ffffe0', lime: '00ff00', limegreen: '32cd32', linen: 'faf0e6', magenta: 'ff00ff', maroon: '800000', mediumaquamarine: '66cdaa', mediumblue: '0000cd', mediumorchid: 'ba55d3', mediumpurple: '9370d8', mediumseagreen: '3cb371', mediumslateblue: '7b68ee', mediumspringgreen: '00fa9a', mediumturquoise: '48d1cc', mediumvioletred: 'c71585', midnightblue: '191970', mintcream: 'f5fffa', mistyrose: 'ffe4e1', moccasin: 'ffe4b5', navajowhite: 'ffdead', navy: '000080', oldlace: 'fdf5e6', olive: '808000', olivedrab: '6b8e23', orange: 'ffa500', orangered: 'ff4500', orchid: 'da70d6', palegoldenrod: 'eee8aa', palegreen: '98fb98', paleturquoise: 'afeeee', palevioletred: 'd87093', papayawhip: 'ffefd5', peachpuff: 'ffdab9', peru: 'cd853f', pink: 'ffc0cb', plum: 'dda0dd', powderblue: 'b0e0e6', purple: '800080', red: 'ff0000', rosybrown: 'bc8f8f', royalblue: '4169e1', saddlebrown: '8b4513', salmon: 'fa8072', sandybrown: 'f4a460', seagreen: '2e8b57', seashell: 'fff5ee', sienna: 'a0522d', silver: 'c0c0c0', skyblue: '87ceeb', slateblue: '6a5acd', slategray: '708090', snow: 'fffafa', springgreen: '00ff7f', steelblue: '4682b4', tan: 'd2b48c', teal: '008080', thistle: 'd8bfd8', tomato: 'ff6347', turquoise: '40e0d0', violet: 'ee82ee', violetred: 'd02090', wheat: 'f5deb3', white: 'ffffff', whitesmoke: 'f5f5f5', yellow: 'ffff00', yellowgreen: '9acd32' }; for (var key in simple_colors) { if (color_string == key) { color_string = simple_colors[key]; } } // emd of simple type-in colors // array of color definition objects var color_defs = [ { re: /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/, example: ['rgb(123, 234, 45)', 'rgb(255,234,245)'], process: function (bits){ return [ parseInt(bits[1]), parseInt(bits[2]), parseInt(bits[3]) ]; } }, { re: /^(\w{2})(\w{2})(\w{2})$/, example: ['#00ff00', '336699'], process: function (bits){ return [ parseInt(bits[1], 16), parseInt(bits[2], 16), parseInt(bits[3], 16) ]; } }, { re: /^(\w{1})(\w{1})(\w{1})$/, example: ['#fb0', 'f0f'], process: function (bits){ return [ parseInt(bits[1] + bits[1], 16), parseInt(bits[2] + bits[2], 16), parseInt(bits[3] + bits[3], 16) ]; } } ]; // search through the definitions to find a match for (var i = 0; i < color_defs.length; i++) { var re = color_defs[i].re; var processor = color_defs[i].process; var bits = re.exec(color_string); if (bits) { var channels = processor(bits); this.r = channels[0]; this.g = channels[1]; this.b = channels[2]; this.ok = true; } } // validate/cleanup values this.r = (this.r < 0 || isNaN(this.r)) ? 0 : ((this.r > 255) ? 255 : this.r); this.g = (this.g < 0 || isNaN(this.g)) ? 0 : ((this.g > 255) ? 255 : this.g); this.b = (this.b < 0 || isNaN(this.b)) ? 0 : ((this.b > 255) ? 255 : this.b); // some getters this.toRGB = function () { return 'rgb(' + this.r + ', ' + this.g + ', ' + this.b + ')'; } this.toHex = function () { var r = this.r.toString(16); var g = this.g.toString(16); var b = this.b.toString(16); if (r.length == 1) r = '0' + r; if (g.length == 1) g = '0' + g; if (b.length == 1) b = '0' + b; return '#' + r + g + b; } // help this.getHelpXML = function () { var examples = new Array(); // add regexps for (var i = 0; i < color_defs.length; i++) { var example = color_defs[i].example; for (var j = 0; j < example.length; j++) { examples[examples.length] = example[j]; } } // add type-in colors for (var sc in simple_colors) { examples[examples.length] = sc;