/* MIT License Copyright (c) 2012 - 2021 @jonobr1 / http://jono.fyi Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var Two = (() => { var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2); var __publicField = (obj, key, value) => { __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); return value; }; // src/two.js var two_exports = {}; __export(two_exports, { default: () => Two }); // src/utils/path-commands.js var Commands = { move: "M", line: "L", curve: "C", arc: "A", close: "Z" }; // src/utils/math.js var math_exports = {}; __export(math_exports, { HALF_PI: () => HALF_PI, NumArray: () => NumArray, TWO_PI: () => TWO_PI, decomposeMatrix: () => decomposeMatrix, getComputedMatrix: () => getComputedMatrix, getPoT: () => getPoT, lerp: () => lerp, mod: () => mod, setMatrix: () => setMatrix, toFixed: () => toFixed }); // src/utils/root.js var root; if (typeof window !== "undefined") { root = window; } else if (typeof global !== "undefined") { root = global; } else if (typeof self !== "undefined") { root = self; } // src/utils/math.js var Matrix; var TWO_PI = Math.PI * 2; var HALF_PI = Math.PI * 0.5; function decomposeMatrix(matrix, b, c, d, e, f) { let a; if (arguments.length <= 1) { a = matrix.a; b = matrix.b; c = matrix.c; d = matrix.d; e = matrix.e; f = matrix.f; } else { a = matrix; } return { translateX: e, translateY: f, scaleX: Math.sqrt(a * a + b * b), scaleY: Math.sqrt(c * c + d * d), rotation: 180 * Math.atan2(b, a) / Math.PI }; } function setMatrix(matrix) { Matrix = matrix; } function getComputedMatrix(object, matrix) { matrix = matrix && matrix.identity() || new Matrix(); let parent = object; const matrices = []; while (parent && parent._matrix) { matrices.push(parent._matrix); parent = parent.parent; } matrices.reverse(); for (let i = 0; i < matrices.length; i++) { const m = matrices[i]; const e = m.elements; matrix.multiply( e[0], e[1], e[2], e[3], e[4], e[5], e[6], e[7], e[8], e[9] ); } return matrix; } function lerp(a, b, t) { return t * (b - a) + a; } var pots = [2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096]; function getPoT(value) { let i = 0; while (pots[i] && pots[i] < value) { i++; } return pots[i]; } function mod(v, l) { while (v < 0) { v += l; } return v % l; } var NumArray = root.Float32Array || Array; var floor = Math.floor; function toFixed(v) { return floor(v * 1e6) / 1e6; } // src/utils/curves.js var curves_exports = {}; __export(curves_exports, { Curve: () => Curve, getAnchorsFromArcData: () => getAnchorsFromArcData, getComponentOnCubicBezier: () => getComponentOnCubicBezier, getControlPoints: () => getControlPoints, getCurveBoundingBox: () => getCurveBoundingBox, getCurveFromPoints: () => getCurveFromPoints, getCurveLength: () => getCurveLength, getReflection: () => getReflection, integrate: () => integrate, subdivide: () => subdivide }); // src/events.js var Events = class { _events = {}; _bound = false; constructor() { } addEventListener(name, handler) { const list = this._events[name] || (this._events[name] = []); list.push(handler); this._bound = true; return this; } on() { return this.addEventListener.apply(this, arguments); } bind() { return this.addEventListener.apply(this, arguments); } removeEventListener(name, handler) { if (!this._events) { return this; } if (!name && !handler) { this._events = {}; this._bound = false; return this; } const names = name ? [name] : Object.keys(this._events); for (let i = 0, l = names.length; i < l; i++) { name = names[i]; let list = this._events[name]; if (list) { let events = []; if (handler) { for (let j = 0, k = list.length; j < k; j++) { let e = list[j]; e = e.handler ? e.handler : e; if (handler !== e) { events.push(e); } } } this._events[name] = events; } } return this; } off() { return this.removeEventListener.apply(this, arguments); } unbind() { return this.removeEventListener.apply(this, arguments); } dispatchEvent(name) { if (!this._events) { return this; } const args = Array.prototype.slice.call(arguments, 1); const events = this._events[name]; if (events) { for (let i = 0; i < events.length; i++) { events[i].call(this, ...args); } } return this; } trigger() { return this.dispatchEvent.apply(this, arguments); } listen(obj, name, handler) { const scope = this; if (obj) { e.obj = obj; e.name = name; e.handler = handler; obj.on(name, e); } function e() { handler.apply(scope, arguments); } return scope; } ignore(obj, name, handler) { obj.off(name, handler); return this; } }; __publicField(Events, "Types", { play: "play", pause: "pause", update: "update", render: "render", resize: "resize", change: "change", remove: "remove", insert: "insert", order: "order", load: "load" }); __publicField(Events, "Methods", [ "addEventListener", "on", "removeEventListener", "off", "unbind", "dispatchEvent", "trigger", "listen", "ignore" ]); // src/vector.js var proto = { x: { enumerable: true, get: function() { return this._x; }, set: function(v) { if (this._x !== v) { this._x = v; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } }, y: { enumerable: true, get: function() { return this._y; }, set: function(v) { if (this._y !== v) { this._y = v; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } } }; var _Vector = class extends Events { _x = 0; _y = 0; constructor(x = 0, y = 0) { super(); for (let prop in proto) { Object.defineProperty(this, prop, proto[prop]); } this.x = x; this.y = y; } static add(v1, v2) { return new _Vector(v1.x + v2.x, v1.y + v2.y); } static sub(v1, v2) { return new _Vector(v1.x - v2.x, v1.y - v2.y); } static subtract(v1, v2) { return _Vector.sub(v1, v2); } static ratioBetween(v1, v2) { return (v1.x * v2.x + v1.y * v2.y) / (v1.length() * v2.length()); } static angleBetween(v1, v2) { if (arguments.length >= 4) { const dx2 = arguments[0] - arguments[2]; const dy2 = arguments[1] - arguments[3]; return Math.atan2(dy2, dx2); } const dx = v1.x - v2.x; const dy = v1.y - v2.y; return Math.atan2(dy, dx); } static distanceBetween(v1, v2) { return Math.sqrt(_Vector.distanceBetweenSquared(v1, v2)); } static distanceBetweenSquared(v1, v2) { const dx = v1.x - v2.x; const dy = v1.y - v2.y; return dx * dx + dy * dy; } set(x, y) { this.x = x; this.y = y; return this; } copy(v) { this.x = v.x; this.y = v.y; return this; } clear() { this.x = 0; this.y = 0; return this; } clone() { return new _Vector(this.x, this.y); } add(x, y) { if (arguments.length <= 0) { return this; } else if (arguments.length <= 1) { if (typeof x === "number") { this.x += x; this.y += x; } else if (x && typeof x.x === "number" && typeof x.y === "number") { this.x += x.x; this.y += x.y; } } else { this.x += x; this.y += y; } return this; } addSelf(v) { return this.add.apply(this, arguments); } sub(x, y) { if (arguments.length <= 0) { return this; } else if (arguments.length <= 1) { if (typeof x === "number") { this.x -= x; this.y -= x; } else if (x && typeof x.x === "number" && typeof x.y === "number") { this.x -= x.x; this.y -= x.y; } } else { this.x -= x; this.y -= y; } return this; } subtract() { return this.sub.apply(this, arguments); } subSelf(v) { return this.sub.apply(this, arguments); } subtractSelf(v) { return this.sub.apply(this, arguments); } multiply(x, y) { if (arguments.length <= 0) { return this; } else if (arguments.length <= 1) { if (typeof x === "number") { this.x *= x; this.y *= x; } else if (x && typeof x.x === "number" && typeof x.y === "number") { this.x *= x.x; this.y *= x.y; } } else { this.x *= x; this.y *= y; } return this; } multiplySelf(v) { return this.multiply.apply(this, arguments); } multiplyScalar(s) { return this.multiply(s); } divide(x, y) { if (arguments.length <= 0) { return this; } else if (arguments.length <= 1) { if (typeof x === "number") { this.x /= x; this.y /= x; } else if (x && typeof x.x === "number" && typeof x.y === "number") { this.x /= x.x; this.y /= x.y; } } else { this.x /= x; this.y /= y; } if (isNaN(this.x)) { this.x = 0; } if (isNaN(this.y)) { this.y = 0; } return this; } divideSelf(v) { return this.divide.apply(this, arguments); } divideScalar(s) { return this.divide(s); } negate() { return this.multiply(-1); } dot(v) { return this.x * v.x + this.y * v.y; } length() { return Math.sqrt(this.lengthSquared()); } lengthSquared() { return this.x * this.x + this.y * this.y; } normalize() { return this.divideScalar(this.length()); } distanceTo(v) { return Math.sqrt(this.distanceToSquared(v)); } distanceToSquared(v) { const dx = this.x - v.x; const dy = this.y - v.y; return dx * dx + dy * dy; } setLength(l) { return this.normalize().multiplyScalar(l); } equals(v, eps) { eps = typeof eps === "undefined" ? 1e-4 : eps; return this.distanceTo(v) < eps; } lerp(v, t) { const x = (v.x - this.x) * t + this.x; const y = (v.y - this.y) * t + this.y; return this.set(x, y); } isZero(eps) { eps = typeof eps === "undefined" ? 1e-4 : eps; return this.length() < eps; } toString() { return this.x + ", " + this.y; } toObject() { return { x: this.x, y: this.y }; } rotate(radians) { const x = this.x; const y = this.y; const cos7 = Math.cos(radians); const sin7 = Math.sin(radians); this.x = x * cos7 - y * sin7; this.y = x * sin7 + y * cos7; return this; } }; var Vector = _Vector; __publicField(Vector, "zero", new _Vector()); __publicField(Vector, "left", new _Vector(-1, 0)); __publicField(Vector, "right", new _Vector(1, 0)); __publicField(Vector, "up", new _Vector(0, -1)); __publicField(Vector, "down", new _Vector(0, 1)); // src/anchor.js var Anchor = class extends Vector { controls = { left: new Vector(), right: new Vector() }; _command = Commands.move; _relative = true; _rx = 0; _ry = 0; _xAxisRotation = 0; _largeArcFlag = 0; _sweepFlag = 1; constructor(x = 0, y = 0, ax = 0, ay = 0, bx = 0, by = 0, command = Commands.move) { super(x, y); for (let prop in proto2) { Object.defineProperty(this, prop, proto2[prop]); } this.command = command; this.relative = true; const broadcast = Anchor.makeBroadcast(this); this.controls.left.set(ax, ay).addEventListener(Events.Types.change, broadcast); this.controls.right.set(bx, by).addEventListener(Events.Types.change, broadcast); } static makeBroadcast(scope) { return broadcast; function broadcast() { if (scope._bound) { scope.dispatchEvent(Events.Types.change); } } } copy(v) { this.x = v.x; this.y = v.y; if (typeof v.command === "string") { this.command = v.command; } if (v.controls) { if (v.controls.left) { this.controls.left.copy(v.controls.left); } if (v.controls.right) { this.controls.right.copy(v.controls.right); } } if (typeof v.relative === "boolean") { this.relative = v.relative; } if (typeof v.rx === "number") { this.rx = v.rx; } if (typeof v.ry === "number") { this.ry = v.ry; } if (typeof v.xAxisRotation === "number") { this.xAxisRotation = v.xAxisRotation; } if (typeof v.largeArcFlag === "number") { this.largeArcFlag = v.largeArcFlag; } if (typeof v.sweepFlag === "number") { this.sweepFlag = v.sweepFlag; } return this; } clone() { return new Anchor().copy(this); } toObject() { return { x: this.x, y: this.y, command: this.command, relative: this.relative, controls: { left: this.controls.left.toObject(), right: this.controls.right.toObject() }, rx: this.rx, ry: this.ry, xAxisRotation: this.xAxisRotation, largeArcFlag: this.largeArcFlag, sweepFlag: this.sweepFlag }; } toString() { return JSON.stringify(this.toObject()); } }; var proto2 = { command: { enumerable: true, get: function() { return this._command; }, set: function(command) { if (this._command !== command) { this._command = command; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } }, relative: { enumerable: true, get: function() { return this._relative; }, set: function(relative) { if (this._relative !== !!relative) { this._relative = !!relative; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } }, rx: { enumerable: true, get: function() { return this._rx; }, set: function(rx) { if (this._rx !== rx) { this._rx = rx; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } }, ry: { enumerable: true, get: function() { return this._ry; }, set: function(ry) { if (this._ry !== ry) { this._ry = ry; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } }, xAxisRotation: { enumerable: true, get: function() { return this._xAxisRotation; }, set: function(xAxisRotation) { if (this._xAxisRotation !== xAxisRotation) { this._xAxisRotation = xAxisRotation; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } }, largeArcFlag: { enumerable: true, get: function() { return this._largeArcFlag; }, set: function(largeArcFlag) { if (this._largeArcFlag !== largeArcFlag) { this._largeArcFlag = largeArcFlag; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } }, sweepFlag: { get: function() { return this._sweepFlag; }, set: function(sweepFlag) { if (this._sweepFlag !== sweepFlag) { this._sweepFlag = sweepFlag; if (this._bound) { this.dispatchEvent(Events.Types.change); } } } } }; // src/constants.js var count = 0; var Constants = { nextFrameID: null, Types: { webgl: "WebGLRenderer", svg: "SVGRenderer", canvas: "CanvasRenderer" }, Version: "v0.8.13", PublishDate: "2024-02-22T06:40:05.376Z", Identifier: "two-", Resolution: 12, AutoCalculateImportedMatrices: true, Instances: [], uniqueId: function() { return count++; } }; // src/utils/curves.js var Curve = { CollinearityEpsilon: Math.pow(10, -30), RecursionLimit: 16, CuspLimit: 0, Tolerance: { distance: 0.25, angle: 0, epsilon: Number.EPSILON }, abscissas: [ [0.5773502691896257], [0, 0.7745966692414834], [0.33998104358485626, 0.8611363115940526], [0, 0.5384693101056831, 0.906179845938664], [0.2386191860831969, 0.6612093864662645, 0.932469514203152], [0, 0.4058451513773972, 0.7415311855993945, 0.9491079123427585], [0.1834346424956498, 0.525532409916329, 0.7966664774136267, 0.9602898564975363], [0, 0.3242534234038089, 0.6133714327005904, 0.8360311073266358, 0.9681602395076261], [0.14887433898163122, 0.4333953941292472, 0.6794095682990244, 0.8650633666889845, 0.9739065285171717], [0, 0.26954315595234496, 0.5190961292068118, 0.7301520055740494, 0.8870625997680953, 0.978228658146057], [0.1252334085114689, 0.3678314989981802, 0.5873179542866175, 0.7699026741943047, 0.9041172563704749, 0.9815606342467192], [0, 0.2304583159551348, 0.44849275103644687, 0.6423493394403402, 0.8015780907333099, 0.9175983992229779, 0.9841830547185881], [0.10805494870734367, 0.31911236892788974, 0.5152486363581541, 0.6872929048116855, 0.827201315069765, 0.9284348836635735, 0.9862838086968123], [0, 0.20119409399743451, 0.3941513470775634, 0.5709721726085388, 0.7244177313601701, 0.8482065834104272, 0.937273392400706, 0.9879925180204854], [0.09501250983763744, 0.2816035507792589, 0.45801677765722737, 0.6178762444026438, 0.755404408355003, 0.8656312023878318, 0.9445750230732326, 0.9894009349916499] ], weights: [ [1], [0.8888888888888888, 0.5555555555555556], [0.6521451548625461, 0.34785484513745385], [0.5688888888888889, 0.47862867049936647, 0.23692688505618908], [0.46791393457269104, 0.3607615730481386, 0.17132449237917036], [0.4179591836734694, 0.3818300505051189, 0.27970539148927664, 0.1294849661688697], [0.362683783378362, 0.31370664587788727, 0.22238103445337448, 0.10122853629037626], [0.3302393550012598, 0.31234707704000286, 0.26061069640293544, 0.1806481606948574, 0.08127438836157441], [0.29552422471475287, 0.26926671930999635, 0.21908636251598204, 0.1494513491505806, 0.06667134430868814], [0.2729250867779006, 0.26280454451024665, 0.23319376459199048, 0.18629021092773426, 0.1255803694649046, 0.05566856711617366], [0.24914704581340277, 0.2334925365383548, 0.20316742672306592, 0.16007832854334622, 0.10693932599531843, 0.04717533638651183], [0.2325515532308739, 0.22628318026289723, 0.2078160475368885, 0.17814598076194574, 0.13887351021978725, 0.09212149983772845, 0.04048400476531588], [0.2152638534631578, 0.2051984637212956, 0.18553839747793782, 0.15720316715819355, 0.12151857068790319, 0.08015808715976021, 0.03511946033175186], [0.2025782419255613, 0.19843148532711158, 0.1861610000155622, 0.16626920581699392, 0.13957067792615432, 0.10715922046717194, 0.07036604748810812, 0.03075324199611727], [0.1894506104550685, 0.18260341504492358, 0.16915651939500254, 0.14959598881657674, 0.12462897125553388, 0.09515851168249279, 0.062253523938647894, 0.027152459411754096] ] }; function getComponentOnCubicBezier(t, a, b, c, d) { const k = 1 - t; return k * k * k * a + 3 * k * k * t * b + 3 * k * t * t * c + t * t * t * d; } function subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit) { limit = limit || Curve.RecursionLimit; const amount = limit + 1; if (Math.abs(x1 - x4) < 1e-3 && Math.abs(y1 - y4) < 1e-3) { return [new Anchor(x4, y4)]; } const result = []; for (let i = 0; i < amount; i++) { const t = i / amount; const x = getComponentOnCubicBezier(t, x1, x2, x3, x4); const y = getComponentOnCubicBezier(t, y1, y2, y3, y4); result.push(new Anchor(x, y)); } return result; } function getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit) { if (x1 === x2 && y1 === y2 && x3 === x4 && y3 === y4) { const dx = x4 - x1; const dy = y4 - y1; return Math.sqrt(dx * dx + dy * dy); } const ax = 9 * (x2 - x3) + 3 * (x4 - x1), bx = 6 * (x1 + x3) - 12 * x2, cx = 3 * (x2 - x1), ay = 9 * (y2 - y3) + 3 * (y4 - y1), by = 6 * (y1 + y3) - 12 * y2, cy = 3 * (y2 - y1); function integrand(t) { const dx = (ax * t + bx) * t + cx, dy = (ay * t + by) * t + cy; return Math.sqrt(dx * dx + dy * dy); } return integrate( integrand, 0, 1, limit || Curve.RecursionLimit ); } function getCurveBoundingBox(x1, y1, x2, y2, x3, y3, x4, y4) { const tvalues = []; const bounds = [[], []]; let a, b, c, t, t1, t2, b2ac, sqrtb2ac; for (let i = 0; i < 2; ++i) { if (i == 0) { b = 6 * x1 - 12 * x2 + 6 * x3; a = -3 * x1 + 9 * x2 - 9 * x3 + 3 * x4; c = 3 * x2 - 3 * x1; } else { b = 6 * y1 - 12 * y2 + 6 * y3; a = -3 * y1 + 9 * y2 - 9 * y3 + 3 * y4; c = 3 * y2 - 3 * y1; } if (Math.abs(a) < 1e-12) { if (Math.abs(b) < 1e-12) { continue; } t = -c / b; if (0 < t && t < 1) { tvalues.push(t); } continue; } b2ac = b * b - 4 * c * a; sqrtb2ac = Math.sqrt(b2ac); if (b2ac < 0) { continue; } t1 = (-b + sqrtb2ac) / (2 * a); if (0 < t1 && t1 < 1) { tvalues.push(t1); } t2 = (-b - sqrtb2ac) / (2 * a); if (0 < t2 && t2 < 1) { tvalues.push(t2); } } let j = tvalues.length; let jlen = j; let mt; while (j--) { t = tvalues[j]; mt = 1 - t; bounds[0][j] = mt * mt * mt * x1 + 3 * mt * mt * t * x2 + 3 * mt * t * t * x3 + t * t * t * x4; bounds[1][j] = mt * mt * mt * y1 + 3 * mt * mt * t * y2 + 3 * mt * t * t * y3 + t * t * t * y4; } bounds[0][jlen] = x1; bounds[1][jlen] = y1; bounds[0][jlen + 1] = x4; bounds[1][jlen + 1] = y4; bounds[0].length = bounds[1].length = jlen + 2; return { min: { x: Math.min.apply(0, bounds[0]), y: Math.min.apply(0, bounds[1]) }, max: { x: Math.max.apply(0, bounds[0]), y: Math.max.apply(0, bounds[1]) } }; } function integrate(f, a, b, n) { let x = Curve.abscissas[n - 2], w = Curve.weights[n - 2], A = 0.5 * (b - a), B = A + a, i = 0, m = n + 1 >> 1, sum = n & 1 ? w[i++] * f(B) : 0; while (i < m) { const Ax = A * x[i]; sum += w[i++] * (f(B + Ax) + f(B - Ax)); } return A * sum; } function getCurveFromPoints(points, closed2) { const l = points.length, last = l - 1; for (let i = 0; i < l; i++) { const point = points[i]; const prev = closed2 ? mod(i - 1, l) : Math.max(i - 1, 0); const next = closed2 ? mod(i + 1, l) : Math.min(i + 1, last); const a = points[prev]; const b = point; const c = points[next]; getControlPoints(a, b, c); b.command = i === 0 ? Commands.move : Commands.curve; } } function getControlPoints(a, b, c) { const a1 = Vector.angleBetween(a, b); const a2 = Vector.angleBetween(c, b); let d1 = Vector.distanceBetween(a, b); let d2 = Vector.distanceBetween(c, b); let mid = (a1 + a2) / 2; if (d1 < 1e-4 || d2 < 1e-4) { if (typeof b.relative === "boolean" && !b.relative) { b.controls.left.copy(b); b.controls.right.copy(b); } return b; } d1 *= 0.33; d2 *= 0.33; if (a2 < a1) { mid += HALF_PI; } else { mid -= HALF_PI; } b.controls.left.x = Math.cos(mid) * d1; b.controls.left.y = Math.sin(mid) * d1; mid -= Math.PI; b.controls.right.x = Math.cos(mid) * d2; b.controls.right.y = Math.sin(mid) * d2; if (typeof b.relative === "boolean" && !b.relative) { b.controls.left.x += b.x; b.controls.left.y += b.y; b.controls.right.x += b.x; b.controls.right.y += b.y; } return b; } function getReflection(a, b, relative) { return new Vector( 2 * a.x - (b.x + a.x) - (relative ? a.x : 0), 2 * a.y - (b.y + a.y) - (relative ? a.y : 0) ); } function getAnchorsFromArcData(center, xAxisRotation, rx, ry, ts, td, ccw) { const resolution = Constants.Resolution; const anchors = []; for (let i = 0; i < resolution; i++) { let pct = (i + 1) / resolution; if (ccw) { pct = 1 - pct; } const theta = pct * td + ts; const x = rx * Math.cos(theta); const y = ry * Math.sin(theta); const anchor2 = new Anchor(x, y); anchor2.command = Commands.line; anchors.push(anchor2); } } // src/utils/device-pixel-ratio.js var devicePixelRatio = root.devicePixelRatio || 1; function getBackingStoreRatio(ctx) { return ctx.webkitBackingStorePixelRatio || ctx.mozBackingStorePixelRatio || ctx.msBackingStorePixelRatio || ctx.oBackingStorePixelRatio || ctx.backingStorePixelRatio || 1; } function getRatio(ctx) { return devicePixelRatio / getBackingStoreRatio(ctx); } // src/utils/underscore.js var slice = Array.prototype.slice; function isArrayLike(collection) { if (collection === null || collection === void 0) return false; const length = collection.length; return typeof length == "number" && length >= 0 && length < 4294967296; } var _ = { isNaN: function(obj) { return typeof obj === "number" && obj !== +obj; }, isElement: function(obj) { return !!(obj && obj.nodeType === 1); }, isObject: function(obj) { const type = typeof obj; return type === "function" || type === "object" && !!obj; }, extend: function(base) { const sources = slice.call(arguments, 1); for (let i = 0; i < sources.length; i++) { const obj = sources[i]; for (let k in obj) { base[k] = obj[k]; } } return base; }, defaults: function(base) { const sources = slice.call(arguments, 1); for (let i = 0; i < sources.length; i++) { const obj = sources[i]; for (let k in obj) { if (base[k] === void 0) { base[k] = obj[k]; } } } return base; }, each: function(obj, iteratee, context) { const ctx = context || this; const keys = !isArrayLike(obj) && Object.keys(obj); const length = (keys || obj).length; for (let i = 0; i < length; i++) { const k = keys ? keys[i] : i; iteratee.call(ctx, obj[k], k, obj); } return obj; }, performance: root.performance && root.performance.now ? root.performance : Date }; // src/element.js var Element = class extends Events { _flagId = false; _flagClassName = false; _renderer = {}; _id = ""; _className = ""; classList = []; constructor() { super(); for (let prop in proto3) { Object.defineProperty(this, prop, proto3[prop]); } } flagReset() { this._flagId = this._flagClassName = false; } }; var proto3 = { renderer: { enumerable: false, get: function() { return this._renderer; } }, id: { enumerable: true, get: function() { return this._id; }, set: function(v) { const id = this._id; if (v === this._id) { return; } this._id = v; this._flagId = true; if (this.parent) { delete this.parent.children.ids[id]; this.parent.children.ids[this._id] = this; } } }, className: { enumerable: true, get: function() { return this._className; }, set: function(v) { if (this._className !== v) { this._flagClassName = true; this.classList = v.split(/\s+?/); this._className = v; } } } }; // src/matrix.js var cos = Math.cos; var sin = Math.sin; var tan = Math.tan; var array = []; var _Matrix = class extends Events { elements = new NumArray(9); manual = false; constructor(a, b, c, d, e, f) { super(); let elements = a; if (!Array.isArray(elements)) { elements = Array.prototype.slice.call(arguments); } this.identity(); if (elements.length > 0) { this.set(elements); } } static Multiply(A, B, C) { if (B.length <= 3) { const e = A; let x, y, z; const a = B[0] || 0, b = B[1] || 0, c = B[2] || 0; x = e[0] * a + e[1] * b + e[2] * c; y = e[3] * a + e[4] * b + e[5] * c; z = e[6] * a + e[7] * b + e[8] * c; return [x, y, z]; } const A0 = A[0], A1 = A[1], A2 = A[2]; const A3 = A[3], A4 = A[4], A5 = A[5]; const A6 = A[6], A7 = A[7], A8 = A[8]; const B0 = B[0], B1 = B[1], B2 = B[2]; const B3 = B[3], B4 = B[4], B5 = B[5]; const B6 = B[6], B7 = B[7], B8 = B[8]; C = C || new NumArray(9); C[0] = A0 * B0 + A1 * B3 + A2 * B6; C[1] = A0 * B1 + A1 * B4 + A2 * B7; C[2] = A0 * B2 + A1 * B5 + A2 * B8; C[3] = A3 * B0 + A4 * B3 + A5 * B6; C[4] = A3 * B1 + A4 * B4 + A5 * B7; C[5] = A3 * B2 + A4 * B5 + A5 * B8; C[6] = A6 * B0 + A7 * B3 + A8 * B6; C[7] = A6 * B1 + A7 * B4 + A8 * B7; C[8] = A6 * B2 + A7 * B5 + A8 * B8; return C; } set(a, b, c, d, e, f, g, h, i) { if (typeof b === "undefined") { const elements = a; a = elements[0]; b = elements[1]; c = elements[2]; d = elements[3]; e = elements[4]; f = elements[5]; g = elements[6]; h = elements[7]; i = elements[8]; } this.elements[0] = a; this.elements[1] = b; this.elements[2] = c; this.elements[3] = d; this.elements[4] = e; this.elements[5] = f; this.elements[6] = g; this.elements[7] = h; this.elements[8] = i; return this.trigger(Events.Types.change); } copy(m) { this.elements[0] = m.elements[0]; this.elements[1] = m.elements[1]; this.elements[2] = m.elements[2]; this.elements[3] = m.elements[3]; this.elements[4] = m.elements[4]; this.elements[5] = m.elements[5]; this.elements[6] = m.elements[6]; this.elements[7] = m.elements[7]; this.elements[8] = m.elements[8]; this.manual = m.manual; return this.trigger(Events.Types.change); } identity() { this.elements[0] = _Matrix.Identity[0]; this.elements[1] = _Matrix.Identity[1]; this.elements[2] = _Matrix.Identity[2]; this.elements[3] = _Matrix.Identity[3]; this.elements[4] = _Matrix.Identity[4]; this.elements[5] = _Matrix.Identity[5]; this.elements[6] = _Matrix.Identity[6]; this.elements[7] = _Matrix.Identity[7]; this.elements[8] = _Matrix.Identity[8]; return this.trigger(Events.Types.change); } multiply(a, b, c, d, e, f, g, h, i) { if (typeof b === "undefined") { this.elements[0] *= a; this.elements[1] *= a; this.elements[2] *= a; this.elements[3] *= a; this.elements[4] *= a; this.elements[5] *= a; this.elements[6] *= a; this.elements[7] *= a; this.elements[8] *= a; return this.trigger(Events.Types.change); } if (typeof c === "undefined") { c = 1; } if (typeof d === "undefined") { a = a || 0; b = b || 0; c = c || 0; e = this.elements; const x = e[0] * a + e[1] * b + e[2] * c; const y = e[3] * a + e[4] * b + e[5] * c; const z = e[6] * a + e[7] * b + e[8] * c; return [x, y, z]; } const A = this.elements; const B = [a, b, c, d, e, f, g, h, i]; const A0 = A[0], A1 = A[1], A2 = A[2]; const A3 = A[3], A4 = A[4], A5 = A[5]; const A6 = A[6], A7 = A[7], A8 = A[8]; const B0 = B[0], B1 = B[1], B2 = B[2]; const B3 = B[3], B4 = B[4], B5 = B[5]; const B6 = B[6], B7 = B[7], B8 = B[8]; this.elements[0] = A0 * B0 + A1 * B3 + A2 * B6; this.elements[1] = A0 * B1 + A1 * B4 + A2 * B7; this.elements[2] = A0 * B2 + A1 * B5 + A2 * B8; this.elements[3] = A3 * B0 + A4 * B3 + A5 * B6; this.elements[4] = A3 * B1 + A4 * B4 + A5 * B7; this.elements[5] = A3 * B2 + A4 * B5 + A5 * B8; this.elements[6] = A6 * B0 + A7 * B3 + A8 * B6; this.elements[7] = A6 * B1 + A7 * B4 + A8 * B7; this.elements[8] = A6 * B2 + A7 * B5 + A8 * B8; return this.trigger(Events.Types.change); } inverse(out) { const a = this.elements; out = out || new _Matrix(); const a00 = a[0], a01 = a[1], a02 = a[2]; const a10 = a[3], a11 = a[4], a12 = a[5]; const a20 = a[6], a21 = a[7], a22 = a[8]; const b01 = a22 * a11 - a12 * a21; const b11 = -a22 * a10 + a12 * a20; const b21 = a21 * a10 - a11 * a20; let det = a00 * b01 + a01 * b11 + a02 * b21; if (!det) { return null; } det = 1 / det; out.elements[0] = b01 * det; out.elements[1] = (-a22 * a01 + a02 * a21) * det; out.elements[2] = (a12 * a01 - a02 * a11) * det; out.elements[3] = b11 * det; out.elements[4] = (a22 * a00 - a02 * a20) * det; out.elements[5] = (-a12 * a00 + a02 * a10) * det; out.elements[6] = b21 * det; out.elements[7] = (-a21 * a00 + a01 * a20) * det; out.elements[8] = (a11 * a00 - a01 * a10) * det; return out; } scale(sx, sy) { const l = arguments.length; if (l <= 1) { sy = sx; } return this.multiply(sx, 0, 0, 0, sy, 0, 0, 0, 1); } rotate(Number2) { const c = cos(Number2); const s = sin(Number2); return this.multiply(c, -s, 0, s, c, 0, 0, 0, 1); } translate(x, y) { return this.multiply(1, 0, x, 0, 1, y, 0, 0, 1); } skewX(Number2) { const a = tan(Number2); return this.multiply(1, a, 0, 0, 1, 0, 0, 0, 1); } skewY(Number2) { const a = tan(Number2); return this.multiply(1, 0, 0, a, 1, 0, 0, 0, 1); } toString(fullMatrix) { array.length = 0; this.toTransformArray(fullMatrix, array); return array.map(toFixed).join(" "); } toTransformArray(fullMatrix, output) { const elements = this.elements; const hasOutput = !!output; const a = elements[0]; const b = elements[1]; const c = elements[2]; const d = elements[3]; const e = elements[4]; const f = elements[5]; if (fullMatrix) { const g = elements[6]; const h = elements[7]; const i = elements[8]; if (hasOutput) { output[0] = a; output[1] = d; output[2] = g; output[3] = b; output[4] = e; output[5] = h; output[6] = c; output[7] = f; output[8] = i; return; } return [ a, d, g, b, e, h, c, f, i ]; } if (hasOutput) { output[0] = a; output[1] = d; output[2] = b; output[3] = e; output[4] = c; output[5] = f; return; } return [ a, d, b, e, c, f ]; } toArray(fullMatrix, output) { const elements = this.elements; const hasOutput = !!output; const a = elements[0]; const b = elements[1]; const c = elements[2]; const d = elements[3]; const e = elements[4]; const f = elements[5]; if (fullMatrix) { const g = elements[6]; const h = elements[7]; const i = elements[8]; if (hasOutput) { output[0] = a; output[1] = b; output[2] = c; output[3] = d; output[4] = e; output[5] = f; output[6] = g; output[7] = h; output[8] = i; return; } return [ a, b, c, d, e, f, g, h, i ]; } if (hasOutput) { output[0] = a; output[1] = b; output[2] = c; output[3] = d; output[4] = e; output[5] = f; return; } return [ a, b, c, d, e, f ]; } toObject() { return { elements: this.toArray(true), manual: !!this.manual }; } clone() { return new _Matrix().copy(this); } }; var Matrix2 = _Matrix; __publicField(Matrix2, "Identity", [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ]); setMatrix(Matrix2); // src/shape.js var Shape = class extends Element { _flagMatrix = true; _flagScale = false; _matrix = null; _worldMatrix = null; _position = null; _rotation = 0; _scale = 1; _skewX = 0; _skewY = 0; constructor() { super(); for (let prop in proto4) { Object.defineProperty(this, prop, proto4[prop]); } this._renderer.flagMatrix = FlagMatrix.bind(this); this.isShape = true; this.id = Constants.Identifier + Constants.uniqueId(); this.matrix = new Matrix2(); this.worldMatrix = new Matrix2(); this.position = new Vector(); this.rotation = 0; this.scale = 1; this.skewX = 0; this.skewY = 0; } get renderer() { return this._renderer; } set renderer(v) { this._renderer = v; } get translation() { return proto4.position.get.apply(this, arguments); } set translation(v) { proto4.position.set.apply(this, arguments); } addTo(group) { group.add(this); return this; } remove() { if (!this.parent) { return this; } this.parent.remove(this); return this; } clone(parent) { const clone = new Shape(); clone.position.copy(this.position); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } if (parent) { parent.add(clone); } return clone._update(); } _update(bubbles) { if (!this._matrix.manual && this._flagMatrix) { this._matrix.identity().translate(this.position.x, this.position.y); if (this._scale instanceof Vector) { this._matrix.scale(this._scale.x, this._scale.y); } else { this._matrix.scale(this._scale); } this._matrix.rotate(this.rotation); this._matrix.skewX(this.skewX); this._matrix.skewY(this.skewY); } if (bubbles) { if (this.parent && this.parent._update) { this.parent._update(); } } return this; } flagReset() { this._flagMatrix = this._flagScale = false; super.flagReset.call(this); return this; } }; var proto4 = { position: { enumerable: true, get: function() { return this._position; }, set: function(v) { if (this._position) { this._position.unbind(Events.Types.change, this._renderer.flagMatrix); } this._position = v; this._position.bind(Events.Types.change, this._renderer.flagMatrix); FlagMatrix.call(this); } }, rotation: { enumerable: true, get: function() { return this._rotation; }, set: function(v) { this._rotation = v; this._flagMatrix = true; } }, scale: { enumerable: true, get: function() { return this._scale; }, set: function(v) { if (this._scale instanceof Vector) { this._scale.unbind(Events.Types.change, this._renderer.flagMatrix); } this._scale = v; if (this._scale instanceof Vector) { this._scale.bind(Events.Types.change, this._renderer.flagMatrix); } this._flagMatrix = true; this._flagScale = true; } }, skewX: { enumerable: true, get: function() { return this._skewX; }, set: function(v) { this._skewX = v; this._flagMatrix = true; } }, skewY: { enumerable: true, get: function() { return this._skewY; }, set: function(v) { this._skewY = v; this._flagMatrix = true; } }, matrix: { enumerable: true, get: function() { return this._matrix; }, set: function(v) { this._matrix = v; this._flagMatrix = true; } }, worldMatrix: { enumerable: true, get: function() { getComputedMatrix(this, this._worldMatrix); return this._worldMatrix; }, set: function(v) { this._worldMatrix = v; } } }; function FlagMatrix() { this._flagMatrix = true; } // src/collection.js var Collection = class extends Array { _events = new Events(); get _bound() { return this._events._bound; } set _bound(v) { this._events._bound = v; } addEventListener() { return this._events.addEventListener.apply(this, arguments); } on() { return this._events.on.apply(this, arguments); } bind() { return this._events.bind.apply(this, arguments); } removeEventListener() { return this._events.removeEventListener.apply(this, arguments); } off() { return this._events.off.apply(this, arguments); } unbind() { return this._events.unbind.apply(this, arguments); } dispatchEvent() { return this._events.dispatchEvent.apply(this, arguments); } trigger() { return this._events.trigger.apply(this, arguments); } listen() { return this._events.listen.apply(this, arguments); } ignore() { return this._events.ignore.apply(this, arguments); } constructor() { super(); if (arguments[0] && Array.isArray(arguments[0])) { if (arguments[0].length > 0) { this.push.apply(this, arguments[0]); } } else if (arguments.length > 0) { this.push.apply(this, arguments); } } pop() { const popped = super.pop.apply(this, arguments); this.trigger(Events.Types.remove, [popped]); return popped; } shift() { const shifted = super.shift.apply(this, arguments); this.trigger(Events.Types.remove, [shifted]); return shifted; } push() { const pushed = super.push.apply(this, arguments); this.trigger(Events.Types.insert, arguments); return pushed; } unshift() { const unshifted = super.unshift.apply(this, arguments); this.trigger(Events.Types.insert, arguments); return unshifted; } splice() { const spliced = super.splice.apply(this, arguments); this.trigger(Events.Types.remove, spliced); if (arguments.length > 2) { const inserted = this.slice(arguments[0], arguments[0] + arguments.length - 2); this.trigger(Events.Types.insert, inserted); this.trigger(Events.Types.order); } return spliced; } sort() { super.sort.apply(this, arguments); this.trigger(Events.Types.order); return this; } reverse() { super.reverse.apply(this, arguments); this.trigger(Events.Types.order); return this; } indexOf() { return super.indexOf.apply(this, arguments); } map(func, scope) { const results = []; for (let key = 0; key < this.length; key++) { const value = this[key]; let result; if (scope) { result = func.call(scope, value, key); } else { result = func(value, key); } results.push(result); } return results; } }; // src/children.js var Children = class extends Collection { ids = {}; constructor(children) { children = Array.isArray(children) ? children : Array.prototype.slice.call(arguments); super(children); this.attach(children); this.on(Events.Types.insert, this.attach); this.on(Events.Types.remove, this.detach); } attach(children) { for (let i = 0; i < children.length; i++) { const child = children[i]; if (child && child.id) { this.ids[child.id] = child; } } return this; } detach(children) { for (let i = 0; i < children.length; i++) { delete this.ids[children[i].id]; } return this; } }; // src/group.js var min = Math.min; var max = Math.max; var _Group = class extends Shape { _flagAdditions = false; _flagSubtractions = false; _flagOrder = false; _flagOpacity = true; _flagBeginning = false; _flagEnding = false; _flagLength = false; _flagMask = false; _fill = "#fff"; _stroke = "#000"; _linewidth = 1; _opacity = 1; _visible = true; _cap = "round"; _join = "round"; _miter = 4; _closed = true; _curved = false; _automatic = true; _beginning = 0; _ending = 1; _length = 0; _mask = null; constructor(children) { super(); for (let prop in proto5) { Object.defineProperty(this, prop, proto5[prop]); } this._renderer.type = "group"; this.additions = []; this.subtractions = []; this.children = Array.isArray(children) ? children : Array.prototype.slice.call(arguments); } static InsertChildren(children) { for (let i = 0; i < children.length; i++) { replaceParent.call(this, children[i], this); } } static RemoveChildren(children) { for (let i = 0; i < children.length; i++) { replaceParent.call(this, children[i]); } } static OrderChildren(children) { this._flagOrder = true; } clone(parent) { const clone = new _Group(); const children = this.children.map(function(child) { return child.clone(); }); clone.add(children); clone.opacity = this.opacity; if (this.mask) { clone.mask = this.mask; } clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.className = this.className; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } if (parent) { parent.add(clone); } return clone._update(); } toObject() { const result = { children: [], translation: this.translation.toObject(), rotation: this.rotation, scale: this.scale instanceof Vector ? this.scale.toObject() : this.scale, opacity: this.opacity, className: this.className, mask: this.mask ? this.mask.toObject() : null }; if (this.matrix.manual) { result.matrix = this.matrix.toObject(); } _.each(this.children, function(child, i) { result.children[i] = child.toObject(); }, this); return result; } corner() { const rect = this.getBoundingClientRect(true); for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.translation.x -= rect.left; child.translation.y -= rect.top; } if (this.mask) { this.mask.translation.x -= rect.left; this.mask.translation.y -= rect.top; } return this; } center() { const rect = this.getBoundingClientRect(true); const cx = rect.left + rect.width / 2 - this.translation.x; const cy = rect.top + rect.height / 2 - this.translation.y; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; if (child.isShape) { child.translation.x -= cx; child.translation.y -= cy; } } if (this.mask) { this.mask.translation.x -= cx; this.mask.translation.y -= cy; } return this; } getById(id) { let found = null; function search(node) { if (node.id === id) { return node; } else if (node.children) { for (let i = 0; i < node.children.length; i++) { found = search(node.children[i]); if (found) { return found; } } } return null; } return search(this); } getByClassName(className) { const found = []; function search(node) { if (Array.prototype.indexOf.call(node.classList, className) >= 0) { found.push(node); } if (node.children) { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; search(child); } } return found; } return search(this); } getByType(type) { const found = []; function search(node) { if (node instanceof type) { found.push(node); } if (node.children) { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; search(child); } } return found; } return search(this); } add(objects) { if (!(objects instanceof Array)) { objects = Array.prototype.slice.call(arguments); } else { objects = objects.slice(); } for (let i = 0; i < objects.length; i++) { const child = objects[i]; if (!(child && child.id)) { continue; } const index = Array.prototype.indexOf.call(this.children, child); if (index >= 0) { this.children.splice(index, 1); } this.children.push(child); } return this; } remove(objects) { const l = arguments.length, grandparent = this.parent; if (l <= 0 && grandparent) { grandparent.remove(this); return this; } if (!(objects instanceof Array)) { objects = Array.prototype.slice.call(arguments); } else { objects = objects.slice(); } for (let i = 0; i < objects.length; i++) { const object = objects[i]; if (!object || !this.children.ids[object.id]) { continue; } const index = this.children.indexOf(object); if (index >= 0) { this.children.splice(index, 1); } } return this; } getBoundingClientRect(shallow) { let rect, matrix, tc, lc, rc, bc; this._update(true); let left = Infinity, right = -Infinity, top = Infinity, bottom = -Infinity; const regex3 = /texture|gradient/i; matrix = shallow ? this.matrix : this.worldMatrix; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; if (!child.visible || regex3.test(child._renderer.type)) { continue; } rect = child.getBoundingClientRect(shallow); tc = typeof rect.top !== "number" || _.isNaN(rect.top) || !isFinite(rect.top); lc = typeof rect.left !== "number" || _.isNaN(rect.left) || !isFinite(rect.left); rc = typeof rect.right !== "number" || _.isNaN(rect.right) || !isFinite(rect.right); bc = typeof rect.bottom !== "number" || _.isNaN(rect.bottom) || !isFinite(rect.bottom); if (tc || lc || rc || bc) { continue; } if (shallow) { const [ax, ay] = matrix.multiply(rect.left, rect.top); const [bx, by] = matrix.multiply(rect.right, rect.top); const [cx, cy] = matrix.multiply(rect.left, rect.bottom); const [dx, dy] = matrix.multiply(rect.right, rect.bottom); top = min(ay, by, cy, dy); left = min(ax, bx, cx, dx); right = max(ax, bx, cx, dx); bottom = max(ay, by, cy, dy); } else { top = min(rect.top, top); left = min(rect.left, left); right = max(rect.right, right); bottom = max(rect.bottom, bottom); } } return { top, left, right, bottom, width: right - left, height: bottom - top }; } noFill() { this.children.forEach(function(child) { child.noFill(); }); return this; } noStroke() { this.children.forEach(function(child) { child.noStroke(); }); return this; } subdivide() { const args = arguments; this.children.forEach(function(child) { child.subdivide.apply(child, args); }); return this; } _update() { let i, l, child; if (this._flagBeginning || this._flagEnding) { const beginning = Math.min(this._beginning, this._ending); const ending = Math.max(this._beginning, this._ending); const length = this.length; let sum = 0; const bd = beginning * length; const ed = ending * length; for (i = 0; i < this.children.length; i++) { child = this.children[i]; l = child.length; if (bd > sum + l) { child.beginning = 1; child.ending = 1; } else if (ed < sum) { child.beginning = 0; child.ending = 0; } else if (bd > sum && bd < sum + l) { child.beginning = (bd - sum) / l; child.ending = 1; } else if (ed > sum && ed < sum + l) { child.beginning = 0; child.ending = (ed - sum) / l; } else { child.beginning = 0; child.ending = 1; } sum += l; } } return super._update.apply(this, arguments); } flagReset() { if (this._flagAdditions) { this.additions.length = 0; this._flagAdditions = false; } if (this._flagSubtractions) { this.subtractions.length = 0; this._flagSubtractions = false; } this._flagOrder = this._flagMask = this._flagOpacity = this._flagBeginning = this._flagEnding = false; super.flagReset.call(this); return this; } }; var Group = _Group; __publicField(Group, "Children", Children); __publicField(Group, "Properties", [ "fill", "stroke", "linewidth", "cap", "join", "miter", "closed", "curved", "automatic" ]); var proto5 = { visible: { enumerable: true, get: function() { return this._visible; }, set: function(v) { this._flagVisible = this._visible !== v || this._flagVisible; this._visible = v; } }, opacity: { enumerable: true, get: function() { return this._opacity; }, set: function(v) { this._flagOpacity = this._opacity !== v || this._flagOpacity; this._opacity = v; } }, beginning: { enumerable: true, get: function() { return this._beginning; }, set: function(v) { this._flagBeginning = this._beginning !== v || this._flagBeginning; this._beginning = v; } }, ending: { enumerable: true, get: function() { return this._ending; }, set: function(v) { this._flagEnding = this._ending !== v || this._flagEnding; this._ending = v; } }, length: { enumerable: true, get: function() { if (this._flagLength || this._length <= 0) { this._length = 0; if (!this.children) { return this._length; } for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; this._length += child.length; } } return this._length; } }, fill: { enumerable: true, get: function() { return this._fill; }, set: function(v) { this._fill = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.fill = v; } } }, stroke: { enumerable: true, get: function() { return this._stroke; }, set: function(v) { this._stroke = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.stroke = v; } } }, linewidth: { enumerable: true, get: function() { return this._linewidth; }, set: function(v) { this._linewidth = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.linewidth = v; } } }, join: { enumerable: true, get: function() { return this._join; }, set: function(v) { this._join = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.join = v; } } }, miter: { enumerable: true, get: function() { return this._miter; }, set: function(v) { this._miter = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.miter = v; } } }, cap: { enumerable: true, get: function() { return this._cap; }, set: function(v) { this._cap = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.cap = v; } } }, closed: { enumerable: true, get: function() { return this._closed; }, set: function(v) { this._closed = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.closed = v; } } }, curved: { enumerable: true, get: function() { return this._curved; }, set: function(v) { this._curved = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.curved = v; } } }, automatic: { enumerable: true, get: function() { return this._automatic; }, set: function(v) { this._automatic = v; for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; child.automatic = v; } } }, children: { enumerable: true, get: function() { return this._children; }, set: function(children) { const insertChildren = Group.InsertChildren.bind(this); const removeChildren = Group.RemoveChildren.bind(this); const orderChildren = Group.OrderChildren.bind(this); if (this._children) { this._children.unbind(); if (this._children.length > 0) { removeChildren(this._children); } } this._children = new Children(children); this._children.bind(Events.Types.insert, insertChildren); this._children.bind(Events.Types.remove, removeChildren); this._children.bind(Events.Types.order, orderChildren); if (children.length > 0) { insertChildren(children); } } }, mask: { enumerable: true, get: function() { return this._mask; }, set: function(v) { this._mask = v; this._flagMask = true; if (_.isObject(v) && !v.clip) { v.clip = true; } } } }; function replaceParent(child, newParent) { const parent = child.parent; let index; if (parent === newParent) { add(); return; } if (parent && parent.children.ids[child.id]) { index = Array.prototype.indexOf.call(parent.children, child); parent.children.splice(index, 1); splice(); } if (newParent) { add(); return; } splice(); if (parent._flagAdditions && parent.additions.length === 0) { parent._flagAdditions = false; } if (parent._flagSubtractions && parent.subtractions.length === 0) { parent._flagSubtractions = false; } delete child.parent; function add() { if (newParent.subtractions.length > 0) { index = Array.prototype.indexOf.call(newParent.subtractions, child); if (index >= 0) { newParent.subtractions.splice(index, 1); } } if (newParent.additions.length > 0) { index = Array.prototype.indexOf.call(newParent.additions, child); if (index >= 0) { newParent.additions.splice(index, 1); } } child.parent = newParent; newParent.additions.push(child); newParent._flagAdditions = true; } function splice() { index = Array.prototype.indexOf.call(parent.additions, child); if (index >= 0) { parent.additions.splice(index, 1); } index = Array.prototype.indexOf.call(parent.subtractions, child); if (index < 0) { parent.subtractions.push(child); parent._flagSubtractions = true; } } } // src/renderers/canvas.js var emptyArray = []; var max2 = Math.max; var min2 = Math.min; var abs = Math.abs; var sin2 = Math.sin; var cos2 = Math.cos; var acos = Math.acos; var sqrt = Math.sqrt; var canvas = { isHidden: /(undefined|none|transparent)/i, alignments: { left: "start", middle: "center", right: "end" }, baselines: { top: "top", middle: "middle", bottom: "bottom", baseline: "alphabetic" }, shim: function(elem, name) { elem.tagName = elem.nodeName = name || "canvas"; elem.nodeType = 1; elem.getAttribute = function(prop) { return this[prop]; }; elem.setAttribute = function(prop, val) { this[prop] = val; return this; }; return elem; }, group: { renderChild: function(child) { canvas[child._renderer.type].render.call(child, this.ctx, true, this.clip); }, render: function(ctx) { if (!this._visible) { return this; } this._update(); const matrix = this._matrix.elements; const parent = this.parent; this._renderer.opacity = this._opacity * (parent && parent._renderer ? parent._renderer.opacity : 1); const mask = this._mask; const defaultMatrix = isDefaultMatrix(matrix); const shouldIsolate = !defaultMatrix || !!mask; if (!this._renderer.context) { this._renderer.context = {}; } this._renderer.context.ctx = ctx; if (shouldIsolate) { ctx.save(); if (!defaultMatrix) { ctx.transform( matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5] ); } } if (mask) { canvas[mask._renderer.type].render.call(mask, ctx, true); } if (this._opacity > 0 && this._scale !== 0) { for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; canvas[child._renderer.type].render.call(child, ctx); } } if (shouldIsolate) { ctx.restore(); } return this.flagReset(); } }, path: { render: function(ctx, forced, parentClipped) { let matrix, stroke, linewidth, fill, opacity, visible, cap, join, miter, closed2, commands, length, last, prev, a, b, c, d, ux, uy, vx, vy, ar, bl, br, cl, x, y, mask, clip, defaultMatrix, isOffset, dashes, po; po = this.parent && this.parent._renderer ? this.parent._renderer.opacity : 1; mask = this._mask; clip = this._clip; opacity = this._opacity * (po || 1); visible = this._visible; if (!forced && (!visible || clip || opacity === 0)) { return this; } this._update(); matrix = this._matrix.elements; stroke = this._stroke; linewidth = this._linewidth; fill = this._fill; cap = this._cap; join = this._join; miter = this._miter; closed2 = this._closed; commands = this._renderer.vertices; length = commands.length; last = length - 1; defaultMatrix = isDefaultMatrix(matrix); dashes = this.dashes; if (!defaultMatrix) { ctx.save(); ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); } if (mask) { canvas[mask._renderer.type].render.call(mask, ctx, true); } if (fill) { if (typeof fill === "string") { ctx.fillStyle = fill; } else { canvas[fill._renderer.type].render.call(fill, ctx, this); ctx.fillStyle = fill._renderer.effect; } } if (stroke) { if (typeof stroke === "string") { ctx.strokeStyle = stroke; } else { canvas[stroke._renderer.type].render.call(stroke, ctx, this); ctx.strokeStyle = stroke._renderer.effect; } if (linewidth) { ctx.lineWidth = linewidth; } if (miter) { ctx.miterLimit = miter; } if (join) { ctx.lineJoin = join; } if (!closed2 && cap) { ctx.lineCap = cap; } } if (typeof opacity === "number") { ctx.globalAlpha = opacity; } if (dashes && dashes.length > 0) { ctx.lineDashOffset = dashes.offset || 0; ctx.setLineDash(dashes); } ctx.beginPath(); let rx, ry, xAxisRotation, largeArcFlag, sweepFlag, ax, ay; for (let i = 0; i < length; i++) { b = commands[i]; x = b.x; y = b.y; switch (b.command) { case Commands.close: ctx.closePath(); break; case Commands.arc: rx = b.rx; ry = b.ry; xAxisRotation = b.xAxisRotation; largeArcFlag = b.largeArcFlag; sweepFlag = b.sweepFlag; prev = closed2 ? mod(i - 1, length) : max2(i - 1, 0); a = commands[prev]; ax = a.x; ay = a.y; canvas.renderSvgArcCommand( ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y ); break; case Commands.curve: prev = closed2 ? mod(i - 1, length) : Math.max(i - 1, 0); a = commands[prev]; ar = a.controls && a.controls.right || Vector.zero; bl = b.controls && b.controls.left || Vector.zero; if (a._relative) { vx = ar.x + a.x; vy = ar.y + a.y; } else { vx = ar.x; vy = ar.y; } if (b._relative) { ux = bl.x + b.x; uy = bl.y + b.y; } else { ux = bl.x; uy = bl.y; } ctx.bezierCurveTo(vx, vy, ux, uy, x, y); if (i >= last && closed2) { c = d; br = b.controls && b.controls.right || Vector.zero; cl = c.controls && c.controls.left || Vector.zero; if (b._relative) { vx = br.x + b.x; vy = br.y + b.y; } else { vx = br.x; vy = br.y; } if (c._relative) { ux = cl.x + c.x; uy = cl.y + c.y; } else { ux = cl.x; uy = cl.y; } x = c.x; y = c.y; ctx.bezierCurveTo(vx, vy, ux, uy, x, y); } break; case Commands.line: ctx.lineTo(x, y); break; case Commands.move: d = b; ctx.moveTo(x, y); break; } } if (closed2) { ctx.closePath(); } if (!clip && !parentClipped) { if (!canvas.isHidden.test(fill)) { isOffset = fill._renderer && fill._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -fill._renderer.offset.x, -fill._renderer.offset.y ); ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y); } ctx.fill(); if (isOffset) { ctx.restore(); } } if (!canvas.isHidden.test(stroke)) { isOffset = stroke._renderer && stroke._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -stroke._renderer.offset.x, -stroke._renderer.offset.y ); ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y); ctx.lineWidth = linewidth / stroke._renderer.scale.x; } ctx.stroke(); if (isOffset) { ctx.restore(); } } } if (!defaultMatrix) { ctx.restore(); } if (clip && !parentClipped) { ctx.clip(); } if (dashes && dashes.length > 0) { ctx.setLineDash(emptyArray); } return this.flagReset(); } }, points: { render: function(ctx, forced, parentClipped) { let me, stroke, linewidth, fill, opacity, visible, size, commands, length, b, x, y, defaultMatrix, isOffset, dashes, po; po = this.parent && this.parent._renderer ? this.parent._renderer.opacity : 1; opacity = this._opacity * (po || 1); visible = this._visible; if (!forced && (!visible || opacity === 0)) { return this; } this._update(); me = this._matrix.elements; stroke = this._stroke; linewidth = this._linewidth; fill = this._fill; commands = this._renderer.collection; length = commands.length; defaultMatrix = isDefaultMatrix(me); dashes = this.dashes; size = this._size; if (!defaultMatrix) { ctx.save(); ctx.transform(me[0], me[3], me[1], me[4], me[2], me[5]); } if (fill) { if (typeof fill === "string") { ctx.fillStyle = fill; } else { canvas[fill._renderer.type].render.call(fill, ctx, this); ctx.fillStyle = fill._renderer.effect; } } if (stroke) { if (typeof stroke === "string") { ctx.strokeStyle = stroke; } else { canvas[stroke._renderer.type].render.call(stroke, ctx, this); ctx.strokeStyle = stroke._renderer.effect; } if (linewidth) { ctx.lineWidth = linewidth; } } if (typeof opacity === "number") { ctx.globalAlpha = opacity; } if (dashes && dashes.length > 0) { ctx.lineDashOffset = dashes.offset || 0; ctx.setLineDash(dashes); } ctx.beginPath(); let radius = size * 0.5, m; if (!this._sizeAttenuation) { m = this.worldMatrix.elements; m = decomposeMatrix(m[0], m[3], m[1], m[4], m[2], m[5]); radius /= Math.max(m.scaleX, m.scaleY); } for (let i = 0; i < length; i++) { b = commands[i]; x = b.x; y = b.y; ctx.moveTo(x + radius, y); ctx.arc(x, y, radius, 0, TWO_PI); } if (!parentClipped) { if (!canvas.isHidden.test(fill)) { isOffset = fill._renderer && fill._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -fill._renderer.offset.x, -fill._renderer.offset.y ); ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y); } ctx.fill(); if (isOffset) { ctx.restore(); } } if (!canvas.isHidden.test(stroke)) { isOffset = stroke._renderer && stroke._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -stroke._renderer.offset.x, -stroke._renderer.offset.y ); ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y); ctx.lineWidth = linewidth / stroke._renderer.scale.x; } ctx.stroke(); if (isOffset) { ctx.restore(); } } } if (!defaultMatrix) { ctx.restore(); } if (dashes && dashes.length > 0) { ctx.setLineDash(emptyArray); } return this.flagReset(); } }, text: { render: function(ctx, forced, parentClipped) { const po = this.parent && this.parent._renderer ? this.parent._renderer.opacity : 1; const opacity = this._opacity * po; const visible = this._visible; const mask = this._mask; const clip = this._clip; if (!forced && (!visible || clip || opacity === 0)) { return this; } this._update(); const matrix = this._matrix.elements; const stroke = this._stroke; const linewidth = this._linewidth; const fill = this._fill; const decoration = this._decoration; const direction = this._direction; const defaultMatrix = isDefaultMatrix(matrix); const isOffset = fill._renderer && fill._renderer.offset && stroke._renderer && stroke._renderer.offset; const dashes = this.dashes; const alignment = canvas.alignments[this._alignment] || this._alignment; const baseline = canvas.baselines[this._baseline] || this._baseline; let a, b, c, d, e, sx, sy, x1, y1, x2, y2; if (!defaultMatrix) { ctx.save(); ctx.transform(matrix[0], matrix[3], matrix[1], matrix[4], matrix[2], matrix[5]); } if (mask) { canvas[mask._renderer.type].render.call(mask, ctx, true); } if (!isOffset) { ctx.font = [this._style, this._weight, this._size + "px/" + this._leading + "px", this._family].join(" "); } ctx.textAlign = alignment; ctx.textBaseline = baseline; ctx.direction = direction; if (fill) { if (typeof fill === "string") { ctx.fillStyle = fill; } else { canvas[fill._renderer.type].render.call(fill, ctx, this); ctx.fillStyle = fill._renderer.effect; } } if (stroke) { if (typeof stroke === "string") { ctx.strokeStyle = stroke; } else { canvas[stroke._renderer.type].render.call(stroke, ctx, this); ctx.strokeStyle = stroke._renderer.effect; } if (linewidth) { ctx.lineWidth = linewidth; } } if (typeof opacity === "number") { ctx.globalAlpha = opacity; } if (dashes && dashes.length > 0) { ctx.lineDashOffset = dashes.offset || 0; ctx.setLineDash(dashes); } if (!clip && !parentClipped) { if (!canvas.isHidden.test(fill)) { if (fill._renderer && fill._renderer.offset) { sx = fill._renderer.scale.x; sy = fill._renderer.scale.y; ctx.save(); ctx.translate( -fill._renderer.offset.x, -fill._renderer.offset.y ); ctx.scale(sx, sy); a = this._size / fill._renderer.scale.y; b = this._leading / fill._renderer.scale.y; ctx.font = [ this._style, this._weight, a + "px/", b + "px", this._family ].join(" "); c = fill._renderer.offset.x / fill._renderer.scale.x; d = fill._renderer.offset.y / fill._renderer.scale.y; ctx.fillText(this.value, c, d); ctx.restore(); } else { ctx.fillText(this.value, 0, 0); } } if (!canvas.isHidden.test(stroke)) { if (stroke._renderer && stroke._renderer.offset) { sx = stroke._renderer.scale.x; sy = stroke._renderer.scale.y; ctx.save(); ctx.translate( -stroke._renderer.offset.x, -stroke._renderer.offset.y ); ctx.scale(sx, sy); a = this._size / stroke._renderer.scale.y; b = this._leading / stroke._renderer.scale.y; ctx.font = [ this._style, this._weight, a + "px/", b + "px", this._family ].join(" "); c = stroke._renderer.offset.x / stroke._renderer.scale.x; d = stroke._renderer.offset.y / stroke._renderer.scale.y; e = linewidth / stroke._renderer.scale.x; ctx.lineWidth = e; ctx.strokeText(this.value, c, d); ctx.restore(); } else { ctx.strokeText(this.value, 0, 0); } } } if (/(underline|strikethrough)/i.test(decoration)) { const metrics = ctx.measureText(this.value); let scalar = 1; switch (decoration) { case "underline": y1 = metrics.actualBoundingBoxDescent; y2 = metrics.actualBoundingBoxDescent; break; case "strikethrough": y1 = 0; y2 = 0; scalar = 0.5; break; } switch (baseline) { case "top": y1 += this._size * scalar; y2 += this._size * scalar; break; case "baseline": case "bottom": y1 -= this._size * scalar; y2 -= this._size * scalar; break; } switch (alignment) { case "left": case "start": x1 = 0; x2 = metrics.width; break; case "right": case "end": x1 = -metrics.width; x2 = 0; break; default: x1 = -metrics.width / 2; x2 = metrics.width / 2; } ctx.lineWidth = Math.max(Math.floor(this._size / 15), 1); ctx.strokeStyle = ctx.fillStyle; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); } if (!defaultMatrix) { ctx.restore(); } if (clip && !parentClipped) { ctx.clip(); } if (dashes && dashes.length > 0) { ctx.setLineDash(emptyArray); } return this.flagReset(); } }, "linear-gradient": { render: function(ctx, parent) { if (!parent) { return; } this._update(); if (!this._renderer.effect || this._flagEndPoints || this._flagStops || this._flagUnits) { let rect; let lx = this.left._x; let ly = this.left._y; let rx = this.right._x; let ry = this.right._y; if (/objectBoundingBox/i.test(this._units)) { rect = parent.getBoundingClientRect(true); lx = (lx - 0.5) * rect.width; ly = (ly - 0.5) * rect.height; rx = (rx - 0.5) * rect.width; ry = (ry - 0.5) * rect.height; } this._renderer.effect = ctx.createLinearGradient(lx, ly, rx, ry); for (let i = 0; i < this.stops.length; i++) { const stop = this.stops[i]; this._renderer.effect.addColorStop(stop._offset, stop._color); } } return this.flagReset(); } }, "radial-gradient": { render: function(ctx, parent) { if (!parent) { return; } this._update(); if (!this._renderer.effect || this._flagCenter || this._flagFocal || this._flagRadius || this._flagStops || this._flagUnits) { let rect; let cx = this.center._x; let cy = this.center._y; let fx = this.focal._x; let fy = this.focal._y; let radius = this._radius; if (/objectBoundingBox/i.test(this._units)) { rect = parent.getBoundingClientRect(true); cx = cx * rect.width * 0.5; cy = cy * rect.height * 0.5; fx = fx * rect.width * 0.5; fy = fy * rect.height * 0.5; radius *= Math.min(rect.width, rect.height) * 0.5; } this._renderer.effect = ctx.createRadialGradient( cx, cy, 0, fx, fy, radius ); for (let i = 0; i < this.stops.length; i++) { const stop = this.stops[i]; this._renderer.effect.addColorStop(stop._offset, stop._color); } } return this.flagReset(); } }, texture: { render: function(ctx) { this._update(); const image = this.image; if (!this._renderer.effect || (this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded) { this._renderer.effect = ctx.createPattern(this.image, this._repeat); } if (this._flagOffset || this._flagLoaded || this._flagScale) { if (!(this._renderer.offset instanceof Vector)) { this._renderer.offset = new Vector(); } this._renderer.offset.x = -this._offset.x; this._renderer.offset.y = -this._offset.y; if (image) { this._renderer.offset.x += image.width / 2; this._renderer.offset.y += image.height / 2; if (this._scale instanceof Vector) { this._renderer.offset.x *= this._scale.x; this._renderer.offset.y *= this._scale.y; } else { this._renderer.offset.x *= this._scale; this._renderer.offset.y *= this._scale; } } } if (this._flagScale || this._flagLoaded) { if (!(this._renderer.scale instanceof Vector)) { this._renderer.scale = new Vector(); } if (this._scale instanceof Vector) { this._renderer.scale.copy(this._scale); } else { this._renderer.scale.set(this._scale, this._scale); } } return this.flagReset(); } }, renderSvgArcCommand: function(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y) { xAxisRotation = xAxisRotation * Math.PI / 180; rx = abs(rx); ry = abs(ry); const dx2 = (ax - x) / 2; const dy2 = (ay - y) / 2; const x1p = cos2(xAxisRotation) * dx2 + sin2(xAxisRotation) * dy2; const y1p = -sin2(xAxisRotation) * dx2 + cos2(xAxisRotation) * dy2; const x1ps = x1p * x1p; const y1ps = y1p * y1p; let rxs = rx * rx; let rys = ry * ry; const cr = x1ps / rxs + y1ps / rys; if (cr > 1) { const s = sqrt(cr); rx = s * rx; ry = s * ry; rxs = rx * rx; rys = ry * ry; } const dq = rxs * y1ps + rys * x1ps; const pq = (rxs * rys - dq) / dq; let q = sqrt(max2(0, pq)); if (largeArcFlag === sweepFlag) q = -q; const cxp = q * rx * y1p / ry; const cyp = -q * ry * x1p / rx; const cx = cos2(xAxisRotation) * cxp - sin2(xAxisRotation) * cyp + (ax + x) / 2; const cy = sin2(xAxisRotation) * cxp + cos2(xAxisRotation) * cyp + (ay + y) / 2; const startAngle = svgAngle(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry); const delta = svgAngle( (x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry ) % TWO_PI; const endAngle = startAngle + delta; const clockwise = sweepFlag === 0; renderArcEstimate( ctx, cx, cy, rx, ry, startAngle, endAngle, clockwise, xAxisRotation ); } }; var Renderer = class extends Events { constructor(params) { super(); const smoothing = params.smoothing !== false; this.domElement = params.domElement || document.createElement("canvas"); this.ctx = this.domElement.getContext("2d"); this.overdraw = params.overdraw || false; if (typeof this.ctx.imageSmoothingEnabled !== "undefined") { this.ctx.imageSmoothingEnabled = smoothing; } this.scene = new Group(); this.scene.parent = this; } setSize(width, height, ratio) { this.width = width; this.height = height; this.ratio = typeof ratio === "undefined" ? getRatio(this.ctx) : ratio; this.domElement.width = width * this.ratio; this.domElement.height = height * this.ratio; if (this.domElement.style) { _.extend(this.domElement.style, { width: width + "px", height: height + "px" }); } return this.trigger(Events.Types.resize, width, height, ratio); } render() { const isOne = this.ratio === 1; if (!isOne) { this.ctx.save(); this.ctx.scale(this.ratio, this.ratio); } if (!this.overdraw) { this.ctx.clearRect(0, 0, this.width, this.height); } canvas.group.render.call(this.scene, this.ctx); if (!isOne) { this.ctx.restore(); } return this; } }; __publicField(Renderer, "Utils", canvas); function renderArcEstimate(ctx, ox, oy, rx, ry, startAngle, endAngle, clockwise, xAxisRotation) { const delta = endAngle - startAngle; const epsilon = Curve.Tolerance.epsilon; const samePoints = Math.abs(delta) < epsilon; let deltaAngle = mod(delta, TWO_PI); if (deltaAngle < epsilon) { if (samePoints) { deltaAngle = 0; } else { deltaAngle = TWO_PI; } } if (clockwise === true && !samePoints) { if (deltaAngle === TWO_PI) { deltaAngle = -TWO_PI; } else { deltaAngle = deltaAngle - TWO_PI; } } for (let i = 0; i < Constants.Resolution; i++) { const t = i / (Constants.Resolution - 1); const angle = startAngle + t * deltaAngle; let x = ox + rx * Math.cos(angle); let y = oy + ry * Math.sin(angle); if (xAxisRotation !== 0) { const cos7 = Math.cos(xAxisRotation); const sin7 = Math.sin(xAxisRotation); const tx = x - ox; const ty = y - oy; x = tx * cos7 - ty * sin7 + ox; y = tx * sin7 + ty * cos7 + oy; } ctx.lineTo(x, y); } } function svgAngle(ux, uy, vx, vy) { const dot = ux * vx + uy * vy; const len = sqrt(ux * ux + uy * uy) * sqrt(vx * vx + vy * vy); let ang = acos(max2(-1, min2(1, dot / len))); if (ux * vy - uy * vx < 0) { ang = -ang; } return ang; } function isDefaultMatrix(m) { return m[0] == 1 && m[3] == 0 && m[1] == 0 && m[4] == 1 && m[2] == 0 && m[5] == 0; } // src/utils/canvas-shim.js var CanvasShim = { Image: null, isHeadless: false, shim: function(canvas3, Image) { Renderer.Utils.shim(canvas3); if (typeof Image !== "undefined") { CanvasShim.Image = Image; } CanvasShim.isHeadless = true; return canvas3; } }; // src/utils/dom.js var dom = { hasEventListeners: typeof root.addEventListener === "function", bind: function(elem, event, func, bool) { if (this.hasEventListeners) { elem.addEventListener(event, func, !!bool); } else { elem.attachEvent("on" + event, func); } return dom; }, unbind: function(elem, event, func, bool) { if (dom.hasEventListeners) { elem.removeEventListeners(event, func, !!bool); } else { elem.detachEvent("on" + event, func); } return dom; }, getRequestAnimationFrame: function() { const vendors = ["ms", "moz", "webkit", "o"]; let lastTime = 0; let request = root.requestAnimationFrame; if (!request) { for (let i = 0; i < vendors.length; i++) { request = root[vendors[i] + "RequestAnimationFrame"] || request; } request = request || fallbackRequest; } function fallbackRequest(callback, element) { const currTime = new Date().getTime(); const timeToCall = Math.max(0, 16 - (currTime - lastTime)); const id = root.setTimeout(nextRequest, timeToCall); lastTime = currTime + timeToCall; function nextRequest() { callback(currTime + timeToCall); } return id; } return request; } }; var temp = root.document ? root.document.createElement("div") : {}; temp.id = "help-two-load"; Object.defineProperty(dom, "temp", { enumerable: true, get: function() { if (_.isElement(temp) && !root.document.head.contains(temp)) { temp.style.display = "none"; root.document.head.appendChild(temp); } return temp; } }); // src/utils/error.js var TwoError = class extends Error { name = "Two.js"; message; constructor(message) { super(); this.message = message; } }; // src/registry.js var Registry = class { map = {}; constructor() { } add(id, obj) { this.map[id] = obj; return this; } remove(id) { delete this.map[id]; return this; } get(id) { return this.map[id]; } contains(id) { return id in this.map; } }; // src/utils/shape.js function contains(path, t) { if (t === 0 || t === 1) { return true; } const length = path._length; const target = length * t; let elapsed = 0; for (let i = 0; i < path._lengths.length; i++) { const dist = path._lengths[i]; if (elapsed >= target) { return target - elapsed >= 0; } elapsed += dist; } return false; } function getIdByLength(path, target) { const total = path._length; if (target <= 0) { return 0; } else if (target >= total) { return path._lengths.length - 1; } for (let i = 0, sum = 0; i < path._lengths.length; i++) { if (sum + path._lengths[i] >= target) { target -= sum; return Math.max(i - 1, 0) + target / path._lengths[i]; } sum += path._lengths[i]; } return -1; } function getCurveLength2(a, b, limit) { let x1, x2, x3, x4, y1, y2, y3, y4; const right = b.controls && b.controls.right; const left = a.controls && a.controls.left; x1 = b.x; y1 = b.y; x2 = (right || b).x; y2 = (right || b).y; x3 = (left || a).x; y3 = (left || a).y; x4 = a.x; y4 = a.y; if (right && b._relative) { x2 += b.x; y2 += b.y; } if (left && a._relative) { x3 += a.x; y3 += a.y; } return getCurveLength(x1, y1, x2, y2, x3, y3, x4, y4, limit); } function getSubdivisions(a, b, limit) { let x1, x2, x3, x4, y1, y2, y3, y4; const right = b.controls && b.controls.right; const left = a.controls && a.controls.left; x1 = b.x; y1 = b.y; x2 = (right || b).x; y2 = (right || b).y; x3 = (left || a).x; y3 = (left || a).y; x4 = a.x; y4 = a.y; if (right && b._relative) { x2 += b.x; y2 += b.y; } if (left && a._relative) { x3 += a.x; y3 += a.y; } return subdivide(x1, y1, x2, y2, x3, y3, x4, y4, limit); } // src/effects/stop.js var _Stop = class extends Element { _flagOffset = true; _flagOpacity = true; _flagColor = true; _offset = 0; _opacity = 1; _color = "#fff"; constructor(offset, color, opacity) { super(); for (let prop in proto6) { Object.defineProperty(this, prop, proto6[prop]); } this._renderer.type = "stop"; this.offset = typeof offset === "number" ? offset : _Stop.Index <= 0 ? 0 : 1; this.opacity = typeof opacity === "number" ? opacity : 1; this.color = typeof color === "string" ? color : _Stop.Index <= 0 ? "#fff" : "#000"; _Stop.Index = (_Stop.Index + 1) % 2; } clone(parent) { const clone = new _Stop(); _.each(_Stop.Properties, function(property) { clone[property] = this[property]; }, this); if (parent && parent.stops) { parent.stops.push(clone); } return clone; } toObject() { const result = {}; _.each(_Stop.Properties, function(k) { result[k] = this[k]; }, this); return result; } flagReset() { this._flagOffset = this._flagColor = this._flagOpacity = false; super.flagReset.call(this); return this; } }; var Stop = _Stop; __publicField(Stop, "Index", 0); __publicField(Stop, "Properties", ["offset", "opacity", "color"]); var proto6 = { offset: { enumerable: true, get: function() { return this._offset; }, set: function(v) { this._offset = v; this._flagOffset = true; if (this.parent) { this.parent._flagStops = true; } } }, opacity: { enumerable: true, get: function() { return this._opacity; }, set: function(v) { this._opacity = v; this._flagOpacity = true; if (this.parent) { this.parent._flagStops = true; } } }, color: { enumerable: true, get: function() { return this._color; }, set: function(v) { this._color = v; this._flagColor = true; if (this.parent) { this.parent._flagStops = true; } } } }; // src/effects/gradient.js var _Gradient = class extends Element { _flagStops = false; _flagSpread = false; _flagUnits = false; _spread = ""; _units = ""; constructor(stops) { super(); for (let prop in proto7) { Object.defineProperty(this, prop, proto7[prop]); } this._renderer.type = "gradient"; this.id = Constants.Identifier + Constants.uniqueId(); this.classList = []; this._renderer.flagStops = FlagStops.bind(this); this._renderer.bindStops = BindStops.bind(this); this._renderer.unbindStops = UnbindStops.bind(this); this.spread = "pad"; this.units = "objectBoundingBox"; if (stops) { this.stops = stops; } } clone(parent) { const stops = this.stops.map(function(s) { return s.clone(); }); const clone = new _Gradient(stops); _.each(_Gradient.Properties, function(k) { clone[k] = this[k]; }, this); if (parent) { parent.add(clone); } return clone; } toObject() { const result = { stops: this.stops.map(function(s) { return s.toObject(); }) }; _.each(_Gradient.Properties, function(k) { result[k] = this[k]; }, this); return result; } _update() { if (this._flagSpread || this._flagStops) { this.trigger(Events.Types.change); } return this; } flagReset() { this._flagSpread = this._flagUnits = this._flagStops = false; super.flagReset.call(this); return this; } }; var Gradient = _Gradient; __publicField(Gradient, "Stop", Stop); __publicField(Gradient, "Properties", ["spread", "stops", "renderer", "units"]); var proto7 = { spread: { enumerable: true, get: function() { return this._spread; }, set: function(v) { this._spread = v; this._flagSpread = true; } }, units: { enumerable: true, get: function() { return this._units; }, set: function(v) { this._units = v; this._flagUnits = true; } }, stops: { enumerable: true, get: function() { return this._stops; }, set: function(stops) { const bindStops = this._renderer.bindStops; const unbindStops = this._renderer.unbindStops; if (this._stops) { this._stops.unbind(Events.Types.insert, bindStops).unbind(Events.Types.remove, unbindStops); } this._stops = new Collection((stops || []).slice(0)); this._stops.bind(Events.Types.insert, bindStops).bind(Events.Types.remove, unbindStops); bindStops(this._stops); } } }; function FlagStops() { this._flagStops = true; } function BindStops(items) { let i = items.length; while (i--) { items[i].bind(Events.Types.change, this._renderer.flagStops); items[i].parent = this; } this._renderer.flagStops(); } function UnbindStops(items) { let i = items.length; while (i--) { items[i].unbind(Events.Types.change, this._renderer.flagStops); delete items[i].parent; } this._renderer.flagStops(); } // src/effects/linear-gradient.js var _LinearGradient = class extends Gradient { _flagEndPoints = false; _left = null; _right = null; constructor(x1, y1, x2, y2, stops) { super(stops); for (let prop in proto8) { Object.defineProperty(this, prop, proto8[prop]); } this._renderer.type = "linear-gradient"; this._renderer.flagEndPoints = FlagEndPoints.bind(this); this.left = new Vector(); this.right = new Vector(); if (typeof x1 === "number") { this.left.x = x1; } if (typeof y1 === "number") { this.left.y = y1; } if (typeof x2 === "number") { this.right.x = x2; } if (typeof y2 === "number") { this.right.y = y2; } } clone(parent) { const stops = this.stops.map(function(stop) { return stop.clone(); }); const clone = new _LinearGradient( this.left._x, this.left._y, this.right._x, this.right._y, stops ); _.each(Gradient.Properties, function(k) { clone[k] = this[k]; }, this); if (parent) { parent.add(clone); } return clone; } toObject() { const result = super.toObject.call(this); result.left = this.left.toObject(); result.right = this.right.toObject(); return result; } _update() { if (this._flagEndPoints || this._flagSpread || this._flagStops) { this.trigger(Events.Types.change); } return this; } flagReset() { this._flagEndPoints = false; super.flagReset.call(this); return this; } }; var LinearGradient = _LinearGradient; __publicField(LinearGradient, "Properties", ["left", "right"]); __publicField(LinearGradient, "Stop", Stop); var proto8 = { left: { enumerable: true, get: function() { return this._left; }, set: function(v) { if (this._left instanceof Vector) { this._left.unbind(Events.Types.change, this._renderer.flagEndPoints); } this._left = v; this._left.bind(Events.Types.change, this._renderer.flagEndPoints); this._flagEndPoints = true; } }, right: { enumerable: true, get: function() { return this._right; }, set: function(v) { if (this._right instanceof Vector) { this._right.unbind(Events.Types.change, this._renderer.flagEndPoints); } this._right = v; this._right.bind(Events.Types.change, this._renderer.flagEndPoints); this._flagEndPoints = true; } } }; function FlagEndPoints() { this._flagEndPoints = true; } // src/effects/radial-gradient.js var _RadialGradient = class extends Gradient { _flagRadius = false; _flagCenter = false; _flagFocal = false; _radius = 0; _center = null; _focal = null; constructor(cx, cy, r, stops, fx, fy) { super(stops); for (let prop in proto9) { Object.defineProperty(this, prop, proto9[prop]); } this._renderer.type = "radial-gradient"; this._renderer.flagCenter = FlagCenter.bind(this); this._renderer.flagFocal = FlagFocal.bind(this); this.center = new Vector(); this.radius = typeof r === "number" ? r : 1; this.focal = new Vector(); if (typeof cx === "number") { this.center.x = cx; } if (typeof cy === "number") { this.center.y = cy; } this.focal.copy(this.center); if (typeof fx === "number") { this.focal.x = fx; } if (typeof fy === "number") { this.focal.y = fy; } } clone(parent) { const stops = this.stops.map(function(stop) { return stop.clone(); }); const clone = new _RadialGradient( this.center._x, this.center._y, this._radius, stops, this.focal._x, this.focal._y ); _.each(Gradient.Properties.concat(_RadialGradient.Properties), function(k) { clone[k] = this[k]; }, this); if (parent) { parent.add(clone); } return clone; } toObject() { const result = super.toObject.call(this); _.each(_RadialGradient.Properties, function(k) { result[k] = this[k]; }, this); result.center = this.center.toObject(); result.focal = this.focal.toObject(); return result; } _update() { if (this._flagRadius || this._flatCenter || this._flagFocal || this._flagSpread || this._flagStops) { this.trigger(Events.Types.change); } return this; } flagReset() { this._flagRadius = this._flagCenter = this._flagFocal = false; super.flagReset.call(this); return this; } }; var RadialGradient = _RadialGradient; __publicField(RadialGradient, "Stop", Stop); __publicField(RadialGradient, "Properties", ["center", "radius", "focal"]); var proto9 = { radius: { enumerable: true, get: function() { return this._radius; }, set: function(v) { this._radius = v; this._flagRadius = true; } }, center: { enumerable: true, get: function() { return this._center; }, set: function(v) { if (this._center) { this._center.unbind(Events.Types.change, this._renderer.flagCenter); } this._center = v; this._center.bind(Events.Types.change, this._renderer.flagCenter); this._flagCenter = true; } }, focal: { enumerable: true, get: function() { return this._focal; }, set: function(v) { if (this._focal) { this._focal.unbind(Events.Types.change, this._renderer.flagFocal); } this._focal = v; this._focal.bind(Events.Types.change, this._renderer.flagFocal); this._flagFocal = true; } } }; function FlagCenter() { this._flagCenter = true; } function FlagFocal() { this._flagFocal = true; } // src/effects/texture.js var anchor; var regex = { video: /\.(mp4|webm|ogg)$/i, image: /\.(jpe?g|png|gif|tiff|webp)$/i, effect: /texture|gradient/i }; if (root.document) { anchor = document.createElement("a"); } var _Texture = class extends Element { _flagSrc = false; _flagImage = false; _flagVideo = false; _flagLoaded = false; _flagRepeat = false; _flagOffset = false; _flagScale = false; _src = ""; _image = null; _loaded = false; _repeat = "no-repeat"; _scale = 1; _offset = null; constructor(src, callback) { super(); this._renderer = {}; for (let prop in proto10) { Object.defineProperty(this, prop, proto10[prop]); } this._renderer.type = "texture"; this._renderer.flagOffset = FlagOffset.bind(this); this._renderer.flagScale = FlagScale.bind(this); this.id = Constants.Identifier + Constants.uniqueId(); this.classList = []; this.loaded = false; this.repeat = "no-repeat"; this.offset = new Vector(); if (typeof callback === "function") { const loaded = function() { this.unbind(Events.Types.load, loaded); if (typeof callback === "function") { callback(); } }.bind(this); this.bind(Events.Types.load, loaded); } if (typeof src === "string") { this.src = src; } else if (typeof src === "object") { const elemString = Object.prototype.toString.call(src); if (elemString === "[object HTMLImageElement]" || elemString === "[object HTMLCanvasElement]" || elemString === "[object HTMLVideoElement]" || elemString === "[object Image]") { this.image = src; } } this._update(); } static getAbsoluteURL(path) { if (!anchor) { return path; } anchor.href = path; return anchor.href; } static loadHeadlessBuffer(texture, loaded) { texture.image.onload = loaded; texture.image.src = texture.src; } static getTag(image) { return image && image.nodeName && image.nodeName.toLowerCase() || "img"; } static getImage(src) { const absoluteSrc = _Texture.getAbsoluteURL(src); if (_Texture.ImageRegistry.contains(absoluteSrc)) { return _Texture.ImageRegistry.get(absoluteSrc); } let image; if (CanvasShim.Image) { image = new CanvasShim.Image(); Renderer.Utils.shim(image, "img"); } else if (root.document) { if (regex.video.test(absoluteSrc)) { image = document.createElement("video"); } else { image = document.createElement("img"); } } else { console.warn("Two.js: no prototypical image defined for Two.Texture"); } image.crossOrigin = "anonymous"; image.referrerPolicy = "no-referrer"; return image; } static load(texture, callback) { let image = texture.image; let tag = _Texture.getTag(image); if (texture._flagImage) { if (/canvas/i.test(tag)) { _Texture.Register.canvas(texture, callback); } else { texture._src = !CanvasShim.isHeadless && image.getAttribute("two-src") || image.src; _Texture.Register[tag](texture, callback); } } if (texture._flagSrc) { if (!image) { image = _Texture.getImage(texture.src); texture.image = image; } tag = _Texture.getTag(image); _Texture.Register[tag](texture, callback); } } clone() { const clone = new _Texture(this.src); clone.repeat = this.repeat; clone.offset.copy(this.origin); clone.scale = this.scale; return clone; } toObject() { return { src: this.src, repeat: this.repeat, origin: this.origin.toObject(), scale: typeof this.scale === "number" ? this.scale : this.scale.toObject() }; } _update() { if (this._flagSrc || this._flagImage) { this.trigger(Events.Types.change); if (this._flagSrc || this._flagImage) { this.loaded = false; _Texture.load(this, function() { this.loaded = true; this.trigger(Events.Types.change).trigger(Events.Types.load); }.bind(this)); } } if (this._image && this._image.readyState >= 4) { this._flagVideo = true; } return this; } flagReset() { this._flagSrc = this._flagImage = this._flagLoaded = this._flagRepeat = this._flagVideo = this._flagScale = this._flagOffset = false; super.flagReset.call(this); return this; } }; var Texture = _Texture; __publicField(Texture, "Properties", [ "src", "loaded", "repeat", "scale", "offset", "image" ]); __publicField(Texture, "RegularExpressions", regex); __publicField(Texture, "ImageRegistry", new Registry()); __publicField(Texture, "Register", { canvas: function(texture, callback) { texture._src = "#" + texture.id; _Texture.ImageRegistry.add(texture.src, texture.image); if (typeof callback === "function") { callback(); } }, img: function(texture, callback) { const image = texture.image; const loaded = function(e) { if (!CanvasShim.isHeadless && image.removeEventListener && typeof image.removeEventListener === "function") { image.removeEventListener("load", loaded, false); image.removeEventListener("error", error, false); } if (typeof callback === "function") { callback(); } }; const error = function(e) { if (!CanvasShim.isHeadless && typeof image.removeEventListener === "function") { image.removeEventListener("load", loaded, false); image.removeEventListener("error", error, false); } throw new TwoError("unable to load " + texture.src); }; if (typeof image.width === "number" && image.width > 0 && typeof image.height === "number" && image.height > 0) { loaded(); } else if (!CanvasShim.isHeadless && typeof image.addEventListener === "function") { image.addEventListener("load", loaded, false); image.addEventListener("error", error, false); } texture._src = _Texture.getAbsoluteURL(texture._src); if (!CanvasShim.isHeadless && image && image.getAttribute("two-src")) { return; } if (!CanvasShim.isHeadless) { image.setAttribute("two-src", texture.src); } _Texture.ImageRegistry.add(texture.src, image); if (CanvasShim.isHeadless) { _Texture.loadHeadlessBuffer(texture, loaded); } else { texture.image.src = texture.src; } }, video: function(texture, callback) { if (CanvasShim.isHeadless) { throw new TwoError("video textures are not implemented in headless environments."); } const loaded = function(e) { texture.image.removeEventListener("canplaythrough", loaded, false); texture.image.removeEventListener("error", error, false); texture.image.width = texture.image.videoWidth; texture.image.height = texture.image.videoHeight; if (typeof callback === "function") { callback(); } }; const error = function(e) { texture.image.removeEventListener("canplaythrough", loaded, false); texture.image.removeEventListener("error", error, false); throw new TwoError("unable to load " + texture.src); }; texture._src = _Texture.getAbsoluteURL(texture._src); if (!texture.image.getAttribute("two-src")) { texture.image.setAttribute("two-src", texture.src); _Texture.ImageRegistry.add(texture.src, texture.image); } if (texture.image.readyState >= 4) { loaded(); } else { texture.image.addEventListener("canplaythrough", loaded, false); texture.image.addEventListener("error", error, false); texture.image.src = texture.src; texture.image.load(); } } }); var proto10 = { src: { enumerable: true, get: function() { return this._src; }, set: function(v) { this._src = v; this._flagSrc = true; } }, loaded: { enumerable: true, get: function() { return this._loaded; }, set: function(v) { this._loaded = v; this._flagLoaded = true; } }, repeat: { enumerable: true, get: function() { return this._repeat; }, set: function(v) { this._repeat = v; this._flagRepeat = true; } }, image: { enumerable: true, get: function() { return this._image; }, set: function(image) { const tag = Texture.getTag(image); let index; switch (tag) { case "canvas": index = "#" + image.id; break; default: index = image.src; } if (Texture.ImageRegistry.contains(index)) { this._image = Texture.ImageRegistry.get(image.src); } else { this._image = image; } this._flagImage = true; } }, offset: { enumerable: true, get: function() { return this._offset; }, set: function(v) { if (this._offset) { this._offset.unbind(Events.Types.change, this._renderer.flagOffset); } this._offset = v; this._offset.bind(Events.Types.change, this._renderer.flagOffset); this._flagOffset = true; } }, scale: { enumerable: true, get: function() { return this._scale; }, set: function(v) { if (this._scale instanceof Vector) { this._scale.unbind(Events.Types.change, this._renderer.flagScale); } this._scale = v; if (this._scale instanceof Vector) { this._scale.bind(Events.Types.change, this._renderer.flagScale); } this._flagScale = true; } } }; function FlagOffset() { this._flagOffset = true; } function FlagScale() { this._flagScale = true; } // src/path.js var min3 = Math.min; var max3 = Math.max; var ceil = Math.ceil; var floor2 = Math.floor; var vector = new Vector(); var _Path = class extends Shape { _flagVertices = true; _flagLength = true; _flagFill = true; _flagStroke = true; _flagLinewidth = true; _flagOpacity = true; _flagVisible = true; _flagCap = true; _flagJoin = true; _flagMiter = true; _flagMask = false; _flagClip = false; _length = 0; _fill = "#fff"; _stroke = "#000"; _linewidth = 1; _opacity = 1; _visible = true; _cap = "round"; _join = "round"; _miter = 4; _closed = true; _curved = false; _automatic = true; _beginning = 0; _ending = 1; _mask = null; _clip = false; _dashes = null; constructor(vertices, closed2, curved, manual) { super(); for (let prop in proto11) { Object.defineProperty(this, prop, proto11[prop]); } this._renderer.type = "path"; this._renderer.flagVertices = FlagVertices.bind(this); this._renderer.bindVertices = BindVertices.bind(this); this._renderer.unbindVertices = UnbindVertices.bind(this); this._renderer.flagFill = FlagFill.bind(this); this._renderer.flagStroke = FlagStroke.bind(this); this._renderer.vertices = []; this._renderer.collection = []; this.closed = !!closed2; this.curved = !!curved; this.beginning = 0; this.ending = 1; this.fill = "#fff"; this.stroke = "#000"; this.linewidth = 1; this.opacity = 1; this.className = ""; this.visible = true; this.cap = "butt"; this.join = "miter"; this.miter = 4; this.vertices = vertices; this.automatic = !manual; this.dashes = []; this.dashes.offset = 0; } clone(parent) { const clone = new _Path(); for (let j = 0; j < this.vertices.length; j++) { clone.vertices.push(this.vertices[j].clone()); } for (let i = 0; i < _Path.Properties.length; i++) { const k = _Path.Properties[i]; clone[k] = this[k]; } clone.className = this.className; clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } if (parent) { parent.add(clone); } return clone._update(); } toObject() { const result = { vertices: this.vertices.map(function(v) { return v.toObject(); }) }; _.each(_Path.Properties, function(k) { if (typeof this[k] !== "undefined") { if (this[k].toObject) { result[k] = this[k].toObject(); } else { result[k] = this[k]; } } }, this); result.className = this.className; result.translation = this.translation.toObject(); result.rotation = this.rotation; result.scale = this.scale instanceof Vector ? this.scale.toObject() : this.scale; result.skewX = this.skewX; result.skewY = this.skewY; if (this.matrix.manual) { result.matrix = this.matrix.toObject(); } return result; } noFill() { this.fill = "none"; return this; } noStroke() { this.stroke = "none"; return this; } corner() { const rect = this.getBoundingClientRect(true); const hw = rect.width / 2; const hh = rect.height / 2; const cx = rect.left + rect.width / 2; const cy = rect.top + rect.height / 2; for (let i = 0; i < this.vertices.length; i++) { const v = this.vertices[i]; v.x -= cx; v.y -= cy; v.x += hw; v.y += hh; } if (this.mask) { this.mask.translation.x -= cx; this.mask.translation.x += hw; this.mask.translation.y -= cy; this.mask.translation.y += hh; } return this; } center() { const rect = this.getBoundingClientRect(true); const cx = rect.left + rect.width / 2 - this.translation.x; const cy = rect.top + rect.height / 2 - this.translation.y; for (let i = 0; i < this.vertices.length; i++) { const v = this.vertices[i]; v.x -= cx; v.y -= cy; } if (this.mask) { this.mask.translation.x -= cx; this.mask.translation.y -= cy; } return this; } getBoundingClientRect(shallow) { let matrix, border, l, i, v0, v1; let left = Infinity, right = -Infinity, top = Infinity, bottom = -Infinity; this._update(true); matrix = shallow ? this.matrix : this.worldMatrix; border = (this.linewidth || 0) / 2; l = this._renderer.vertices.length; if (this.linewidth > 0 || this.stroke && !/(transparent|none)/i.test(this.stroke)) { if (this.matrix.manual) { const { scaleX, scaleY } = decomposeMatrix( matrix.elements[0], matrix.elements[3], matrix.elements[1], matrix.elements[4], matrix.elements[2], matrix.elements[5] ); if (typeof scaleX === "number" && typeof scaleY === "number") { border = Math.max(scaleX, scaleY) * (this.linewidth || 0) / 2; } } else { border *= typeof this.scale === "number" ? this.scale : Math.max(this.scale.x, this.scale.y); } } if (l <= 0) { return { width: 0, height: 0 }; } for (i = 0; i < l; i++) { v1 = this._renderer.vertices[i]; v0 = this._renderer.vertices[(i + l - 1) % l]; const [v0x, v0y] = matrix.multiply(v0.x, v0.y); const [v1x, v1y] = matrix.multiply(v1.x, v1.y); if (v0.controls && v1.controls) { let rx = v0.controls.right.x; let ry = v0.controls.right.y; if (v0.relative) { rx += v0.x; ry += v0.y; } let [c0x, c0y] = matrix.multiply(rx, ry); let lx = v1.controls.left.x; let ly = v1.controls.left.y; if (v1.relative) { lx += v1.x; ly += v1.y; } let [c1x, c1y] = matrix.multiply(lx, ly); const bb = getCurveBoundingBox( v0x, v0y, c0x, c0y, c1x, c1y, v1x, v1y ); top = min3(bb.min.y - border, top); left = min3(bb.min.x - border, left); right = max3(bb.max.x + border, right); bottom = max3(bb.max.y + border, bottom); } else { if (i <= 1) { top = min3(v0y - border, top); left = min3(v0x - border, left); right = max3(v0x + border, right); bottom = max3(v0y + border, bottom); } top = min3(v1y - border, top); left = min3(v1x - border, left); right = max3(v1x + border, right); bottom = max3(v1y + border, bottom); } } return { top, left, right, bottom, width: right - left, height: bottom - top }; } getPointAt(t, obj) { let ia, ib, result; let x, x1, x2, x3, x4, y, y1, y2, y3, y4, left, right; let target = this.length * Math.min(Math.max(t, 0), 1); const length = this.vertices.length; const last = length - 1; let a = null; let b = null; for (let i = 0, l = this._lengths.length, sum = 0; i < l; i++) { if (sum + this._lengths[i] >= target) { if (this._closed) { ia = mod(i, length); ib = mod(i - 1, length); if (i === 0) { ia = ib; ib = i; } } else { ia = i; ib = Math.min(Math.max(i - 1, 0), last); } a = this.vertices[ia]; b = this.vertices[ib]; target -= sum; if (this._lengths[i] !== 0) { t = target / this._lengths[i]; } else { t = 0; } break; } sum += this._lengths[i]; } if (a === null || b === null) { return null; } if (!a) { return b; } else if (!b) { return a; } right = b.controls && b.controls.right; left = a.controls && a.controls.left; x1 = b.x; y1 = b.y; x2 = (right || b).x; y2 = (right || b).y; x3 = (left || a).x; y3 = (left || a).y; x4 = a.x; y4 = a.y; if (right && b.relative) { x2 += b.x; y2 += b.y; } if (left && a.relative) { x3 += a.x; y3 += a.y; } x = getComponentOnCubicBezier(t, x1, x2, x3, x4); y = getComponentOnCubicBezier(t, y1, y2, y3, y4); const t1x = lerp(x1, x2, t); const t1y = lerp(y1, y2, t); const t2x = lerp(x2, x3, t); const t2y = lerp(y2, y3, t); const t3x = lerp(x3, x4, t); const t3y = lerp(y3, y4, t); const brx = lerp(t1x, t2x, t); const bry = lerp(t1y, t2y, t); const alx = lerp(t2x, t3x, t); const aly = lerp(t2y, t3y, t); if (_.isObject(obj)) { obj.x = x; obj.y = y; if (obj instanceof Anchor) { obj.controls.left.x = brx; obj.controls.left.y = bry; obj.controls.right.x = alx; obj.controls.right.y = aly; if (!(typeof obj.relative === "boolean") || obj.relative) { obj.controls.left.x -= x; obj.controls.left.y -= y; obj.controls.right.x -= x; obj.controls.right.y -= y; } } obj.t = t; return obj; } result = new Anchor( x, y, brx - x, bry - y, alx - x, aly - y, this._curved ? Commands.curve : Commands.line ); result.t = t; return result; } plot() { if (this.curved) { getCurveFromPoints(this._collection, this.closed); return this; } for (let i = 0; i < this._collection.length; i++) { this._collection[i].command = i === 0 ? Commands.move : Commands.line; } return this; } subdivide(limit) { this._update(); const last = this.vertices.length - 1; const closed2 = this._closed || this.vertices[last]._command === Commands.close; let b = this.vertices[last]; let points = [], verts; _.each(this.vertices, function(a, i) { if (i <= 0 && !closed2) { b = a; return; } if (a.command === Commands.move) { points.push(new Anchor(b.x, b.y)); if (i > 0) { points[points.length - 1].command = Commands.line; } b = a; return; } verts = getSubdivisions(a, b, limit); points = points.concat(verts); _.each(verts, function(v, i2) { if (i2 <= 0 && b.command === Commands.move) { v.command = Commands.move; } else { v.command = Commands.line; } }); if (i >= last) { if (this._closed && this._automatic) { b = a; verts = getSubdivisions(a, b, limit); points = points.concat(verts); _.each(verts, function(v, i2) { if (i2 <= 0 && b.command === Commands.move) { v.command = Commands.move; } else { v.command = Commands.line; } }); } else if (closed2) { points.push(new Anchor(a.x, a.y)); } points[points.length - 1].command = closed2 ? Commands.close : Commands.line; } b = a; }, this); this._automatic = false; this._curved = false; this.vertices = points; return this; } _updateLength(limit, silent) { if (!silent) { this._update(); } const length = this.vertices.length; const last = length - 1; const closed2 = false; let b = this.vertices[last]; let sum = 0; if (typeof this._lengths === "undefined") { this._lengths = []; } _.each(this.vertices, function(a, i) { if (i <= 0 && !closed2 || a.command === Commands.move) { b = a; this._lengths[i] = 0; return; } this._lengths[i] = getCurveLength2(a, b, limit); sum += this._lengths[i]; if (i >= last && closed2) { b = this.vertices[(i + 1) % length]; this._lengths[i + 1] = getCurveLength2(a, b, limit); sum += this._lengths[i + 1]; } b = a; }, this); this._length = sum; this._flagLength = false; return this; } _update() { if (this._flagVertices) { if (this._automatic) { this.plot(); } if (this._flagLength) { this._updateLength(void 0, true); } const l = this._collection.length; const closed2 = this._closed; const beginning = Math.min(this._beginning, this._ending); const ending = Math.max(this._beginning, this._ending); const bid = getIdByLength(this, beginning * this._length); const eid = getIdByLength(this, ending * this._length); const low = ceil(bid); const high = floor2(eid); let left, right, prev, next, v, i; this._renderer.vertices.length = 0; for (i = 0; i < l; i++) { if (this._renderer.collection.length <= i) { this._renderer.collection.push(new Anchor()); } if (i > high && !right) { v = this._renderer.collection[i].copy(this._collection[i]); this.getPointAt(ending, v); v.command = this._renderer.collection[i].command; this._renderer.vertices.push(v); right = v; prev = this._collection[i - 1]; if (prev && prev.controls) { if (v.relative) { v.controls.right.clear(); } else { v.controls.right.copy(v); } if (prev.relative) { this._renderer.collection[i - 1].controls.right.copy(prev.controls.right).lerp(Vector.zero, 1 - v.t); } else { this._renderer.collection[i - 1].controls.right.copy(prev.controls.right).lerp(prev, 1 - v.t); } } } else if (i >= low && i <= high) { v = this._renderer.collection[i].copy(this._collection[i]); this._renderer.vertices.push(v); if (i === high && contains(this, ending)) { right = v; if (!closed2 && right.controls) { if (right.relative) { right.controls.right.clear(); } else { right.controls.right.copy(right); } } } else if (i === low && contains(this, beginning)) { left = v; left.command = Commands.move; if (!closed2 && left.controls) { if (left.relative) { left.controls.left.clear(); } else { left.controls.left.copy(left); } } } } } if (low > 0 && !left) { i = low - 1; v = this._renderer.collection[i].copy(this._collection[i]); this.getPointAt(beginning, v); v.command = Commands.move; this._renderer.vertices.unshift(v); next = this._collection[i + 1]; if (next && next.controls) { v.controls.left.clear(); if (next.relative) { this._renderer.collection[i + 1].controls.left.copy(next.controls.left).lerp(Vector.zero, v.t); } else { vector.copy(next); this._renderer.collection[i + 1].controls.left.copy(next.controls.left).lerp(next, v.t); } } } } Shape.prototype._update.apply(this, arguments); return this; } flagReset() { this._flagVertices = this._flagLength = this._flagFill = this._flagStroke = this._flagLinewidth = this._flagOpacity = this._flagVisible = this._flagCap = this._flagJoin = this._flagMiter = this._flagClip = false; Shape.prototype.flagReset.call(this); return this; } }; var Path = _Path; __publicField(Path, "Properties", [ "fill", "stroke", "linewidth", "opacity", "visible", "cap", "join", "miter", "closed", "curved", "automatic", "beginning", "ending" ]); __publicField(Path, "Utils", { getCurveLength: getCurveLength2 }); var proto11 = { linewidth: { enumerable: true, get: function() { return this._linewidth; }, set: function(v) { this._linewidth = v; this._flagLinewidth = true; } }, opacity: { enumerable: true, get: function() { return this._opacity; }, set: function(v) { this._opacity = v; this._flagOpacity = true; } }, visible: { enumerable: true, get: function() { return this._visible; }, set: function(v) { this._visible = v; this._flagVisible = true; } }, cap: { enumerable: true, get: function() { return this._cap; }, set: function(v) { this._cap = v; this._flagCap = true; } }, join: { enumerable: true, get: function() { return this._join; }, set: function(v) { this._join = v; this._flagJoin = true; } }, miter: { enumerable: true, get: function() { return this._miter; }, set: function(v) { this._miter = v; this._flagMiter = true; } }, fill: { enumerable: true, get: function() { return this._fill; }, set: function(f) { if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) { this._fill.unbind(Events.Types.change, this._renderer.flagFill); } this._fill = f; this._flagFill = true; if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) { this._fill.bind(Events.Types.change, this._renderer.flagFill); } } }, stroke: { enumerable: true, get: function() { return this._stroke; }, set: function(f) { if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) { this._stroke.unbind(Events.Types.change, this._renderer.flagStroke); } this._stroke = f; this._flagStroke = true; if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) { this._stroke.bind(Events.Types.change, this._renderer.flagStroke); } } }, length: { get: function() { if (this._flagLength) { this._updateLength(); } return this._length; } }, closed: { enumerable: true, get: function() { return this._closed; }, set: function(v) { this._closed = !!v; this._flagVertices = true; } }, curved: { enumerable: true, get: function() { return this._curved; }, set: function(v) { this._curved = !!v; this._flagVertices = true; } }, automatic: { enumerable: true, get: function() { return this._automatic; }, set: function(v) { if (v === this._automatic) { return; } this._automatic = !!v; const method = this._automatic ? "ignore" : "listen"; _.each(this.vertices, function(v2) { v2[method](); }); } }, beginning: { enumerable: true, get: function() { return this._beginning; }, set: function(v) { this._beginning = v; this._flagVertices = true; } }, ending: { enumerable: true, get: function() { return this._ending; }, set: function(v) { this._ending = v; this._flagVertices = true; } }, vertices: { enumerable: true, get: function() { return this._collection; }, set: function(vertices) { const bindVertices = this._renderer.bindVertices; const unbindVertices = this._renderer.unbindVertices; if (this._collection) { this._collection.unbind(Events.Types.insert, bindVertices).unbind(Events.Types.remove, unbindVertices); } if (vertices instanceof Collection) { this._collection = vertices; } else { this._collection = new Collection(vertices || []); } this._collection.bind(Events.Types.insert, bindVertices).bind(Events.Types.remove, unbindVertices); bindVertices(this._collection); } }, mask: { enumerable: true, get: function() { return this._mask; }, set: function(v) { this._mask = v; this._flagMask = true; if (_.isObject(v) && !v.clip) { v.clip = true; } } }, clip: { enumerable: true, get: function() { return this._clip; }, set: function(v) { this._clip = v; this._flagClip = true; } }, dashes: { enumerable: true, get: function() { return this._dashes; }, set: function(v) { if (typeof v.offset !== "number") { v.offset = this.dashes && this._dashes.offset || 0; } this._dashes = v; } } }; function FlagVertices() { this._flagVertices = true; this._flagLength = true; if (this.parent) { this.parent._flagLength = true; } } function BindVertices(items) { let i = items.length; while (i--) { items[i].bind(Events.Types.change, this._renderer.flagVertices); } this._renderer.flagVertices(); } function UnbindVertices(items) { let i = items.length; while (i--) { items[i].unbind(Events.Types.change, this._renderer.flagVertices); } this._renderer.flagVertices(); } function FlagFill() { this._flagFill = true; } function FlagStroke() { this._flagStroke = true; } // src/shapes/rectangle.js var _Rectangle = class extends Path { constructor(x, y, width, height) { const points = [ new Anchor(), new Anchor(), new Anchor(), new Anchor() ]; super(points, true, false, true); for (let prop in proto12) { Object.defineProperty(this, prop, proto12[prop]); } this.width = typeof width === "number" ? width : 1; this.height = typeof height === "number" ? height : 1; this.origin = new Vector(); if (typeof x === "number") { this.translation.x = x; } if (typeof y === "number") { this.translation.y = y; } this._update(); } _flagWidth = 0; _flagHeight = 0; _width = 0; _height = 0; _origin = null; _update() { if (this._flagVertices || this._flagWidth || this._flagHeight) { const xr = this._width / 2; const yr = this._height / 2; if (!this._closed && this.vertices.length === 4) { this.vertices.push(new Anchor()); } this.vertices[0].set(-xr, -yr).sub(this._origin).command = Commands.move; this.vertices[1].set(xr, -yr).sub(this._origin).command = Commands.line; this.vertices[2].set(xr, yr).sub(this._origin).command = Commands.line; this.vertices[3].set(-xr, yr).sub(this._origin).command = Commands.line; if (this.vertices[4]) { this.vertices[4].set(-xr, -yr).sub(this._origin).command = Commands.line; } } super._update.call(this); return this; } flagReset() { this._flagWidth = this._flagHeight = false; super.flagReset.call(this); return this; } clone(parent) { const clone = new _Rectangle(0, 0, this.width, this.height); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } for (let i = 0; i < Path.Properties.length; i++) { const k = Path.Properties[i]; clone[k] = this[k]; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); object.width = this.width; object.height = this.height; object.origin = this.origin.toObject(); return object; } }; var Rectangle = _Rectangle; __publicField(Rectangle, "Properties", ["width", "height"]); var proto12 = { width: { enumerable: true, get: function() { return this._width; }, set: function(v) { this._width = v; this._flagWidth = true; } }, height: { enumerable: true, get: function() { return this._height; }, set: function(v) { this._height = v; this._flagHeight = true; } }, origin: { enumerable: true, get: function() { return this._origin; }, set: function(v) { if (this._origin) { this._origin.unbind(Events.Types.change, this._renderer.flagVertices); } this._origin = v; this._origin.bind(Events.Types.change, this._renderer.flagVertices); this._renderer.flagVertices(); } } }; // src/effects/sprite.js var _Sprite = class extends Rectangle { _flagTexture = false; _flagColumns = false; _flagRows = false; _flagFrameRate = false; _flagIndex = false; _amount = 1; _duration = 0; _startTime = 0; _playing = false; _firstFrame = 0; _lastFrame = 0; _loop = true; _texture = null; _columns = 1; _rows = 1; _frameRate = 0; _index = 0; _origin = null; constructor(path, ox, oy, cols, rows, frameRate) { super(ox, oy, 0, 0); for (let prop in proto13) { Object.defineProperty(this, prop, proto13[prop]); } this.noStroke(); this.noFill(); if (path instanceof Texture) { this.texture = path; } else if (typeof path === "string") { this.texture = new Texture(path); } this.origin = new Vector(); this._update(); if (typeof cols === "number") { this.columns = cols; } if (typeof rows === "number") { this.rows = rows; } if (typeof frameRate === "number") { this.frameRate = frameRate; } this.index = 0; } play(firstFrame, lastFrame, onLastFrame) { this._playing = true; this._firstFrame = 0; this._lastFrame = this.amount - 1; this._startTime = _.performance.now(); if (typeof firstFrame === "number") { this._firstFrame = firstFrame; } if (typeof lastFrame === "number") { this._lastFrame = lastFrame; } if (typeof onLastFrame === "function") { this._onLastFrame = onLastFrame; } else { delete this._onLastFrame; } if (this._index !== this._firstFrame) { this._startTime -= 1e3 * Math.abs(this._index - this._firstFrame) / this._frameRate; } return this; } pause() { this._playing = false; return this; } stop() { this._playing = false; this._index = 0; return this; } clone(parent) { const clone = new _Sprite( this.texture, this.translation.x, this.translation.y, this.columns, this.rows, this.frameRate ); if (this.playing) { clone.play(this._firstFrame, this._lastFrame); clone._loop = this._loop; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); object.texture = this.texture.toObject(); object.columns = this.columns; object.rows = this.rows; object.frameRate = this.frameRate; object.index = this.index; object._firstFrame = this._firstFrame; object._lastFrame = this._lastFrame; object._loop = this._loop; return object; } _update() { const effect = this._texture; const cols = this._columns; const rows = this._rows; let width, height, elapsed, amount, duration; let index, iw, ih, frames; if (effect) { if (this._flagColumns || this._flagRows) { this._amount = this._columns * this._rows; } if (this._flagFrameRate) { this._duration = 1e3 * this._amount / this._frameRate; } if (this._flagTexture) { this.fill = effect; } if (effect.loaded) { iw = effect.image.width; ih = effect.image.height; width = iw / cols; height = ih / rows; amount = this._amount; if (this.width !== width) { this.width = width; } if (this.height !== height) { this.height = height; } if (this._playing && this._frameRate > 0) { if (_.isNaN(this._lastFrame)) { this._lastFrame = amount - 1; } elapsed = _.performance.now() - this._startTime; frames = this._lastFrame + 1; duration = 1e3 * (frames - this._firstFrame) / this._frameRate; if (this._loop) { elapsed = elapsed % duration; } else { elapsed = Math.min(elapsed, duration); } index = lerp(this._firstFrame, frames, elapsed / duration); index = Math.floor(index); if (index !== this._index) { this._index = index; if (index >= this._lastFrame - 1 && this._onLastFrame) { this._onLastFrame(); } } } const col = this._index % cols; const row = Math.floor(this._index / cols); const ox = -width * col + (iw - width) / 2; const oy = -height * row + (ih - height) / 2; if (ox !== effect.offset.x) { effect.offset.x = ox; } if (oy !== effect.offset.y) { effect.offset.y = oy; } } } super._update.call(this); return this; } flagReset() { this._flagTexture = this._flagColumns = this._flagRows = this._flagFrameRate = false; super.flagReset.call(this); return this; } }; var Sprite = _Sprite; __publicField(Sprite, "Properties", [ "texture", "columns", "rows", "frameRate", "index" ]); var proto13 = { texture: { enumerable: true, get: function() { return this._texture; }, set: function(v) { this._texture = v; this._flagTexture = true; } }, columns: { enumerable: true, get: function() { return this._columns; }, set: function(v) { this._columns = v; this._flagColumns = true; } }, rows: { enumerable: true, get: function() { return this._rows; }, set: function(v) { this._rows = v; this._flagRows = true; } }, frameRate: { enumerable: true, get: function() { return this._frameRate; }, set: function(v) { this._frameRate = v; this._flagFrameRate = true; } }, index: { enumerable: true, get: function() { return this._index; }, set: function(v) { this._index = v; this._flagIndex = true; } } }; // src/shapes/circle.js var cos3 = Math.cos; var sin3 = Math.sin; var _Circle = class extends Path { _flagRadius = false; _radius = 0; constructor(ox, oy, r, resolution) { const amount = resolution ? Math.max(resolution, 2) : 4; const points = []; for (let i = 0; i < amount; i++) { points.push(new Anchor(0, 0, 0, 0, 0, 0)); } super(points, true, true, true); for (let prop in proto14) { Object.defineProperty(this, prop, proto14[prop]); } if (typeof r === "number") { this.radius = r; } this._update(); if (typeof ox === "number") { this.translation.x = ox; } if (typeof oy === "number") { this.translation.y = oy; } } _update() { if (this._flagVertices || this._flagRadius) { let length = this.vertices.length; if (!this._closed && length > 2) { length -= 1; } const c = 4 / 3 * Math.tan(Math.PI / (length * 2)); const radius = this._radius; const rc = radius * c; for (let i = 0; i < this.vertices.length; i++) { const pct = i / length; const theta = pct * TWO_PI; const x = radius * cos3(theta); const y = radius * sin3(theta); const lx = rc * cos3(theta - HALF_PI); const ly = rc * sin3(theta - HALF_PI); const rx = rc * cos3(theta + HALF_PI); const ry = rc * sin3(theta + HALF_PI); const v = this.vertices[i]; v.command = i === 0 ? Commands.move : Commands.curve; v.set(x, y); v.controls.left.set(lx, ly); v.controls.right.set(rx, ry); } } super._update.call(this); return this; } flagReset() { this._flagRadius = false; super.flagReset.call(this); return this; } clone(parent) { const clone = new _Circle(0, 0, this.radius, this.vertices.length); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } for (let i = 0; i < Path.Properties.length; i++) { const k = Path.Properties[i]; clone[k] = this[k]; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); for (let i = 0; i < _Circle.Properties.length; i++) { const k = _Circle.Properties[i]; object[k] = this[k]; } return object; } }; var Circle = _Circle; __publicField(Circle, "Properties", ["radius"]); var proto14 = { radius: { enumerable: true, get: function() { return this._radius; }, set: function(v) { this._radius = v; this._flagRadius = true; } } }; // src/shapes/ellipse.js var cos4 = Math.cos; var sin4 = Math.sin; var _Ellipse = class extends Path { _flagWidth = false; _flagHeight = false; _width = 0; _height = 0; constructor(x, y, rx, ry, resolution) { if (typeof ry !== "number" && typeof rx === "number") { ry = rx; } const amount = resolution ? Math.max(resolution, 2) : 4; const points = []; for (let i = 0; i < amount; i++) { points.push(new Anchor()); } super(points, true, true, true); for (let prop in proto15) { Object.defineProperty(this, prop, proto15[prop]); } if (typeof rx === "number") { this.width = rx * 2; } if (typeof ry === "number") { this.height = ry * 2; } this._update(); if (typeof x === "number") { this.translation.x = x; } if (typeof y === "number") { this.translation.y = y; } } _update() { if (this._flagVertices || this._flagWidth || this._flagHeight) { let length = this.vertices.length; if (!this._closed && length > 2) { length -= 1; } const c = 4 / 3 * Math.tan(Math.PI / (this.vertices.length * 2)); const radiusX = this._width / 2; const radiusY = this._height / 2; for (let i = 0; i < this.vertices.length; i++) { const pct = i / length; const theta = pct * TWO_PI; const x = radiusX * cos4(theta); const y = radiusY * sin4(theta); const lx = radiusX * c * cos4(theta - HALF_PI); const ly = radiusY * c * sin4(theta - HALF_PI); const rx = radiusX * c * cos4(theta + HALF_PI); const ry = radiusY * c * sin4(theta + HALF_PI); const v = this.vertices[i]; v.command = i === 0 ? Commands.move : Commands.curve; v.set(x, y); v.controls.left.set(lx, ly); v.controls.right.set(rx, ry); } } super._update.call(this); return this; } flagReset() { this._flagWidth = this._flagHeight = false; super.flagReset.call(this); return this; } clone(parent) { const rx = this.width / 2; const ry = this.height / 2; const resolution = this.vertices.length; const clone = new _Ellipse(0, 0, rx, ry, resolution); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } for (let i = 0; i < Path.Properties.length; i++) { const k = Path.Properties[i]; clone[k] = this[k]; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); for (let i = 0; i < _Ellipse.Properties.length; i++) { const k = _Ellipse.Properties[i]; object[k] = this[k]; } return object; } }; var Ellipse = _Ellipse; __publicField(Ellipse, "Properties", ["width", "height"]); var proto15 = { width: { enumerable: true, get: function() { return this._width; }, set: function(v) { this._width = v; this._flagWidth = true; } }, height: { enumerable: true, get: function() { return this._height; }, set: function(v) { this._height = v; this._flagHeight = true; } } }; // src/shapes/line.js var Line = class extends Path { constructor(x1, y1, x2, y2) { const points = [ new Anchor(x1, y1), new Anchor(x2, y2) ]; super(points); for (let prop in proto16) { Object.defineProperty(this, prop, proto16[prop]); } this.vertices[0].command = Commands.move; this.vertices[1].command = Commands.line; this.automatic = false; } }; var proto16 = { left: { enumerable: true, get: function() { return this.vertices[0]; }, set: function(v) { if (_.isObject(v)) { this.vertices.splice(0, 1, v); } else { const error = new TwoError("Two.Line.x argument is not an object."); console.warn(error.name, error.message); } } }, right: { enumerable: true, get: function() { return this.vertices[1]; }, set: function(v) { if (_.isObject(v)) { this.vertices.splice(1, 1, v); } else { const error = new TwoError("Two.Line.y argument is not an object."); console.warn(error.name, error.message); } } } }; // src/shapes/rounded-rectangle.js var _RoundedRectangle = class extends Path { _flagWidth = false; _flagHeight = false; _flagRadius = false; _width = 0; _height = 0; _radius = 12; constructor(x, y, width, height, radius) { if (typeof radius === "undefined" && typeof width === "number" && typeof height === "number") { radius = Math.floor(Math.min(width, height) / 12); } const points = []; for (let i = 0; i < 10; i++) { points.push( new Anchor( 0, 0, 0, 0, 0, 0, i === 0 ? Commands.move : Commands.curve ) ); } super(points); for (let prop in proto17) { Object.defineProperty(this, prop, proto17[prop]); } this.closed = true; this.automatic = false; this._renderer.flagRadius = FlagRadius.bind(this); if (typeof width === "number") { this.width = width; } if (typeof height === "number") { this.height = height; } if (typeof radius === "number") { this.radius = radius; } this._update(); if (typeof x === "number") { this.translation.x = x; } if (typeof y === "number") { this.translation.y = y; } } _update() { if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagRadius) { const width = this._width; const height = this._height; let rx, ry; if (this._radius instanceof Vector) { rx = this._radius.x; ry = this._radius.y; } else { rx = this._radius; ry = this._radius; } let v; let w = width / 2; let h = height / 2; v = this.vertices[0]; v.x = -(w - rx); v.y = -h; v = this.vertices[1]; v.x = w - rx; v.y = -h; v.controls.left.clear(); v.controls.right.x = rx; v.controls.right.y = 0; v = this.vertices[2]; v.x = w; v.y = -(h - ry); v.controls.right.clear(); v.controls.left.clear(); v = this.vertices[3]; v.x = w; v.y = h - ry; v.controls.left.clear(); v.controls.right.x = 0; v.controls.right.y = ry; v = this.vertices[4]; v.x = w - rx; v.y = h; v.controls.right.clear(); v.controls.left.clear(); v = this.vertices[5]; v.x = -(w - rx); v.y = h; v.controls.left.clear(); v.controls.right.x = -rx; v.controls.right.y = 0; v = this.vertices[6]; v.x = -w; v.y = h - ry; v.controls.left.clear(); v.controls.right.clear(); v = this.vertices[7]; v.x = -w; v.y = -(h - ry); v.controls.left.clear(); v.controls.right.x = 0; v.controls.right.y = -ry; v = this.vertices[8]; v.x = -(w - rx); v.y = -h; v.controls.left.clear(); v.controls.right.clear(); v = this.vertices[9]; v.copy(this.vertices[8]); } super._update.call(this); return this; } flagReset() { this._flagWidth = this._flagHeight = this._flagRadius = false; super.flagReset.call(this); return this; } clone(parent) { const width = this.width; const height = this.height; const radius = this.radius; const clone = new _RoundedRectangle(0, 0, width, height, radius); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } for (let i = 0; i < Path.Properties.length; i++) { const k = Path.Properties[i]; clone[k] = this[k]; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); for (let i = 0; i < _RoundedRectangle.Properties.length; i++) { const k = _RoundedRectangle.Properties[i]; object[k] = this[k]; } object.radius = typeof this.radius === "number" ? this.radius : this.radius.toObject(); return object; } }; var RoundedRectangle = _RoundedRectangle; __publicField(RoundedRectangle, "Properties", ["width", "height", "radius"]); var proto17 = { width: { enumerable: true, get: function() { return this._width; }, set: function(v) { this._width = v; this._flagWidth = true; } }, height: { enumerable: true, get: function() { return this._height; }, set: function(v) { this._height = v; this._flagHeight = true; } }, radius: { enumerable: true, get: function() { return this._radius; }, set: function(v) { if (this._radius instanceof Vector) { this._radius.unbind(Events.Types.change, this._renderer.flagRadius); } this._radius = v; if (this._radius instanceof Vector) { this._radius.bind(Events.Types.change, this._renderer.flagRadius); } this._flagRadius = true; } } }; function FlagRadius() { this._flagRadius = true; } // src/text.js var canvas2; var min4 = Math.min; var max4 = Math.max; if (root.document) { canvas2 = document.createElement("canvas"); } var _Text = class extends Shape { _flagValue = true; _flagFamily = true; _flagSize = true; _flagLeading = true; _flagAlignment = true; _flagBaseline = true; _flagStyle = true; _flagWeight = true; _flagDecoration = true; _flagFill = true; _flagStroke = true; _flagLinewidth = true; _flagOpacity = true; _flagVisible = true; _flagMask = false; _flagClip = false; _value = ""; _family = "sans-serif"; _size = 13; _leading = 17; _alignment = "center"; _baseline = "middle"; _style = "normal"; _weight = 500; _decoration = "none"; _direction = "ltr"; _fill = "#000"; _stroke = "none"; _linewidth = 1; _opacity = 1; _visible = true; _mask = null; _clip = false; _dashes = null; constructor(message, x, y, styles) { super(); for (let prop in proto18) { Object.defineProperty(this, prop, proto18[prop]); } this._renderer.type = "text"; this._renderer.flagFill = FlagFill2.bind(this); this._renderer.flagStroke = FlagStroke2.bind(this); this.value = message; if (typeof x === "number") { this.translation.x = x; } if (typeof y === "number") { this.translation.y = y; } this.dashes = []; this.dashes.offset = 0; if (!_.isObject(styles)) { return this; } for (let i = 0; i < _Text.Properties.length; i++) { const property = _Text.Properties[i]; if (property in styles) { this[property] = styles[property]; } } } static Measure(text) { if (canvas2) { const ctx = canvas2.getContext("2d"); ctx.font = [ text._style, text._weight, `${text._size}px/${text._leading}px`, text._family ].join(" "); const metrics = ctx.measureText(text.value, 0, 0); const height = metrics.actualBoundingBoxDescent + metrics.actualBoundingBoxAscent; return { width: metrics.width, height }; } else { const width = this.value.length * this.size * _Text.Ratio; const height = this.leading; console.warn("Two.Text: unable to accurately measure text, so using an approximation."); return { width, height }; } } clone(parent) { const clone = new _Text(this.value); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; for (let i = 0; i < _Text.Properties.length; i++) { const prop = _Text.Properties[i]; clone[prop] = this[prop]; } if (this.matrix.manual) { clone.matrix.copy(this.matrix); } if (parent) { parent.add(clone); } return clone._update(); } toObject() { const result = { translation: this.translation.toObject(), rotation: this.rotation, scale: this.scale }; if (this.matrix.manual) { result.matrix = this.matrix.toObject(); } for (let i = 0; i < _Text.Properties.length; i++) { const prop = _Text.Properties[i]; result[prop] = this[prop]; } return result; } noFill() { this.fill = "none"; return this; } noStroke() { this.stroke = "none"; this.linewidth = 0; return this; } getBoundingClientRect(shallow) { let matrix; let left, right, top, bottom; this._update(true); matrix = shallow ? this.matrix : this.worldMatrix; const { width, height } = _Text.Measure(this); const border = (this._linewidth || 0) / 2; switch (this.alignment) { case "left": left = -border; right = width + border; break; case "right": left = -(width + border); right = border; break; default: left = -(width / 2 + border); right = width / 2 + border; } switch (this.baseline) { case "middle": top = -(height / 2 + border); bottom = height / 2 + border; break; default: top = -(height + border); bottom = border; } const [ax, ay] = matrix.multiply(left, top); const [bx, by] = matrix.multiply(left, bottom); const [cx, cy] = matrix.multiply(right, top); const [dx, dy] = matrix.multiply(right, bottom); top = min4(ay, by, cy, dy); left = min4(ax, bx, cx, dx); right = max4(ax, bx, cx, dx); bottom = max4(ay, by, cy, dy); return { top, left, right, bottom, width: right - left, height: bottom - top }; } flagReset() { super.flagReset.call(this); this._flagValue = this._flagFamily = this._flagSize = this._flagLeading = this._flagAlignment = this._flagFill = this._flagStroke = this._flagLinewidth = this._flagOpacity = this._flagVisible = this._flagClip = this._flagDecoration = this._flagClassName = this._flagBaseline = this._flagWeight = this._flagStyle = false; return this; } }; var Text = _Text; __publicField(Text, "Ratio", 0.6); __publicField(Text, "Properties", [ "value", "family", "size", "leading", "alignment", "linewidth", "style", "weight", "decoration", "direction", "baseline", "opacity", "visible", "fill", "stroke" ]); var proto18 = { value: { enumerable: true, get: function() { return this._value; }, set: function(v) { this._value = v; this._flagValue = true; } }, family: { enumerable: true, get: function() { return this._family; }, set: function(v) { this._family = v; this._flagFamily = true; } }, size: { enumerable: true, get: function() { return this._size; }, set: function(v) { this._size = v; this._flagSize = true; } }, leading: { enumerable: true, get: function() { return this._leading; }, set: function(v) { this._leading = v; this._flagLeading = true; } }, alignment: { enumerable: true, get: function() { return this._alignment; }, set: function(v) { this._alignment = v; this._flagAlignment = true; } }, linewidth: { enumerable: true, get: function() { return this._linewidth; }, set: function(v) { this._linewidth = v; this._flagLinewidth = true; } }, style: { enumerable: true, get: function() { return this._style; }, set: function(v) { this._style = v; this._flagStyle = true; } }, weight: { enumerable: true, get: function() { return this._weight; }, set: function(v) { this._weight = v; this._flagWeight = true; } }, decoration: { enumerable: true, get: function() { return this._decoration; }, set: function(v) { this._decoration = v; this._flagDecoration = true; } }, direction: { enumerable: true, get: function() { return this._direction; }, set: function(v) { this._direction = v; this._flagDirection = true; } }, baseline: { enumerable: true, get: function() { return this._baseline; }, set: function(v) { this._baseline = v; this._flagBaseline = true; } }, opacity: { enumerable: true, get: function() { return this._opacity; }, set: function(v) { this._opacity = v; this._flagOpacity = true; } }, visible: { enumerable: true, get: function() { return this._visible; }, set: function(v) { this._visible = v; this._flagVisible = true; } }, fill: { enumerable: true, get: function() { return this._fill; }, set: function(f) { if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) { this._fill.unbind(Events.Types.change, this._renderer.flagFill); } this._fill = f; this._flagFill = true; if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) { this._fill.bind(Events.Types.change, this._renderer.flagFill); } } }, stroke: { enumerable: true, get: function() { return this._stroke; }, set: function(f) { if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) { this._stroke.unbind(Events.Types.change, this._renderer.flagStroke); } this._stroke = f; this._flagStroke = true; if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) { this._stroke.bind(Events.Types.change, this._renderer.flagStroke); } } }, mask: { enumerable: true, get: function() { return this._mask; }, set: function(v) { this._mask = v; this._flagMask = true; if (_.isObject(v) && !v.clip) { v.clip = true; } } }, clip: { enumerable: true, get: function() { return this._clip; }, set: function(v) { this._clip = v; this._flagClip = true; } }, dashes: { enumerable: true, get: function() { return this._dashes; }, set: function(v) { if (typeof v.offset !== "number") { v.offset = this.dashes && this._dashes.offset || 0; } this._dashes = v; } } }; function FlagFill2() { this._flagFill = true; } function FlagStroke2() { this._flagStroke = true; } // src/utils/interpret-svg.js var regex2 = { path: /[+-]?(?:\d*\.\d+|\d+)(?:[eE][+-]\d+)?/g, cssBackgroundImage: /url\(['"]?#([\w\d-_]*)['"]?\)/i, unitSuffix: /[a-zA-Z%]*/i }; var alignments = { start: "left", middle: "center", end: "right" }; var reservedAttributesToRemove = ["id", "class", "transform", "xmlns", "viewBox"]; var overwriteAttrs = ["x", "y", "width", "height", "href", "xlink:href"]; function getAlignment(anchor2) { return alignments[anchor2]; } function getBaseline(node) { const a = node.getAttribute("dominant-baseline"); const b = node.getAttribute("alignment-baseline"); return a || b; } function getTagName(tag) { return tag.replace(/svg:/ig, "").toLowerCase(); } function applyTransformsToVector(transforms, vector3) { vector3.x += transforms.translateX; vector3.y += transforms.translateY; vector3.x *= transforms.scaleX; vector3.y *= transforms.scaleY; if (transforms.rotation !== 0) { const l = vector3.length(); vector3.x = l * Math.cos(transforms.rotation); vector3.y = l * Math.sin(transforms.rotation); } } function extractCSSText(text, styles) { if (!styles) { styles = {}; } const commands = text.split(";"); for (let i = 0; i < commands.length; i++) { const command = commands[i].split(":"); const name = command[0]; const value = command[1]; if (typeof name === "undefined" || typeof value === "undefined") { continue; } styles[name] = value.replace(/\s/, ""); } return styles; } function getSvgStyles(node) { const styles = {}; const attributes = getSvgAttributes(node); const length = Math.max(attributes.length, node.style.length); for (let i = 0; i < length; i++) { const command = node.style[i]; const attribute = attributes[i]; if (command) { styles[command] = node.style[command]; } if (attribute) { styles[attribute] = node.getAttribute(attribute); } } return styles; } function getSvgAttributes(node) { const attributes = node.getAttributeNames(); for (let i = 0; i < reservedAttributesToRemove.length; i++) { const keyword = reservedAttributesToRemove[i]; const index = Array.prototype.indexOf.call(attributes, keyword); if (index >= 0) { attributes.splice(index, 1); } } return attributes; } function applySvgViewBox(node, value) { const elements = value.split(/[\s,]/); const x = -parseFloat(elements[0]); const y = -parseFloat(elements[1]); const width = parseFloat(elements[2]); const height = parseFloat(elements[3]); if (x && y) { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; if ("translation" in child) { child.translation.add(x, y); } else if ("x" in child) { child.x = x; } else if ("y" in child) { child.y = y; } } } const xExists = typeof node.x === "number"; const yExists = typeof node.y === "number"; const widthExists = typeof node.width === "number"; const heightExists = typeof node.height === "number"; if (xExists) { node.translation.x += node.x; } if (yExists) { node.translation.y += node.y; } if (widthExists || heightExists) { node.scale = new Vector(1, 1); } if (widthExists) { node.scale.x = node.width / width; } if (heightExists) { node.scale.y = node.height / height; } node.mask = new Rectangle(0, 0, width, height); node.mask.origin.set(-width / 2, -height / 2); return node; } function applySvgAttributes(node, elem, parentStyles) { const styles = {}, attributes = {}, extracted = {}; let i, m, key, value, prop, attr; let transforms, x, y; let id, scene, ref, tagName; let ca, cb, cc, error; if (node === null) { return styles; } if (root.getComputedStyle) { const computedStyles = root.getComputedStyle(node); i = computedStyles.length; while (i--) { key = computedStyles[i]; value = computedStyles[key]; if (typeof value !== "undefined") { styles[key] = value; } } } for (i = 0; i < node.attributes.length; i++) { attr = node.attributes[i]; if (/style/i.test(attr.nodeName)) { extractCSSText(attr.value, extracted); } else { attributes[attr.nodeName] = attr.value; } } if (typeof styles.opacity !== "undefined") { styles["stroke-opacity"] = styles.opacity; styles["fill-opacity"] = styles.opacity; delete styles.opacity; } if (parentStyles) { _.defaults(styles, parentStyles); } _.extend(styles, extracted, attributes); styles.visible = !(typeof styles.display === "undefined" && /none/i.test(styles.display)) || typeof styles.visibility === "undefined" && /hidden/i.test(styles.visibility); for (key in styles) { value = styles[key]; switch (key) { case "gradientTransform": if (/none/i.test(value)) break; m = node.gradientTransform && node.gradientTransform.baseVal && node.gradientTransform.baseVal.length > 0 ? node.gradientTransform.baseVal[0].matrix : node.getCTM ? node.getCTM() : null; if (m === null) break; transforms = decomposeMatrix(m); switch (elem._renderer.type) { case "linear-gradient": applyTransformsToVector(transforms, elem.left); applyTransformsToVector(transforms, elem.right); break; case "radial-gradient": elem.center.x += transforms.translateX; elem.center.y += transforms.translateY; elem.focal.x += transforms.translateX; elem.focal.y += transforms.translateY; elem.radius *= Math.max(transforms.scaleX, transforms.scaleY); break; } break; case "transform": if (/none/i.test(value)) break; m = node.transform && node.transform.baseVal && node.transform.baseVal.length > 0 ? node.transform.baseVal[0].matrix : node.getCTM ? node.getCTM() : null; if (m === null) break; if (Constants.AutoCalculateImportedMatrices) { transforms = decomposeMatrix(m); elem.translation.set(transforms.translateX, transforms.translateY); elem.rotation = Math.PI * (transforms.rotation / 180); elem.scale = new Vector(transforms.scaleX, transforms.scaleY); x = parseFloat((styles.x + "").replace("px")); y = parseFloat((styles.y + "").replace("px")); if (x) { elem.translation.x = x; } if (y) { elem.translation.y = y; } } else { m = node.getCTM(); elem._matrix.manual = true; elem._matrix.set(m.a, m.b, m.c, m.d, m.e, m.f); } break; case "visible": if (elem instanceof Group) { elem._visible = value; break; } elem.visible = value; break; case "stroke-linecap": if (elem instanceof Group) { elem._cap = value; break; } elem.cap = value; break; case "stroke-linejoin": if (elem instanceof Group) { elem._join = value; break; } elem.join = value; break; case "stroke-miterlimit": if (elem instanceof Group) { elem._miter = value; break; } elem.miter = value; break; case "stroke-width": if (elem instanceof Group) { elem._linewidth = parseFloat(value); break; } elem.linewidth = parseFloat(value); break; case "opacity": case "stroke-opacity": case "fill-opacity": if (elem instanceof Group) { elem._opacity = parseFloat(value); break; } elem.opacity = parseFloat(value); break; case "clip-path": if (regex2.cssBackgroundImage.test(value)) { id = value.replace(regex2.cssBackgroundImage, "$1"); if (read.defs.current && read.defs.current.contains(id)) { ref = read.defs.current.get(id); if (ref && ref.childNodes.length > 0) { ref = ref.childNodes[0]; tagName = getTagName(ref.nodeName); elem.mask = read[tagName].call(this, ref, {}); switch (elem._renderer.type) { case "text": case "path": elem.position.add(elem.mask.position); elem.mask.position.clear(); break; } } } } break; case "fill": case "stroke": prop = (elem instanceof Group ? "_" : "") + key; if (regex2.cssBackgroundImage.test(value)) { id = value.replace(regex2.cssBackgroundImage, "$1"); if (read.defs.current && read.defs.current.contains(id)) { ref = read.defs.current.get(id); if (!ref.object) { tagName = getTagName(ref.nodeName); ref.object = read[tagName].call(this, ref, {}); } ref = ref.object; } else { scene = getScene(this); ref = scene.getById(id); } elem[prop] = ref; } else { elem[prop] = value; } break; case "id": elem.id = value; break; case "class": case "className": elem.classList = value.split(" "); elem._flagClassName = true; break; case "x": case "y": ca = elem instanceof Gradient; cb = elem instanceof LinearGradient; cc = elem instanceof RadialGradient; if (ca || cb || cc) { break; } if (value.match("[a-z%]$") && !value.endsWith("px")) { error = new TwoError( "only pixel values are supported with the " + key + " attribute." ); console.warn(error.name, error.message); } elem.translation[key] = parseFloat(value); break; case "font-family": if (elem instanceof Text) { elem.family = value; } break; case "font-size": if (elem instanceof Text) { elem.size = value; } break; case "font-weight": if (elem instanceof Text) { elem.weight = value; } break; case "font-style": if (elem instanceof Text) { elem.style = value; } break; case "text-decoration": if (elem instanceof Text) { elem.decoration = value; } break; case "line-height": if (elem instanceof Text) { elem.leading = value; } break; } } if (Object.keys(node.dataset).length) elem.dataset = node.dataset; return styles; } function updateDefsCache(node, defsCache) { for (let i = 0, l = node.childNodes.length; i < l; i++) { const n = node.childNodes[i]; if (!n.id) continue; const tagName = getTagName(node.nodeName); if (tagName === "#text") continue; defsCache.add(n.id, n); } } function getScene(node) { while (node.parent) { node = node.parent; } return node.scene; } var read = { svg: function(node) { const defs = read.defs.current = new Registry(); const elements = node.getElementsByTagName("defs"); for (let i = 0; i < elements.length; i++) { updateDefsCache(elements[i], defs); } const svg2 = read.g.call(this, node); const viewBox = node.getAttribute("viewBox"); const x = node.getAttribute("x"); const y = node.getAttribute("y"); const width = node.getAttribute("width"); const height = node.getAttribute("height"); svg2.defs = defs; const viewBoxExists = viewBox !== null; const xExists = x !== null; const yExists = y !== null; const widthExists = width !== null; const heightExists = height !== null; if (xExists) { svg2.x = parseFloat(x.replace(regex2.unitSuffix, "")); } if (yExists) { svg2.y = parseFloat(y.replace(regex2.unitSuffix, "")); } if (widthExists) { svg2.width = parseFloat(width.replace(regex2.unitSuffix, "")); } if (heightExists) { svg2.height = parseFloat(height.replace(regex2.unitSuffix, "")); } if (viewBoxExists) { applySvgViewBox(svg2, viewBox); } delete read.defs.current; return svg2; }, defs: function(node) { return null; }, use: function(node, styles) { let error; const href = node.getAttribute("href") || node.getAttribute("xlink:href"); if (!href) { error = new TwoError("encountered with no href."); console.warn(error.name, error.message); return null; } const id = href.slice(1); if (!read.defs.current.contains(id)) { error = new TwoError( "unable to find element for reference " + href + "." ); console.warn(error.name, error.message); return null; } const template = read.defs.current.get(id); const fullNode = template.cloneNode(true); for (let i = 0; i < node.attributes.length; i++) { const attr = node.attributes[i]; const ca = overwriteAttrs.includes(attr.nodeName); const cb = !fullNode.hasAttribute(attr.nodeName); if (ca || cb) { fullNode.setAttribute(attr.nodeName, attr.value); } } const tagName = getTagName(fullNode.nodeName); return read[tagName].call(this, fullNode, styles); }, g: function(node, parentStyles) { const group = new Group(); applySvgAttributes.call(this, node, group, parentStyles); this.add(group); const styles = getSvgStyles.call(this, node); for (let i = 0, l = node.childNodes.length; i < l; i++) { const n = node.childNodes[i]; const tag = n.nodeName; if (!tag) return; const tagName = getTagName(tag); if (tagName in read) { const o = read[tagName].call(group, n, styles); if (!!o && !o.parent) { group.add(o); } } } return group; }, polygon: function(node, parentStyles) { let points; if (typeof node === "string") { points = node; } else { points = node.getAttribute("points"); } const verts = []; points.replace(/(-?[\d.eE-]+)[,|\s](-?[\d.eE-]+)/g, function(match, p1, p2) { verts.push(new Anchor(parseFloat(p1), parseFloat(p2))); }); const poly = new Path(verts, true).noStroke(); poly.fill = "black"; applySvgAttributes.call(this, node, poly, parentStyles); return poly; }, polyline: function(node, parentStyles) { const poly = read.polygon.call(this, node, parentStyles); poly.closed = false; return poly; }, path: function(node, parentStyles) { let path; if (typeof node === "string") { path = node; node = null; } else { path = node.getAttribute("d"); } let points = []; let closed2 = false, relative = false; if (path) { let coord = new Anchor(); let control, coords; let commands = path.match(/[a-df-z][^a-df-z]*/ig); const last = commands.length - 1; _.each(commands.slice(0), function(command, i) { const items = command.slice(1).trim().match(regex2.path); const type = command[0]; const lower = type.toLowerCase(); let bin, j, l, ct, times; const result = []; if (i === 0) { commands = []; } switch (lower) { case "h": case "v": if (items.length > 1) { bin = 1; } break; case "m": case "l": case "t": if (items.length > 2) { bin = 2; } break; case "s": case "q": if (items.length > 4) { bin = 4; } break; case "c": if (items.length > 6) { bin = 6; } break; case "a": if (items.length > 7) { bin = 7; } break; } if (bin) { for (j = 0, l = items.length, times = 0; j < l; j += bin) { ct = type; if (times > 0) { switch (type) { case "m": ct = "l"; break; case "M": ct = "L"; break; } } result.push(ct + items.slice(j, j + bin).join(" ")); times++; } commands = Array.prototype.concat.apply(commands, result); } else { commands.push(command); } }); _.each(commands, function(command, i) { let result, x, y; const type = command[0]; const lower = type.toLowerCase(); coords = command.slice(1).trim().match(regex2.path); relative = type === lower; let x1, y1, x2, y2, x3, y3, x4, y4, reflection; let a, b; let anchor2, rx, ry, xAxisRotation, largeArcFlag, sweepFlag; switch (lower) { case "z": if (i >= last) { closed2 = true; } else { x = coord.x; y = coord.y; result = new Anchor( x, y, void 0, void 0, void 0, void 0, Commands.close ); for (let j = points.length - 1; j >= 0; j--) { const point = points[j]; if (/m/i.test(point.command)) { coord = point; break; } } } break; case "m": case "l": control = void 0; x = parseFloat(coords[0]); y = parseFloat(coords[1]); result = new Anchor( x, y, void 0, void 0, void 0, void 0, /m/i.test(lower) ? Commands.move : Commands.line ); if (relative) { result.addSelf(coord); } coord = result; break; case "h": case "v": a = /h/i.test(lower) ? "x" : "y"; b = /x/i.test(a) ? "y" : "x"; result = new Anchor( void 0, void 0, void 0, void 0, void 0, void 0, Commands.line ); result[a] = parseFloat(coords[0]); result[b] = coord[b]; if (relative) { result[a] += coord[a]; } coord = result; break; case "c": case "s": x1 = coord.x; y1 = coord.y; if (!control) { control = new Vector(); } if (/c/i.test(lower)) { x2 = parseFloat(coords[0]); y2 = parseFloat(coords[1]); x3 = parseFloat(coords[2]); y3 = parseFloat(coords[3]); x4 = parseFloat(coords[4]); y4 = parseFloat(coords[5]); } else { reflection = getReflection(coord, control, relative); x2 = reflection.x; y2 = reflection.y; x3 = parseFloat(coords[0]); y3 = parseFloat(coords[1]); x4 = parseFloat(coords[2]); y4 = parseFloat(coords[3]); } if (relative) { x2 += x1; y2 += y1; x3 += x1; y3 += y1; x4 += x1; y4 += y1; } coord.controls.right.set(x2 - coord.x, y2 - coord.y); result = new Anchor( x4, y4, x3 - x4, y3 - y4, void 0, void 0, Commands.curve ); coord = result; control = result.controls.left; break; case "t": case "q": x1 = coord.x; y1 = coord.y; if (!control) { control = new Vector(); } if (/q/i.test(lower)) { x2 = parseFloat(coords[0]); y2 = parseFloat(coords[1]); x3 = parseFloat(coords[0]); y3 = parseFloat(coords[1]); x4 = parseFloat(coords[2]); y4 = parseFloat(coords[3]); } else { reflection = getReflection(coord, control, relative); x2 = reflection.x; y2 = reflection.y; x3 = reflection.x; y3 = reflection.y; x4 = parseFloat(coords[0]); y4 = parseFloat(coords[1]); } if (relative) { x2 += x1; y2 += y1; x3 += x1; y3 += y1; x4 += x1; y4 += y1; } coord.controls.right.set( (x2 - coord.x) * 0.33, (y2 - coord.y) * 0.33 ); result = new Anchor( x4, y4, x3 - x4, y3 - y4, void 0, void 0, Commands.curve ); coord = result; control = result.controls.left; break; case "a": x1 = coord.x; y1 = coord.y; rx = parseFloat(coords[0]); ry = parseFloat(coords[1]); xAxisRotation = parseFloat(coords[2]); largeArcFlag = parseFloat(coords[3]); sweepFlag = parseFloat(coords[4]); x4 = parseFloat(coords[5]); y4 = parseFloat(coords[6]); if (relative) { x4 += x1; y4 += y1; } anchor2 = new Anchor(x4, y4); anchor2.command = Commands.arc; anchor2.rx = rx; anchor2.ry = ry; anchor2.xAxisRotation = xAxisRotation; anchor2.largeArcFlag = largeArcFlag; anchor2.sweepFlag = sweepFlag; result = anchor2; coord = anchor2; control = void 0; break; } if (result) { if (Array.isArray(result)) { points = points.concat(result); } else { points.push(result); } } }); } path = new Path(points, closed2, void 0, true).noStroke(); path.fill = "black"; const rect = path.getBoundingClientRect(true); rect.centroid = { x: rect.left + rect.width / 2, y: rect.top + rect.height / 2 }; _.each(path.vertices, function(v) { v.subSelf(rect.centroid); }); applySvgAttributes.call(this, node, path, parentStyles); path.translation.addSelf(rect.centroid); return path; }, circle: function(node, parentStyles) { const x = parseFloat(node.getAttribute("cx")); const y = parseFloat(node.getAttribute("cy")); const r = parseFloat(node.getAttribute("r")); const circle = new Circle(0, 0, r).noStroke(); circle.fill = "black"; applySvgAttributes.call(this, node, circle, parentStyles); circle.translation.x = x; circle.translation.y = y; return circle; }, ellipse: function(node, parentStyles) { const x = parseFloat(node.getAttribute("cx")); const y = parseFloat(node.getAttribute("cy")); const width = parseFloat(node.getAttribute("rx")); const height = parseFloat(node.getAttribute("ry")); const ellipse = new Ellipse(0, 0, width, height).noStroke(); ellipse.fill = "black"; applySvgAttributes.call(this, node, ellipse, parentStyles); ellipse.translation.x = x; ellipse.translation.y = y; return ellipse; }, rect: function(node, parentStyles) { const rx = parseFloat(node.getAttribute("rx")); const ry = parseFloat(node.getAttribute("ry")); if (!_.isNaN(rx) || !_.isNaN(ry)) { return read["rounded-rect"](node); } const width = parseFloat(node.getAttribute("width")); const height = parseFloat(node.getAttribute("height")); const w2 = width / 2; const h2 = height / 2; const rect = new Rectangle(0, 0, width, height).noStroke(); rect.fill = "black"; applySvgAttributes.call(this, node, rect, parentStyles); rect.translation.x += w2; rect.translation.y += h2; return rect; }, "rounded-rect": function(node, parentStyles) { const rx = parseFloat(node.getAttribute("rx")) || 0; const ry = parseFloat(node.getAttribute("ry")) || 0; const width = parseFloat(node.getAttribute("width")); const height = parseFloat(node.getAttribute("height")); const w2 = width / 2; const h2 = height / 2; const radius = new Vector(rx, ry); const rect = new RoundedRectangle(0, 0, width, height, radius).noStroke(); rect.fill = "black"; applySvgAttributes.call(this, node, rect, parentStyles); rect.translation.x += w2; rect.translation.y += h2; return rect; }, line: function(node, parentStyles) { const x1 = parseFloat(node.getAttribute("x1")); const y1 = parseFloat(node.getAttribute("y1")); const x2 = parseFloat(node.getAttribute("x2")); const y2 = parseFloat(node.getAttribute("y2")); const line = new Line(x1, y1, x2, y2).noFill(); applySvgAttributes.call(this, node, line, parentStyles); return line; }, lineargradient: function(node, parentStyles) { let units = node.getAttribute("gradientUnits"); let spread = node.getAttribute("spreadMethod"); if (!units) { units = "objectBoundingBox"; } if (!spread) { spread = "pad"; } let x1 = parseFloat(node.getAttribute("x1") || 0); let y1 = parseFloat(node.getAttribute("y1") || 0); let x2 = parseFloat(node.getAttribute("x2") || 0); let y2 = parseFloat(node.getAttribute("y2") || 0); const ox = (x2 + x1) / 2; const oy = (y2 + y1) / 2; if (/userSpaceOnUse/i.test(units)) { x1 -= ox; y1 -= oy; x2 -= ox; y2 -= oy; } const stops = []; for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; let offset = child.getAttribute("offset"); if (/%/ig.test(offset)) { offset = parseFloat(offset.replace(/%/ig, "")) / 100; } offset = parseFloat(offset); let color = child.getAttribute("stop-color"); let opacity = child.getAttribute("stop-opacity"); let style = child.getAttribute("style"); let matches; if (color === null) { matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false; color = matches && matches.length > 1 ? matches[1] : void 0; } if (opacity === null) { matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false; opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1; } else { opacity = parseFloat(opacity); } stops.push(new Stop(offset, color, opacity)); } const gradient = new LinearGradient(x1, y1, x2, y2, stops); gradient.spread = spread; gradient.units = units; applySvgAttributes.call(this, node, gradient, parentStyles); return gradient; }, radialgradient: function(node, parentStyles) { let units = node.getAttribute("gradientUnits"); let spread = node.getAttribute("spreadMethod"); if (!units) { units = "objectBoundingBox"; } if (!spread) { spread = "pad"; } let cx = parseFloat(node.getAttribute("cx")) || 0; let cy = parseFloat(node.getAttribute("cy")) || 0; let r = parseFloat(node.getAttribute("r")); let fx = parseFloat(node.getAttribute("fx")); let fy = parseFloat(node.getAttribute("fy")); if (_.isNaN(fx)) { fx = cx; } if (_.isNaN(fy)) { fy = cy; } const ox = Math.abs(cx + fx) / 2; const oy = Math.abs(cy + fy) / 2; if (/userSpaceOnUse/i.test(units)) { cx -= ox; cy -= oy; fx -= ox; fy -= oy; } const stops = []; for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; let offset = child.getAttribute("offset"); if (/%/ig.test(offset)) { offset = parseFloat(offset.replace(/%/ig, "")) / 100; } offset = parseFloat(offset); let color = child.getAttribute("stop-color"); let opacity = child.getAttribute("stop-opacity"); let style = child.getAttribute("style"); let matches; if (color === null) { matches = style ? style.match(/stop-color:\s?([#a-fA-F0-9]*)/) : false; color = matches && matches.length > 1 ? matches[1] : void 0; } if (opacity === null) { matches = style ? style.match(/stop-opacity:\s?([0-9.-]*)/) : false; opacity = matches && matches.length > 1 ? parseFloat(matches[1]) : 1; } else { opacity = parseFloat(opacity); } stops.push(new Stop(offset, color, opacity)); } const gradient = new RadialGradient(cx, cy, r, stops, fx, fy); gradient.spread = spread; gradient.units = units; applySvgAttributes.call(this, node, gradient, parentStyles); return gradient; }, text: function(node, parentStyles) { const alignment = getAlignment(node.getAttribute("text-anchor")) || "left"; const baseline = getBaseline(node) || "baseline"; const message = node.textContent; const text = new Text(message); applySvgAttributes.call(this, node, text, parentStyles); text.alignment = alignment; text.baseline = baseline; return text; }, clippath: function(node, parentStyles) { if (read.defs.current && !read.defs.current.contains(node.id)) { read.defs.current.add(node.id, node); } return null; }, image: function(node, parentStyles) { let error; const href = node.getAttribute("href") || node.getAttribute("xlink:href"); if (!href) { error = new TwoError("encountered with no href."); console.warn(error.name, error.message); return null; } const x = parseFloat(node.getAttribute("x")) || 0; const y = parseFloat(node.getAttribute("y")) || 0; const width = parseFloat(node.getAttribute("width")); const height = parseFloat(node.getAttribute("height")); const sprite = new Sprite(href, x, y); if (!_.isNaN(width)) { sprite.width = width; } if (!_.isNaN(height)) { sprite.height = height; } applySvgAttributes.call(this, node, sprite, parentStyles); return sprite; } }; // src/utils/xhr.js function xhr(path, callback) { const xhr2 = new XMLHttpRequest(); xhr2.open("GET", path); xhr2.onreadystatechange = function() { if (xhr2.readyState === 4 && xhr2.status === 200) { callback(xhr2.responseText); } }; xhr2.send(); return xhr2; } // src/effects/image-sequence.js var _ImageSequence = class extends Rectangle { _flagTextures = false; _flagFrameRate = false; _flagIndex = false; _amount = 1; _duration = 0; _index = 0; _startTime = 0; _playing = false; _firstFrame = 0; _lastFrame = 0; _loop = true; _textures = null; _frameRate = 0; _origin = null; constructor(paths, ox, oy, frameRate) { super(ox, oy, 0, 0); for (let prop in proto19) { Object.defineProperty(this, prop, proto19[prop]); } this._renderer.flagTextures = FlagTextures.bind(this); this._renderer.bindTextures = BindTextures.bind(this); this._renderer.unbindTextures = UnbindTextures.bind(this); this.noStroke(); this.noFill(); if (Array.isArray(paths)) { this.textures = paths.map(GenerateTexture.bind(this)); } else { this.textures = [GenerateTexture(paths)]; } this.origin = new Vector(); this._update(); if (typeof frameRate === "number") { this.frameRate = frameRate; } else { this.frameRate = _ImageSequence.DefaultFrameRate; } this.index = 0; } play(firstFrame, lastFrame, onLastFrame) { this._playing = true; this._firstFrame = 0; this._lastFrame = this.amount - 1; this._startTime = _.performance.now(); if (typeof firstFrame === "number") { this._firstFrame = firstFrame; } if (typeof lastFrame === "number") { this._lastFrame = lastFrame; } if (typeof onLastFrame === "function") { this._onLastFrame = onLastFrame; } else { delete this._onLastFrame; } if (this._index !== this._firstFrame) { this._startTime -= 1e3 * Math.abs(this._index - this._firstFrame) / this._frameRate; } return this; } pause() { this._playing = false; return this; } stop() { this._playing = false; this._index = this._firstFrame; return this; } clone(parent) { const clone = new _ImageSequence( this.textures, this.translation.x, this.translation.y, this.frameRate ); clone._loop = this._loop; if (this._playing) { clone.play(); } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); object.textures = this.textures.map(function(texture) { return texture.toObject(); }); object.frameRate = this.frameRate; object.index = this.index; object._firstFrame = this._firstFrame; object._lastFrame = this._lastFrame; object._loop = this._loop; return object; } _update() { const effect = this._textures; let width, height, elapsed, amount, duration, texture; let index, frames; if (effect) { if (this._flagTextures) { this._amount = effect.length; } if (this._flagFrameRate) { this._duration = 1e3 * this._amount / this._frameRate; } if (this._playing && this._frameRate > 0) { amount = this._amount; if (_.isNaN(this._lastFrame)) { this._lastFrame = amount - 1; } elapsed = _.performance.now() - this._startTime; frames = this._lastFrame + 1; duration = 1e3 * (frames - this._firstFrame) / this._frameRate; if (this._loop) { elapsed = elapsed % duration; } else { elapsed = Math.min(elapsed, duration); } index = lerp(this._firstFrame, frames, elapsed / duration); index = Math.floor(index); if (index !== this._index) { this._index = index; texture = effect[this._index]; if (texture.loaded) { width = texture.image.width; height = texture.image.height; if (this.width !== width) { this.width = width; } if (this.height !== height) { this.height = height; } this.fill = texture; if (index >= this._lastFrame - 1 && this._onLastFrame) { this._onLastFrame(); } } } } else if (this._flagIndex || !(this.fill instanceof Texture)) { texture = effect[this._index]; if (texture.loaded) { width = texture.image.width; height = texture.image.height; if (this.width !== width) { this.width = width; } if (this.height !== height) { this.height = height; } } this.fill = texture; } } super._update.call(this); return this; } flagReset() { this._flagTextures = this._flagFrameRate = false; super.flagReset.call(this); return this; } }; var ImageSequence = _ImageSequence; __publicField(ImageSequence, "Properties", [ "textures", "frameRate", "index" ]); __publicField(ImageSequence, "DefaultFrameRate", 30); var proto19 = { frameRate: { enumerable: true, get: function() { return this._frameRate; }, set: function(v) { this._frameRate = v; this._flagFrameRate = true; } }, index: { enumerable: true, get: function() { return this._index; }, set: function(v) { this._index = v; this._flagIndex = true; } }, textures: { enumerable: true, get: function() { return this._textures; }, set: function(textures) { const bindTextures = this._renderer.bindTextures; const unbindTextures = this._renderer.unbindTextures; if (this._textures) { this._textures.unbind(Events.Types.insert, bindTextures).unbind(Events.Types.remove, unbindTextures); } this._textures = new Collection((textures || []).slice(0)); this._textures.bind(Events.Types.insert, bindTextures).bind(Events.Types.remove, unbindTextures); bindTextures(this._textures); } } }; function FlagTextures() { this._flagTextures = true; } function BindTextures(items) { let i = items.length; while (i--) { items[i].bind(Events.Types.change, this._renderer.flagTextures); } this._renderer.flagTextures(); } function UnbindTextures(items) { let i = items.length; while (i--) { items[i].unbind(Events.Types.change, this._renderer.flagTextures); } this._renderer.flagTextures(); } function GenerateTexture(obj) { if (obj instanceof Texture) { return obj; } else if (typeof obj === "string") { return new Texture(obj); } } // src/shapes/arc-segment.js var _ArcSegment = class extends Path { _flagStartAngle = false; _flagEndAngle = false; _flagInnerRadius = false; _flagOuterRadius = false; _startAngle = 0; _endAngle = TWO_PI; _innerRadius = 0; _outerRadius = 0; constructor(x, y, ir, or, sa, ea, res) { const amount = res || Constants.Resolution * 3; const points = []; for (let i = 0; i < amount; i++) { points.push(new Anchor()); } super(points, true, false, true); for (let prop in proto20) { Object.defineProperty(this, prop, proto20[prop]); } if (typeof ir === "number") { this.innerRadius = ir; } if (typeof or === "number") { this.outerRadius = or; } if (typeof sa === "number") { this.startAngle = sa; } if (typeof ea === "number") { this.endAngle = ea; } this._update(); if (typeof x === "number") { this.translation.x = x; } if (typeof y === "number") { this.translation.y = y; } } _update() { if (this._flagVertices || this._flagStartAngle || this._flagEndAngle || this._flagInnerRadius || this._flagOuterRadius) { const sa = this._startAngle; const ea = this._endAngle; const ir = this._innerRadius; const or = this._outerRadius; const connected = mod(sa, TWO_PI) === mod(ea, TWO_PI); const punctured = ir > 0; const vertices = this.vertices; let length = punctured ? vertices.length / 2 : vertices.length; let command, id = 0; let i, last, pct, v, theta, step, x, y, amp; if (connected) { length--; } else if (!punctured) { length -= 2; } for (i = 0, last = length - 1; i < length; i++) { pct = i / last; v = vertices[id]; theta = pct * (ea - sa) + sa; step = (ea - sa) / length; x = or * Math.cos(theta); y = or * Math.sin(theta); switch (i) { case 0: command = Commands.move; break; default: command = Commands.curve; } v.command = command; v.x = x; v.y = y; v.controls.left.clear(); v.controls.right.clear(); if (v.command === Commands.curve) { amp = or * step / Math.PI; v.controls.left.x = amp * Math.cos(theta - HALF_PI); v.controls.left.y = amp * Math.sin(theta - HALF_PI); v.controls.right.x = amp * Math.cos(theta + HALF_PI); v.controls.right.y = amp * Math.sin(theta + HALF_PI); if (i === 1) { v.controls.left.multiplyScalar(2); } if (i === last) { v.controls.right.multiplyScalar(2); } } id++; } if (punctured) { if (connected) { vertices[id].command = Commands.close; id++; } else { length--; last = length - 1; } for (i = 0; i < length; i++) { pct = i / last; v = vertices[id]; theta = (1 - pct) * (ea - sa) + sa; step = (ea - sa) / length; x = ir * Math.cos(theta); y = ir * Math.sin(theta); command = Commands.curve; if (i <= 0) { command = connected ? Commands.move : Commands.line; } v.command = command; v.x = x; v.y = y; v.controls.left.clear(); v.controls.right.clear(); if (v.command === Commands.curve) { amp = ir * step / Math.PI; v.controls.left.x = amp * Math.cos(theta + HALF_PI); v.controls.left.y = amp * Math.sin(theta + HALF_PI); v.controls.right.x = amp * Math.cos(theta - HALF_PI); v.controls.right.y = amp * Math.sin(theta - HALF_PI); if (i === 1) { v.controls.left.multiplyScalar(2); } if (i === last) { v.controls.right.multiplyScalar(2); } } id++; } vertices[id].copy(vertices[0]); vertices[id].command = Commands.line; } else if (!connected) { vertices[id].command = Commands.line; vertices[id].x = 0; vertices[id].y = 0; id++; vertices[id].copy(vertices[0]); vertices[id].command = Commands.line; } } super._update.call(this); return this; } flagReset() { super.flagReset.call(this); this._flagStartAngle = this._flagEndAngle = this._flagInnerRadius = this._flagOuterRadius = false; return this; } clone(parent) { const ir = this.innerRadius; const or = this.outerRadius; const sa = this.startAngle; const ea = this.endAngle; const resolution = this.vertices.length; const clone = new _ArcSegment(0, 0, ir, or, sa, ea, resolution); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } for (let i = 0; i < Path.Properties.length; i++) { const k = Path.Properties[i]; clone[k] = this[k]; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); for (let i = 0; i < _ArcSegment.Properties.length; i++) { const k = _ArcSegment.Properties[i]; object[k] = this[k]; } return object; } }; var ArcSegment = _ArcSegment; __publicField(ArcSegment, "Properties", ["startAngle", "endAngle", "innerRadius", "outerRadius"]); var proto20 = { startAngle: { enumerable: true, get: function() { return this._startAngle; }, set: function(v) { this._startAngle = v; this._flagStartAngle = true; } }, endAngle: { enumerable: true, get: function() { return this._endAngle; }, set: function(v) { this._endAngle = v; this._flagEndAngle = true; } }, innerRadius: { enumerable: true, get: function() { return this._innerRadius; }, set: function(v) { this._innerRadius = v; this._flagInnerRadius = true; } }, outerRadius: { enumerable: true, get: function() { return this._outerRadius; }, set: function(v) { this._outerRadius = v; this._flagOuterRadius = true; } } }; // src/shapes/points.js var ceil2 = Math.ceil; var floor3 = Math.floor; var _Points = class extends Shape { _flagVertices = true; _flagLength = true; _flagFill = true; _flagStroke = true; _flagLinewidth = true; _flagOpacity = true; _flagVisible = true; _flagSize = true; _flagSizeAttenuation = true; _length = 0; _fill = "#fff"; _stroke = "#000"; _linewidth = 1; _opacity = 1; _visible = true; _size = 1; _sizeAttenuation = false; _beginning = 0; _ending = 1; _dashes = null; constructor(vertices) { super(); for (let prop in proto21) { Object.defineProperty(this, prop, proto21[prop]); } this._renderer.type = "points"; this._renderer.flagVertices = FlagVertices.bind(this); this._renderer.bindVertices = BindVertices.bind(this); this._renderer.unbindVertices = UnbindVertices.bind(this); this._renderer.flagFill = FlagFill.bind(this); this._renderer.flagStroke = FlagStroke.bind(this); this._renderer.vertices = null; this._renderer.collection = null; this.sizeAttenuation = false; this.beginning = 0; this.ending = 1; this.fill = "#fff"; this.stroke = "#000"; this.className = ""; this.visible = true; this.vertices = vertices; this.dashes = []; this.dashes.offset = 0; } clone(parent) { const clone = new _Points(); for (let j = 0; j < this.vertices.length; j++) { clone.vertices.push(this.vertices[j].clone()); } for (let i = 0; i < _Points.Properties.length; i++) { const k = _Points.Properties[i]; clone[k] = this[k]; } clone.className = this.className; clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } if (parent) { parent.add(clone); } return clone._update(); } toObject() { const result = { vertices: this.vertices.map(function(v) { return v.toObject(); }) }; _.each(_Points.Properties, function(k) { result[k] = this[k]; }, this); result.className = this.className; result.translation = this.translation.toObject(); result.rotation = this.rotation; result.scale = this.scale instanceof Vector ? this.scale.toObject() : this.scale; result.skewX = this.skewX; result.skewY = this.skewY; if (this.matrix.manual) { result.matrix = this.matrix.toObject(); } return result; } noFill = Path.prototype.noFill; noStroke = Path.prototype.noStroke; corner = Path.prototype.corner; center = Path.prototype.center; getBoundingClientRect = Path.prototype.getBoundingClientRect; subdivide(limit) { this._update(); let points = []; for (let i = 0; i < this.vertices.length; i++) { const a = this.vertices[i]; const b = this.vertices[i - 1]; if (!b) { continue; } const x1 = a.x; const y1 = a.y; const x2 = b.x; const y2 = b.y; const subdivisions = subdivide(x1, y1, x1, y1, x2, y2, x2, y2, limit); points = points.concat(subdivisions); } this.vertices = points; return this; } _updateLength = Path.prototype._updateLength; _update() { if (this._flagVertices) { if (this._flagLength) { this._updateLength(void 0, true); } const beginning = Math.min(this._beginning, this._ending); const ending = Math.max(this._beginning, this._ending); const bid = getIdByLength(this, beginning * this._length); const eid = getIdByLength(this, ending * this._length); const low = ceil2(bid); const high = floor3(eid); let j = 0, v; this._renderer.vertices = []; this._renderer.collection = []; for (let i = 0; i < this._collection.length; i++) { if (i >= low && i <= high) { v = this._collection[i]; this._renderer.collection.push(v); this._renderer.vertices[j * 2 + 0] = v.x; this._renderer.vertices[j * 2 + 1] = v.y; j++; } } } super._update.apply(this, arguments); return this; } flagReset() { this._flagVertices = this._flagLength = this._flagFill = this._flagStroke = this._flagLinewidth = this._flagOpacity = this._flagVisible = this._flagSize = this._flagSizeAttenuation = false; super.flagReset.call(this); return this; } }; var Points = _Points; __publicField(Points, "Properties", [ "fill", "stroke", "linewidth", "opacity", "visible", "size", "sizeAttenuation", "beginning", "ending" ]); var proto21 = { linewidth: { enumerable: true, get: function() { return this._linewidth; }, set: function(v) { this._linewidth = v; this._flagLinewidth = true; } }, opacity: { enumerable: true, get: function() { return this._opacity; }, set: function(v) { this._opacity = v; this._flagOpacity = true; } }, visible: { enumerable: true, get: function() { return this._visible; }, set: function(v) { this._visible = v; this._flagVisible = true; } }, size: { enumerable: true, get: function() { return this._size; }, set: function(v) { this._size = v; this._flagSize = true; } }, sizeAttenuation: { enumerable: true, get: function() { return this._sizeAttenuation; }, set: function(v) { this._sizeAttenuation = v; this._flagSizeAttenuation = true; } }, fill: { enumerable: true, get: function() { return this._fill; }, set: function(f) { if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) { this._fill.unbind(Events.Types.change, this._renderer.flagFill); } this._fill = f; this._flagFill = true; if (this._fill instanceof Gradient || this._fill instanceof LinearGradient || this._fill instanceof RadialGradient || this._fill instanceof Texture) { this._fill.bind(Events.Types.change, this._renderer.flagFill); } } }, stroke: { enumerable: true, get: function() { return this._stroke; }, set: function(f) { if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) { this._stroke.unbind(Events.Types.change, this._renderer.flagStroke); } this._stroke = f; this._flagStroke = true; if (this._stroke instanceof Gradient || this._stroke instanceof LinearGradient || this._stroke instanceof RadialGradient || this._stroke instanceof Texture) { this._stroke.bind(Events.Types.change, this._renderer.flagStroke); } } }, length: { get: function() { if (this._flagLength) { this._updateLength(); } return this._length; } }, beginning: { enumerable: true, get: function() { return this._beginning; }, set: function(v) { this._beginning = v; this._flagVertices = true; } }, ending: { enumerable: true, get: function() { return this._ending; }, set: function(v) { this._ending = v; this._flagVertices = true; } }, vertices: { enumerable: true, get: function() { return this._collection; }, set: function(vertices) { const bindVertices = this._renderer.bindVertices; const unbindVertices = this._renderer.unbindVertices; if (this._collection) { this._collection.unbind(Events.Types.insert, bindVertices).unbind(Events.Types.remove, unbindVertices); } if (vertices instanceof Collection) { this._collection = vertices; } else { this._collection = new Collection(vertices || []); } this._collection.bind(Events.Types.insert, bindVertices).bind(Events.Types.remove, unbindVertices); bindVertices(this._collection); } }, dashes: { enumerable: true, get: function() { return this._dashes; }, set: function(v) { if (typeof v.offset !== "number") { v.offset = this.dashes && this._dashes.offset || 0; } this._dashes = v; } } }; // src/shapes/polygon.js var cos5 = Math.cos; var sin5 = Math.sin; var _Polygon = class extends Path { _flagWidth = false; _flagHeight = false; _flagSides = false; _radius = 0; _width = 0; _height = 0; _sides = 0; constructor(x, y, radius, sides) { sides = Math.max(sides || 0, 3); super(); for (let prop in proto22) { Object.defineProperty(this, prop, proto22[prop]); } this.closed = true; this.automatic = false; if (typeof radius === "number") { this.radius = radius; } if (typeof sides === "number") { this.sides = sides; } this._update(); if (typeof x === "number") { this.translation.x = x; } if (typeof y === "number") { this.translation.y = y; } } _update() { if (this._flagVertices || this._flagWidth || this._flagHeight || this._flagSides) { const sides = this._sides; const amount = sides + 1; let length = this.vertices.length; if (length > sides) { this.vertices.splice(sides - 1, length - sides); length = sides; } for (let i = 0; i < amount; i++) { const pct = (i + 0.5) / sides; const theta = TWO_PI * pct + Math.PI / 2; const x = this._width * cos5(theta) / 2; const y = this._height * sin5(theta) / 2; if (i >= length) { this.vertices.push(new Anchor(x, y)); } else { this.vertices[i].set(x, y); } this.vertices[i].command = i === 0 ? Commands.move : Commands.line; } } super._update.call(this); return this; } flagReset() { this._flagWidth = this._flagHeight = this._flagSides = false; super.flagReset.call(this); return this; } clone(parent) { const clone = new _Polygon(0, 0, 0, this.sides); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; clone.width = this.width; clone.height = this.height; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } for (let i = 0; i < Path.Properties.length; i++) { const k = Path.Properties[i]; clone[k] = this[k]; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); for (let i = 0; i < _Polygon.Properties.length; i++) { const k = _Polygon.Properties[i]; object[k] = this[k]; } return object; } }; var Polygon = _Polygon; __publicField(Polygon, "Properties", ["width", "height", "sides"]); var proto22 = { radius: { enumerable: true, get: function() { return this._radius; }, set: function(v) { this._radius = v; this.width = v * 2; this.height = v * 2; } }, width: { enumerable: true, get: function() { return this._width; }, set: function(v) { this._width = v; this._flagWidth = true; this._radius = Math.max(this.width, this.height) / 2; } }, height: { enumerable: true, get: function() { return this._height; }, set: function(v) { this._height = v; this._flagHeight = true; this._radius = Math.max(this.width, this.height) / 2; } }, sides: { enumerable: true, get: function() { return this._sides; }, set: function(v) { this._sides = v; this._flagSides = true; } } }; // src/shapes/star.js var cos6 = Math.cos; var sin6 = Math.sin; var _Star = class extends Path { _flagInnerRadius = false; _flagOuterRadius = false; _flagSides = false; _innerRadius = 0; _outerRadius = 0; _sides = 0; constructor(x, y, innerRadius, outerRadius, sides) { if (arguments.length <= 3) { outerRadius = innerRadius; innerRadius = outerRadius / 2; } if (typeof sides !== "number" || sides <= 0) { sides = 5; } super(); for (let prop in proto23) { Object.defineProperty(this, prop, proto23[prop]); } this.closed = true; this.automatic = false; if (typeof innerRadius === "number") { this.innerRadius = innerRadius; } if (typeof outerRadius === "number") { this.outerRadius = outerRadius; } if (typeof sides === "number") { this.sides = sides; } this._update(); if (typeof x === "number") { this.translation.x = x; } if (typeof y === "number") { this.translation.y = y; } } _update() { if (this._flagVertices || this._flagInnerRadius || this._flagOuterRadius || this._flagSides) { const sides = this._sides * 2; const amount = sides + 1; let length = this.vertices.length; if (length > sides) { this.vertices.splice(sides - 1, length - sides); length = sides; } for (let i = 0; i < amount; i++) { const pct = (i + 0.5) / sides; const theta = TWO_PI * pct; const r = (!(i % 2) ? this._innerRadius : this._outerRadius) / 2; const x = r * cos6(theta); const y = r * sin6(theta); if (i >= length) { this.vertices.push(new Anchor(x, y)); } else { this.vertices[i].set(x, y); } this.vertices[i].command = i === 0 ? Commands.move : Commands.line; } } super._update.call(this); return this; } flagReset() { this._flagInnerRadius = this._flagOuterRadius = this._flagSides = false; super.flagReset.call(this); return this; } clone(parent) { const ir = this.innerRadius; const or = this.outerRadius; const sides = this.sides; const clone = new _Star(0, 0, ir, or, sides); clone.translation.copy(this.translation); clone.rotation = this.rotation; clone.scale = this.scale; clone.skewX = this.skewX; clone.skewY = this.skewY; if (this.matrix.manual) { clone.matrix.copy(this.matrix); } for (let i = 0; i < Path.Properties.length; i++) { const k = Path.Properties[i]; clone[k] = this[k]; } if (parent) { parent.add(clone); } return clone; } toObject() { const object = super.toObject.call(this); for (let i = 0; i < _Star.Properties.length; i++) { const k = _Star.Properties[i]; object[k] = this[k]; } return object; } }; var Star = _Star; __publicField(Star, "Properties", ["innerRadius", "outerRadius", "sides"]); var proto23 = { innerRadius: { enumerable: true, get: function() { return this._innerRadius; }, set: function(v) { this._innerRadius = v; this._flagInnerRadius = true; } }, outerRadius: { enumerable: true, get: function() { return this._outerRadius; }, set: function(v) { this._outerRadius = v; this._flagOuterRadius = true; } }, sides: { enumerable: true, get: function() { return this._sides; }, set: function(v) { this._sides = v; this._flagSides = true; } } }; // src/renderers/svg.js var svg = { version: 1.1, ns: "http://www.w3.org/2000/svg", xlink: "http://www.w3.org/1999/xlink", alignments: { left: "start", center: "middle", right: "end" }, baselines: { top: "hanging", middle: "middle", bottom: "ideographic", baseline: "alphabetic" }, createElement: function(name, attrs) { const tag = name; const elem = document.createElementNS(svg.ns, tag); if (tag === "svg") { attrs = _.defaults(attrs || {}, { version: svg.version }); } if (attrs && Object.keys(attrs).length > 0) { svg.setAttributes(elem, attrs); } return elem; }, setAttributes: function(elem, attrs) { const keys = Object.keys(attrs); for (let i = 0; i < keys.length; i++) { if (/href/.test(keys[i])) { elem.setAttributeNS(svg.xlink, keys[i], attrs[keys[i]]); } else { elem.setAttribute(keys[i], attrs[keys[i]]); } } return this; }, removeAttributes: function(elem, attrs) { for (let key in attrs) { elem.removeAttribute(key); } return this; }, toString: function(points, closed2) { let l = points.length, last = l - 1, d, string = ""; for (let i = 0; i < l; i++) { const b = points[i]; const prev = closed2 ? mod(i - 1, l) : Math.max(i - 1, 0); const a = points[prev]; let command, c; let vx, vy, ux, uy, ar, bl, br, cl; let rx, ry, xAxisRotation, largeArcFlag, sweepFlag; let x = toFixed(b.x); let y = toFixed(b.y); switch (b.command) { case Commands.close: command = Commands.close; break; case Commands.arc: rx = b.rx; ry = b.ry; xAxisRotation = b.xAxisRotation; largeArcFlag = b.largeArcFlag; sweepFlag = b.sweepFlag; command = Commands.arc + " " + rx + " " + ry + " " + xAxisRotation + " " + largeArcFlag + " " + sweepFlag + " " + x + " " + y; break; case Commands.curve: ar = a.controls && a.controls.right || Vector.zero; bl = b.controls && b.controls.left || Vector.zero; if (a.relative) { vx = toFixed(ar.x + a.x); vy = toFixed(ar.y + a.y); } else { vx = toFixed(ar.x); vy = toFixed(ar.y); } if (b.relative) { ux = toFixed(bl.x + b.x); uy = toFixed(bl.y + b.y); } else { ux = toFixed(bl.x); uy = toFixed(bl.y); } command = (i === 0 ? Commands.move : Commands.curve) + " " + vx + " " + vy + " " + ux + " " + uy + " " + x + " " + y; break; case Commands.move: d = b; command = Commands.move + " " + x + " " + y; break; default: command = b.command + " " + x + " " + y; } if (i >= last && closed2) { if (b.command === Commands.curve) { c = d; br = b.controls && b.controls.right || b; cl = c.controls && c.controls.left || c; if (b.relative) { vx = toFixed(br.x + b.x); vy = toFixed(br.y + b.y); } else { vx = toFixed(br.x); vy = toFixed(br.y); } if (c.relative) { ux = toFixed(cl.x + c.x); uy = toFixed(cl.y + c.y); } else { ux = toFixed(cl.x); uy = toFixed(cl.y); } x = toFixed(c.x); y = toFixed(c.y); command += " C " + vx + " " + vy + " " + ux + " " + uy + " " + x + " " + y; } if (b.command !== Commands.close) { command += " Z"; } } string += command + " "; } return string; }, pointsToString: function(points, size) { let string = ""; const r = size * 0.5; for (let i = 0; i < points.length; i++) { const x = points[i].x; const y = points[i].y - r; string += Commands.move + " " + x + " " + y + " "; string += "a " + r + " " + r + " 0 1 0 0.001 0 Z"; } return string; }, getClip: function(shape, domElement) { let clip = shape._renderer.clip; if (!clip) { clip = shape._renderer.clip = svg.createElement("clipPath", { "clip-rule": "nonzero" }); } if (clip.parentNode === null) { domElement.defs.appendChild(clip); } return clip; }, defs: { update: function(domElement) { const { defs } = domElement; if (defs._flagUpdate) { const children = Array.prototype.slice.call( defs.children, 0 ); for (let i = 0; i < children.length; i++) { const child = children[i]; const id = child.id; const selector = `[fill="url(#${id})"],[stroke="url(#${id})"],[clip-path="url(#${id})"]`; const exists = domElement.querySelector(selector); if (!exists) { defs.removeChild(child); } } defs._flagUpdate = false; } } }, group: { appendChild: function(object) { const elem = object._renderer.elem; if (!elem) { return; } const tag = elem.nodeName; if (!tag || /(radial|linear)gradient/i.test(tag) || object._clip) { return; } this.elem.appendChild(elem); }, removeChild: function(object) { const elem = object._renderer.elem; if (!elem || elem.parentNode != this.elem) { return; } const tag = elem.nodeName; if (!tag) { return; } if (object._clip) { return; } this.elem.removeChild(elem); }, orderChild: function(object) { this.elem.appendChild(object._renderer.elem); }, renderChild: function(child) { svg[child._renderer.type].render.call(child, this); }, render: function(domElement) { if (!this._visible && !this._flagVisible || this._opacity === 0 && !this._flagOpacity) { return this; } this._update(); if (!this._renderer.elem) { this._renderer.elem = svg.createElement("g", { id: this.id }); domElement.appendChild(this._renderer.elem); } const flagMatrix = this._matrix.manual || this._flagMatrix; const context = { domElement, elem: this._renderer.elem }; if (flagMatrix) { this._renderer.elem.setAttribute("transform", "matrix(" + this._matrix.toString() + ")"); } for (let i = 0; i < this.children.length; i++) { const child = this.children[i]; svg[child._renderer.type].render.call(child, domElement); } if (this._flagId) { this._renderer.elem.setAttribute("id", this._id); } if (this._flagOpacity) { this._renderer.elem.setAttribute("opacity", this._opacity); } if (this._flagVisible) { this._renderer.elem.setAttribute("display", this._visible ? "inline" : "none"); } if (this._flagClassName) { this._renderer.elem.setAttribute("class", this.classList.join(" ")); } if (this._flagAdditions) { this.additions.forEach(svg.group.appendChild, context); } if (this._flagSubtractions) { this.subtractions.forEach(svg.group.removeChild, context); } if (this._flagOrder) { this.children.forEach(svg.group.orderChild, context); } if (this._flagMask) { if (this._mask) { svg[this._mask._renderer.type].render.call(this._mask, domElement); this._renderer.elem.setAttribute("clip-path", "url(#" + this._mask.id + ")"); } else { this._renderer.elem.removeAttribute("clip-path"); } } if (this.dataset) { Object.assign(this._renderer.elem.dataset, this.dataset); } return this.flagReset(); } }, path: { render: function(domElement) { if (this._opacity === 0 && !this._flagOpacity) { return this; } this._update(); const changed = {}; const flagMatrix = this._matrix.manual || this._flagMatrix; if (flagMatrix) { changed.transform = "matrix(" + this._matrix.toString() + ")"; } if (this._flagId) { changed.id = this._id; } if (this._flagVertices) { const vertices = svg.toString(this._renderer.vertices, this._closed); changed.d = vertices; } if (this._fill && this._fill._renderer) { this._renderer.hasFillEffect = true; this._fill._update(); svg[this._fill._renderer.type].render.call(this._fill, domElement, true); } if (this._flagFill) { changed.fill = this._fill && this._fill.id ? "url(#" + this._fill.id + ")" : this._fill; if (this._renderer.hasFillEffect && typeof this._fill.id === "undefined") { domElement.defs._flagUpdate = true; delete this._renderer.hasFillEffect; } } if (this._stroke && this._stroke._renderer) { this._renderer.hasStrokeEffect = true; this._stroke._update(); svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true); } if (this._flagStroke) { changed.stroke = this._stroke && this._stroke.id ? "url(#" + this._stroke.id + ")" : this._stroke; if (this._renderer.hasStrokeEffect && typeof this._stroke.id === "undefined") { domElement.defs._flagUpdate = true; delete this._renderer.hasStrokeEffect; } } if (this._flagLinewidth) { changed["stroke-width"] = this._linewidth; } if (this._flagOpacity) { changed["stroke-opacity"] = this._opacity; changed["fill-opacity"] = this._opacity; } if (this._flagClassName) { changed["class"] = this.classList.join(" "); } if (this._flagVisible) { changed.visibility = this._visible ? "visible" : "hidden"; } if (this._flagCap) { changed["stroke-linecap"] = this._cap; } if (this._flagJoin) { changed["stroke-linejoin"] = this._join; } if (this._flagMiter) { changed["stroke-miterlimit"] = this._miter; } if (this.dashes && this.dashes.length > 0) { changed["stroke-dasharray"] = this.dashes.join(" "); changed["stroke-dashoffset"] = this.dashes.offset || 0; } if (!this._renderer.elem) { changed.id = this._id; this._renderer.elem = svg.createElement("path", changed); domElement.appendChild(this._renderer.elem); } else { svg.setAttributes(this._renderer.elem, changed); } if (this._flagClip) { const clip = svg.getClip(this, domElement); const elem = this._renderer.elem; if (this._clip) { elem.removeAttribute("id"); clip.setAttribute("id", this.id); clip.appendChild(elem); } else { clip.removeAttribute("id"); elem.setAttribute("id", this.id); this.parent._renderer.elem.appendChild(elem); } } if (this._flagMask) { if (this._mask) { svg[this._mask._renderer.type].render.call(this._mask, domElement); this._renderer.elem.setAttribute("clip-path", "url(#" + this._mask.id + ")"); } else { this._renderer.elem.removeAttribute("clip-path"); } } return this.flagReset(); } }, points: { render: function(domElement) { if (this._opacity === 0 && !this._flagOpacity) { return this; } this._update(); const changed = {}; const flagMatrix = this._matrix.manual || this._flagMatrix; if (flagMatrix) { changed.transform = "matrix(" + this._matrix.toString() + ")"; } if (this._flagId) { changed.id = this._id; } if (this._flagVertices || this._flagSize || this._flagSizeAttenuation) { let size = this._size; if (!this._sizeAttenuation) { const me = this.worldMatrix.elements; const m = decomposeMatrix(me[0], me[3], me[1], me[4], me[2], me[5]); size /= Math.max(m.scaleX, m.scaleY); } const vertices = svg.pointsToString(this._renderer.collection, size); changed.d = vertices; } if (this._fill && this._fill._renderer) { this._renderer.hasFillEffect = true; this._fill._update(); svg[this._fill._renderer.type].render.call(this._fill, domElement, true); } if (this._flagFill) { changed.fill = this._fill && this._fill.id ? "url(#" + this._fill.id + ")" : this._fill; if (this._renderer.hasFillEffect && typeof this._fill.id === "undefined") { domElement.defs._flagUpdate = true; delete this._renderer.hasFillEffect; } } if (this._stroke && this._stroke._renderer) { this._renderer.hasStrokeEffect = true; this._stroke._update(); svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true); } if (this._flagStroke) { changed.stroke = this._stroke && this._stroke.id ? "url(#" + this._stroke.id + ")" : this._stroke; if (this._renderer.hasStrokeEffect && typeof this._stroke.id === "undefined") { domElement.defs._flagUpdate = true; delete this._renderer.hasStrokeEffect; } } if (this._flagLinewidth) { changed["stroke-width"] = this._linewidth; } if (this._flagOpacity) { changed["stroke-opacity"] = this._opacity; changed["fill-opacity"] = this._opacity; } if (this._flagClassName) { changed["class"] = this.classList.join(" "); } if (this._flagVisible) { changed.visibility = this._visible ? "visible" : "hidden"; } if (this.dashes && this.dashes.length > 0) { changed["stroke-dasharray"] = this.dashes.join(" "); changed["stroke-dashoffset"] = this.dashes.offset || 0; } if (!this._renderer.elem) { changed.id = this._id; this._renderer.elem = svg.createElement("path", changed); domElement.appendChild(this._renderer.elem); } else { svg.setAttributes(this._renderer.elem, changed); } return this.flagReset(); } }, text: { render: function(domElement) { this._update(); const changed = {}; const flagMatrix = this._matrix.manual || this._flagMatrix; if (flagMatrix) { changed.transform = "matrix(" + this._matrix.toString() + ")"; } if (this._flagId) { changed.id = this._id; } if (this._flagFamily) { changed["font-family"] = this._family; } if (this._flagSize) { changed["font-size"] = this._size; } if (this._flagLeading) { changed["line-height"] = this._leading; } if (this._flagAlignment) { changed["text-anchor"] = svg.alignments[this._alignment] || this._alignment; } if (this._flagBaseline) { changed["dominant-baseline"] = svg.baselines[this._baseline] || this._baseline; } if (this._flagStyle) { changed["font-style"] = this._style; } if (this._flagWeight) { changed["font-weight"] = this._weight; } if (this._flagDecoration) { changed["text-decoration"] = this._decoration; } if (this._flagDirection) { changed["direction"] = this._direction; } if (this._fill && this._fill._renderer) { this._renderer.hasFillEffect = true; this._fill._update(); svg[this._fill._renderer.type].render.call(this._fill, domElement, true); } if (this._flagFill) { changed.fill = this._fill && this._fill.id ? "url(#" + this._fill.id + ")" : this._fill; if (this._renderer.hasFillEffect && typeof this._fill.id === "undefined") { domElement.defs._flagUpdate = true; delete this._renderer.hasFillEffect; } } if (this._stroke && this._stroke._renderer) { this._renderer.hasStrokeEffect = true; this._stroke._update(); svg[this._stroke._renderer.type].render.call(this._stroke, domElement, true); } if (this._flagStroke) { changed.stroke = this._stroke && this._stroke.id ? "url(#" + this._stroke.id + ")" : this._stroke; if (this._renderer.hasStrokeEffect && typeof this._stroke.id === "undefined") { domElement.defs._flagUpdate = true; delete this._renderer.hasStrokeEffect; } } if (this._flagLinewidth) { changed["stroke-width"] = this._linewidth; } if (this._flagOpacity) { changed.opacity = this._opacity; } if (this._flagClassName) { changed["class"] = this.classList.join(" "); } if (this._flagVisible) { changed.visibility = this._visible ? "visible" : "hidden"; } if (this.dashes && this.dashes.length > 0) { changed["stroke-dasharray"] = this.dashes.join(" "); changed["stroke-dashoffset"] = this.dashes.offset || 0; } if (!this._renderer.elem) { changed.id = this._id; this._renderer.elem = svg.createElement("text", changed); domElement.appendChild(this._renderer.elem); } else { svg.setAttributes(this._renderer.elem, changed); } if (this._flagClip) { const clip = svg.getClip(this, domElement); const elem = this._renderer.elem; if (this._clip) { elem.removeAttribute("id"); clip.setAttribute("id", this.id); clip.appendChild(elem); } else { clip.removeAttribute("id"); elem.setAttribute("id", this.id); this.parent._renderer.elem.appendChild(elem); } } if (this._flagMask) { if (this._mask) { svg[this._mask._renderer.type].render.call(this._mask, domElement); this._renderer.elem.setAttribute("clip-path", "url(#" + this._mask.id + ")"); } else { this._renderer.elem.removeAttribute("clip-path"); } } if (this._flagValue) { this._renderer.elem.textContent = this._value; } return this.flagReset(); } }, "linear-gradient": { render: function(domElement, silent) { if (!silent) { this._update(); } const changed = {}; if (this._flagId) { changed.id = this._id; } if (this._flagEndPoints) { changed.x1 = this.left._x; changed.y1 = this.left._y; changed.x2 = this.right._x; changed.y2 = this.right._y; } if (this._flagSpread) { changed.spreadMethod = this._spread; } if (this._flagUnits) { changed.gradientUnits = this._units; } if (!this._renderer.elem) { changed.id = this._id; this._renderer.elem = svg.createElement("linearGradient", changed); } else { svg.setAttributes(this._renderer.elem, changed); } if (this._renderer.elem.parentNode === null) { domElement.defs.appendChild(this._renderer.elem); } if (this._flagStops) { const lengthChanged = this._renderer.elem.childNodes.length !== this.stops.length; if (lengthChanged) { while (this._renderer.elem.lastChild) { this._renderer.elem.removeChild(this._renderer.elem.lastChild); } } for (let i = 0; i < this.stops.length; i++) { const stop = this.stops[i]; const attrs = {}; if (stop._flagOffset) { attrs.offset = 100 * stop._offset + "%"; } if (stop._flagColor) { attrs["stop-color"] = stop._color; } if (stop._flagOpacity) { attrs["stop-opacity"] = stop._opacity; } if (!stop._renderer.elem) { stop._renderer.elem = svg.createElement("stop", attrs); } else { svg.setAttributes(stop._renderer.elem, attrs); } if (lengthChanged) { this._renderer.elem.appendChild(stop._renderer.elem); } stop.flagReset(); } } return this.flagReset(); } }, "radial-gradient": { render: function(domElement, silent) { if (!silent) { this._update(); } const changed = {}; if (this._flagId) { changed.id = this._id; } if (this._flagCenter) { changed.cx = this.center._x; changed.cy = this.center._y; } if (this._flagFocal) { changed.fx = this.focal._x; changed.fy = this.focal._y; } if (this._flagRadius) { changed.r = this._radius; } if (this._flagSpread) { changed.spreadMethod = this._spread; } if (this._flagUnits) { changed.gradientUnits = this._units; } if (!this._renderer.elem) { changed.id = this._id; this._renderer.elem = svg.createElement("radialGradient", changed); } else { svg.setAttributes(this._renderer.elem, changed); } if (this._renderer.elem.parentNode === null) { domElement.defs.appendChild(this._renderer.elem); } if (this._flagStops) { const lengthChanged = this._renderer.elem.childNodes.length !== this.stops.length; if (lengthChanged) { while (this._renderer.elem.lastChild) { this._renderer.elem.removeChild(this._renderer.elem.lastChild); } } for (let i = 0; i < this.stops.length; i++) { const stop = this.stops[i]; const attrs = {}; if (stop._flagOffset) { attrs.offset = 100 * stop._offset + "%"; } if (stop._flagColor) { attrs["stop-color"] = stop._color; } if (stop._flagOpacity) { attrs["stop-opacity"] = stop._opacity; } if (!stop._renderer.elem) { stop._renderer.elem = svg.createElement("stop", attrs); } else { svg.setAttributes(stop._renderer.elem, attrs); } if (lengthChanged) { this._renderer.elem.appendChild(stop._renderer.elem); } stop.flagReset(); } } return this.flagReset(); } }, texture: { render: function(domElement, silent) { if (!silent) { this._update(); } const changed = {}; const styles = { x: 0, y: 0 }; const image = this.image; if (this._flagId) { changed.id = this._id; } if (this._flagLoaded && this.loaded) { switch (image.nodeName.toLowerCase()) { case "canvas": styles.href = styles["xlink:href"] = image.toDataURL("image/png"); break; case "img": case "image": styles.href = styles["xlink:href"] = this.src; break; } } if (this._flagOffset || this._flagLoaded || this._flagScale) { changed.x = this._offset.x; changed.y = this._offset.y; if (image) { changed.x -= image.width / 2; changed.y -= image.height / 2; if (this._scale instanceof Vector) { changed.x *= this._scale.x; changed.y *= this._scale.y; } else { changed.x *= this._scale; changed.y *= this._scale; } } if (changed.x > 0) { changed.x *= -1; } if (changed.y > 0) { changed.y *= -1; } } if (this._flagScale || this._flagLoaded || this._flagRepeat) { changed.width = 0; changed.height = 0; if (image) { styles.width = changed.width = image.width; styles.height = changed.height = image.height; switch (this._repeat) { case "no-repeat": changed.width += 1; changed.height += 1; break; } if (this._scale instanceof Vector) { changed.width *= this._scale.x; changed.height *= this._scale.y; } else { changed.width *= this._scale; changed.height *= this._scale; } } } if (this._flagScale || this._flagLoaded) { if (!this._renderer.image) { this._renderer.image = svg.createElement("image", styles); } else { svg.setAttributes(this._renderer.image, styles); } } if (!this._renderer.elem) { changed.id = this._id; changed.patternUnits = "userSpaceOnUse"; this._renderer.elem = svg.createElement("pattern", changed); } else if (Object.keys(changed).length !== 0) { svg.setAttributes(this._renderer.elem, changed); } if (this._renderer.elem.parentNode === null) { domElement.defs.appendChild(this._renderer.elem); } if (this._renderer.elem && this._renderer.image && !this._renderer.appended) { this._renderer.elem.appendChild(this._renderer.image); this._renderer.appended = true; } return this.flagReset(); } } }; var Renderer2 = class extends Events { constructor(params) { super(); this.domElement = params.domElement || svg.createElement("svg"); this.scene = new Group(); this.scene.parent = this; this.defs = svg.createElement("defs"); this.defs._flagUpdate = false; this.domElement.appendChild(this.defs); this.domElement.defs = this.defs; this.domElement.style.overflow = "hidden"; } setSize(width, height) { this.width = width; this.height = height; svg.setAttributes(this.domElement, { width, height }); return this.trigger(Events.Types.resize, width, height); } render() { svg.group.render.call(this.scene, this.domElement); svg.defs.update(this.domElement); return this; } }; __publicField(Renderer2, "Utils", svg); // src/utils/shaders.js var shaders = { create: function(gl, source, type) { const shader = gl.createShader(gl[type]); gl.shaderSource(shader, source); gl.compileShader(shader); const compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!compiled) { const error = gl.getShaderInfoLog(shader); gl.deleteShader(shader); throw new TwoError("unable to compile shader " + shader + ": " + error); } return shader; }, types: { vertex: "VERTEX_SHADER", fragment: "FRAGMENT_SHADER" }, path: { vertex: ` precision mediump float; attribute vec2 a_position; uniform mat3 u_matrix; uniform vec2 u_resolution; uniform vec4 u_rect; varying vec2 v_textureCoords; void main() { vec2 rectCoords = (a_position * (u_rect.zw - u_rect.xy)) + u_rect.xy; vec2 projected = (u_matrix * vec3(rectCoords, 1.0)).xy; vec2 normal = projected / u_resolution; vec2 clipspace = (normal * 2.0) - 1.0; gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0); v_textureCoords = a_position; } `, fragment: ` precision mediump float; uniform sampler2D u_image; varying vec2 v_textureCoords; void main() { vec4 texel = texture2D(u_image, v_textureCoords); if (texel.a == 0.0) { discard; } gl_FragColor = texel; } ` }, points: { vertex: ` precision mediump float; attribute vec2 a_position; uniform float u_size; uniform mat3 u_matrix; uniform vec2 u_resolution; varying vec2 v_textureCoords; void main() { vec2 projected = (u_matrix * vec3(a_position, 1.0)).xy; vec2 normal = projected / u_resolution; vec2 clipspace = (normal * 2.0) - 1.0; gl_PointSize = u_size; gl_Position = vec4(clipspace * vec2(1.0, -1.0), 0.0, 1.0); v_textureCoords = a_position; } `, fragment: ` precision mediump float; uniform sampler2D u_image; void main() { vec4 texel = texture2D(u_image, gl_PointCoord); if (texel.a == 0.0) { discard; } gl_FragColor = texel; } ` } }; // src/renderers/webgl.js var multiplyMatrix = Matrix2.Multiply; var identity = [1, 0, 0, 0, 1, 0, 0, 0, 1]; var transformation = new NumArray(9); var CanvasUtils = Renderer.Utils; var vector2 = new Vector(); var quad = new NumArray([ 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1 ]); var webgl = { precision: 0.9, isHidden: /(undefined|none|transparent)/i, canvas: root.document ? root.document.createElement("canvas") : { getContext: function() { } }, alignments: { left: "start", middle: "center", right: "end" }, matrix: new Matrix2(), group: { removeChild: function(child, gl) { if (child.children) { for (let i = 0; i < child.children.length; i++) { webgl.group.removeChild(child.children[i], gl); } } if (child._renderer.texture) { gl.deleteTexture(child._renderer.texture); delete child._renderer.texture; } if (child._renderer.positionBuffer) { gl.deleteBuffer(child._renderer.positionBuffer); delete child._renderer.positionBuffer; } }, render: function(gl, programs) { if (!this._visible) { return; } this._update(); const parent = this.parent; const flagParentMatrix = parent._matrix && parent._matrix.manual || parent._flagMatrix; const flagMatrix = this._matrix.manual || this._flagMatrix; if (flagParentMatrix || flagMatrix) { if (!this._renderer.matrix) { this._renderer.matrix = new NumArray(9); } this._matrix.toTransformArray(true, transformation); multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix); if (!(this._renderer.scale instanceof Vector)) { this._renderer.scale = new Vector(); } if (this._scale instanceof Vector) { this._renderer.scale.x = this._scale.x; this._renderer.scale.y = this._scale.y; } else { this._renderer.scale.x = this._scale; this._renderer.scale.y = this._scale; } if (!/renderer/i.test(parent._renderer.type)) { this._renderer.scale.x *= parent._renderer.scale.x; this._renderer.scale.y *= parent._renderer.scale.y; } if (flagParentMatrix) { this._flagMatrix = true; } } if (this._mask) { gl.clear(gl.STENCIL_BUFFER_BIT); gl.enable(gl.STENCIL_TEST); gl.stencilFunc(gl.ALWAYS, 1, 0); gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); gl.colorMask(false, false, false, false); webgl[this._mask._renderer.type].render.call(this._mask, gl, programs, this); gl.stencilFunc(gl.EQUAL, 1, 255); gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); gl.colorMask(true, true, true, true); } this._flagOpacity = parent._flagOpacity || this._flagOpacity; this._renderer.opacity = this._opacity * (parent && parent._renderer ? parent._renderer.opacity : 1); let i; if (this._flagSubtractions) { for (i = 0; i < this.subtractions.length; i++) { webgl.group.removeChild(this.subtractions[i], gl); } } for (i = 0; i < this.children.length; i++) { const child = this.children[i]; webgl[child._renderer.type].render.call(child, gl, programs); } if (this._mask) { gl.disable(gl.STENCIL_TEST); } return this.flagReset(); } }, path: { updateCanvas: function(gl, elem) { let prev, a, c, ux, uy, vx, vy, ar, bl, br, cl, x, y; let isOffset; const commands = elem._renderer.vertices; const canvas3 = this.canvas; const ctx = this.ctx; const ratio = gl.renderer.ratio; const scale = vector2.copy(elem._renderer.scale).multiply(ratio); const stroke = elem._stroke; const linewidth = elem._linewidth; const fill = elem._fill; const opacity = elem._renderer.opacity || elem._opacity; const cap = elem._cap; const join = elem._join; const miter = elem._miter; const closed2 = elem._closed; const dashes = elem.dashes; const length = commands.length; const last = length - 1; canvas3.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1); canvas3.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1); const centroid = elem._renderer.rect.centroid; const cx = centroid.x; const cy = centroid.y; ctx.clearRect(0, 0, canvas3.width, canvas3.height); if (fill) { if (typeof fill === "string") { ctx.fillStyle = fill; } else { webgl[fill._renderer.type].render.call(fill, ctx, elem); ctx.fillStyle = fill._renderer.effect; } } if (stroke) { if (typeof stroke === "string") { ctx.strokeStyle = stroke; } else { webgl[stroke._renderer.type].render.call(stroke, ctx, elem); ctx.strokeStyle = stroke._renderer.effect; } if (linewidth) { ctx.lineWidth = linewidth; } if (miter) { ctx.miterLimit = miter; } if (join) { ctx.lineJoin = join; } if (!closed2 && cap) { ctx.lineCap = cap; } } if (typeof opacity === "number") { ctx.globalAlpha = opacity; } if (dashes && dashes.length > 0) { ctx.lineDashOffset = dashes.offset || 0; ctx.setLineDash(dashes); } let d, rx, ry, xAxisRotation, largeArcFlag, sweepFlag, ax, ay; ctx.save(); ctx.scale(scale.x, scale.y); ctx.translate(cx, cy); ctx.beginPath(); for (let i = 0; i < commands.length; i++) { const b = commands[i]; x = b.x; y = b.y; switch (b.command) { case Commands.close: ctx.closePath(); break; case Commands.arc: rx = b.rx; ry = b.ry; xAxisRotation = b.xAxisRotation; largeArcFlag = b.largeArcFlag; sweepFlag = b.sweepFlag; prev = closed2 ? mod(i - 1, length) : Math.max(i - 1, 0); a = commands[prev]; ax = a.x; ay = a.y; CanvasUtils.renderSvgArcCommand(ctx, ax, ay, rx, ry, largeArcFlag, sweepFlag, xAxisRotation, x, y); break; case Commands.curve: prev = closed2 ? mod(i - 1, length) : Math.max(i - 1, 0); a = commands[prev]; ar = a.controls && a.controls.right || Vector.zero; bl = b.controls && b.controls.left || Vector.zero; if (a._relative) { vx = ar.x + a.x; vy = ar.y + a.y; } else { vx = ar.x; vy = ar.y; } if (b._relative) { ux = bl.x + b.x; uy = bl.y + b.y; } else { ux = bl.x; uy = bl.y; } ctx.bezierCurveTo(vx, vy, ux, uy, x, y); if (i >= last && closed2) { c = d; br = b.controls && b.controls.right || Vector.zero; cl = c.controls && c.controls.left || Vector.zero; if (b._relative) { vx = br.x + b.x; vy = br.y + b.y; } else { vx = br.x; vy = br.y; } if (c._relative) { ux = cl.x + c.x; uy = cl.y + c.y; } else { ux = cl.x; uy = cl.y; } x = c.x; y = c.y; ctx.bezierCurveTo(vx, vy, ux, uy, x, y); } break; case Commands.line: ctx.lineTo(x, y); break; case Commands.move: d = b; ctx.moveTo(x, y); break; } } if (closed2) { ctx.closePath(); } if (!webgl.isHidden.test(fill)) { isOffset = fill._renderer && fill._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -fill._renderer.offset.x, -fill._renderer.offset.y ); ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y); } ctx.fill(); if (isOffset) { ctx.restore(); } } if (!webgl.isHidden.test(stroke)) { isOffset = stroke._renderer && stroke._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -stroke._renderer.offset.x, -stroke._renderer.offset.y ); ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y); ctx.lineWidth = linewidth / stroke._renderer.scale.x; } ctx.stroke(); if (isOffset) { ctx.restore(); } } ctx.restore(); }, getBoundingClientRect: function(vertices, border, rect) { let left = Infinity, right = -Infinity, top = Infinity, bottom = -Infinity, width, height; vertices.forEach(function(v) { const x = v.x, y = v.y, controls = v.controls; let a, b, c, d, cl, cr; top = Math.min(y, top); left = Math.min(x, left); right = Math.max(x, right); bottom = Math.max(y, bottom); if (!v.controls) { return; } cl = controls.left; cr = controls.right; if (!cl || !cr) { return; } a = v._relative ? cl.x + x : cl.x; b = v._relative ? cl.y + y : cl.y; c = v._relative ? cr.x + x : cr.x; d = v._relative ? cr.y + y : cr.y; if (!a || !b || !c || !d) { return; } top = Math.min(b, d, top); left = Math.min(a, c, left); right = Math.max(a, c, right); bottom = Math.max(b, d, bottom); }); if (typeof border === "number") { top -= border; left -= border; right += border; bottom += border; } width = right - left; height = bottom - top; rect.top = top; rect.left = left; rect.right = right; rect.bottom = bottom; rect.width = width; rect.height = height; if (!rect.centroid) { rect.centroid = {}; } rect.centroid.x = -left; rect.centroid.y = -top; }, render: function(gl, programs, forcedParent) { if (!this._visible || !this._opacity) { return this; } this._update(); const parent = forcedParent || this.parent; const program = programs[this._renderer.type]; const flagParentMatrix = parent._matrix.manual || parent._flagMatrix; const flagMatrix = this._matrix.manual || this._flagMatrix; const parentChanged = this._renderer.parent !== parent; const flagTexture = this._flagVertices || this._flagFill || this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints) || this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal) || this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale) || this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints) || this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal) || this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale) || this._flagStroke || this._flagLinewidth || this._flagOpacity || parent._flagOpacity || this._flagVisible || this._flagCap || this._flagJoin || this._flagMiter || this._flagScale || this.dashes && this.dashes.length > 0 || !this._renderer.texture; if (flagParentMatrix || flagMatrix || parentChanged) { if (!this._renderer.matrix) { this._renderer.matrix = new NumArray(9); } this._matrix.toTransformArray(true, transformation); multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix); if (!(this._renderer.scale instanceof Vector)) { this._renderer.scale = new Vector(); } if (this._scale instanceof Vector) { this._renderer.scale.x = this._scale.x * parent._renderer.scale.x; this._renderer.scale.y = this._scale.y * parent._renderer.scale.y; } else { this._renderer.scale.x = this._scale * parent._renderer.scale.x; this._renderer.scale.y = this._scale * parent._renderer.scale.y; } if (parentChanged) { this._renderer.parent = parent; } } if (this._mask) { gl.clear(gl.STENCIL_BUFFER_BIT); gl.enable(gl.STENCIL_TEST); gl.stencilFunc(gl.ALWAYS, 1, 0); gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); gl.colorMask(false, false, false, false); webgl[this._mask._renderer.type].render.call(this._mask, gl, programs, this); gl.stencilFunc(gl.EQUAL, 1, 255); gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); gl.colorMask(true, true, true, true); } if (flagTexture) { if (!this._renderer.rect) { this._renderer.rect = {}; } this._renderer.opacity = this._opacity * parent._renderer.opacity; webgl.path.getBoundingClientRect( this._renderer.vertices, this._linewidth, this._renderer.rect ); webgl.updateTexture.call(webgl, gl, this); } else { if (this._fill && this._fill._update) { this._fill._update(); } if (this._stroke && this._stroke._update) { this._stroke._update(); } } if (this._clip && !forcedParent || !this._renderer.texture) { return this; } if (programs.current !== program) { gl.useProgram(program); gl.bindBuffer(gl.ARRAY_BUFFER, programs.buffers.position); gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(program.position); gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW); if (!programs.resolution.flagged) { gl.uniform2f( gl.getUniformLocation(program, "u_resolution"), programs.resolution.width, programs.resolution.height ); } programs.current = program; } if (programs.resolution.flagged) { gl.uniform2f( gl.getUniformLocation(program, "u_resolution"), programs.resolution.width, programs.resolution.height ); } gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture); const rect = this._renderer.rect; gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix); gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom); gl.drawArrays(gl.TRIANGLES, 0, 6); if (this._mask) { gl.disable(gl.STENCIL_TEST); } return this.flagReset(); } }, points: { updateCanvas: function(gl, elem) { let isOffset; const canvas3 = this.canvas; const ctx = this.ctx; const ratio = gl.renderer.ratio; const stroke = elem._stroke; const linewidth = elem._linewidth; const fill = elem._fill; const opacity = elem._renderer.opacity || elem._opacity; const dashes = elem.dashes; const size = elem._size * ratio; let dimension = size; if (!webgl.isHidden.test(stroke)) { dimension += linewidth; } canvas3.width = getPoT(dimension); canvas3.height = canvas3.width; const aspect = dimension / canvas3.width; const cx = canvas3.width / 2; const cy = canvas3.height / 2; ctx.clearRect(0, 0, canvas3.width, canvas3.height); if (fill) { if (typeof fill === "string") { ctx.fillStyle = fill; } else { webgl[fill._renderer.type].render.call(fill, ctx, elem); ctx.fillStyle = fill._renderer.effect; } } if (stroke) { if (typeof stroke === "string") { ctx.strokeStyle = stroke; } else { webgl[stroke._renderer.type].render.call(stroke, ctx, elem); ctx.strokeStyle = stroke._renderer.effect; } if (linewidth) { ctx.lineWidth = linewidth / aspect; } } if (typeof opacity === "number") { ctx.globalAlpha = opacity; } if (dashes && dashes.length > 0) { ctx.lineDashOffset = dashes.offset || 0; ctx.setLineDash(dashes); } ctx.save(); ctx.translate(cx, cy); ctx.scale(webgl.precision, webgl.precision); ctx.beginPath(); ctx.arc(0, 0, size / aspect * 0.5, 0, TWO_PI); ctx.restore(); if (closed) { ctx.closePath(); } if (!webgl.isHidden.test(fill)) { isOffset = fill._renderer && fill._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -fill._renderer.offset.x, -fill._renderer.offset.y ); ctx.scale(fill._renderer.scale.x, fill._renderer.scale.y); } ctx.fill(); if (isOffset) { ctx.restore(); } } if (!webgl.isHidden.test(stroke)) { isOffset = stroke._renderer && stroke._renderer.offset; if (isOffset) { ctx.save(); ctx.translate( -stroke._renderer.offset.x, -stroke._renderer.offset.y ); ctx.scale(stroke._renderer.scale.x, stroke._renderer.scale.y); ctx.lineWidth = linewidth / stroke._renderer.scale.x; } ctx.stroke(); if (isOffset) { ctx.restore(); } } }, render: function(gl, programs, forcedParent) { if (!this._visible || !this._opacity) { return this; } this._update(); let size = this._size; const parent = forcedParent || this.parent; const program = programs[this._renderer.type]; const sizeAttenuation = this._sizeAttenuation; const stroke = this._stroke; const linewidth = this._linewidth; const flagParentMatrix = parent._matrix.manual || parent._flagMatrix; const flagMatrix = this._matrix.manual || this._flagMatrix; const parentChanged = this._renderer.parent !== parent; const commands = this._renderer.vertices; const length = this._renderer.collection.length; const flagVertices = this._flagVertices; const flagTexture = this._flagFill || this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints) || this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal) || this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale) || this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints) || this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal) || this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale) || this._flagStroke || this._flagLinewidth || this._flagOpacity || parent._flagOpacity || this._flagVisible || this._flagScale || this.dashes && this.dashes.length > 0 || !this._renderer.texture; if (flagParentMatrix || flagMatrix || parentChanged) { if (!this._renderer.matrix) { this._renderer.matrix = new NumArray(9); } this._matrix.toTransformArray(true, transformation); multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix); if (!(this._renderer.scale instanceof Vector)) { this._renderer.scale = new Vector(); } if (this._scale instanceof Vector) { this._renderer.scale.x = this._scale.x * parent._renderer.scale.x; this._renderer.scale.y = this._scale.y * parent._renderer.scale.y; } else { this._renderer.scale.x = this._scale * parent._renderer.scale.x; this._renderer.scale.y = this._scale * parent._renderer.scale.y; } if (parentChanged) { this._renderer.parent = parent; } } if (flagVertices) { const positionBuffer = this._renderer.positionBuffer; if (positionBuffer) { gl.deleteBuffer(positionBuffer); } this._renderer.positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this._renderer.positionBuffer); gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(program.position); gl.bufferData(gl.ARRAY_BUFFER, commands, gl.STATIC_DRAW); } if (flagTexture) { this._renderer.opacity = this._opacity * parent._renderer.opacity; webgl.updateTexture.call(webgl, gl, this); } else { if (this._fill && this._fill._update) { this._fill._update(); } if (this._stroke && this._stroke._update) { this._stroke._update(); } } if (this._clip && !forcedParent || !this._renderer.texture) { return this; } if (!webgl.isHidden.test(stroke)) { size += linewidth; } size /= webgl.precision; if (sizeAttenuation) { size *= Math.max(this._renderer.scale.x, this._renderer.scale.y); } if (programs.current !== program) { gl.useProgram(program); if (!programs.resolution.flagged) { gl.uniform2f( gl.getUniformLocation(program, "u_resolution"), programs.resolution.width, programs.resolution.height ); } programs.current = program; } if (programs.resolution.flagged) { gl.uniform2f( gl.getUniformLocation(program, "u_resolution"), programs.resolution.width, programs.resolution.height ); } gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture); gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix); gl.uniform1f(program.size, size * programs.resolution.ratio); gl.drawArrays(gl.POINTS, 0, length); return this.flagReset(); } }, text: { updateCanvas: function(gl, elem) { const canvas3 = this.canvas; const ctx = this.ctx; const ratio = gl.renderer.ratio; const scale = vector2.copy(elem._renderer.scale).multiply(ratio); const stroke = elem._stroke; const linewidth = elem._linewidth; const fill = elem._fill; const opacity = elem._renderer.opacity || elem._opacity; const dashes = elem.dashes; const decoration = elem._decoration; const direction = elem._direction; canvas3.width = Math.max(Math.ceil(elem._renderer.rect.width * scale.x), 1); canvas3.height = Math.max(Math.ceil(elem._renderer.rect.height * scale.y), 1); const centroid = elem._renderer.rect.centroid; const cx = centroid.x; const cy = centroid.y; let a, b, c, d, e, sx, sy, x1, y1, x2, y2; const isOffset = fill._renderer && fill._renderer.offset && stroke._renderer && stroke._renderer.offset; ctx.clearRect(0, 0, canvas3.width, canvas3.height); if (!isOffset) { ctx.font = [elem._style, elem._weight, elem._size + "px/" + elem._leading + "px", elem._family].join(" "); } ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.textDirection = direction; if (fill) { if (typeof fill === "string") { ctx.fillStyle = fill; } else { webgl[fill._renderer.type].render.call(fill, ctx, elem); ctx.fillStyle = fill._renderer.effect; } } if (stroke) { if (typeof stroke === "string") { ctx.strokeStyle = stroke; } else { webgl[stroke._renderer.type].render.call(stroke, ctx, elem); ctx.strokeStyle = stroke._renderer.effect; } if (linewidth) { ctx.lineWidth = linewidth; } } if (typeof opacity === "number") { ctx.globalAlpha = opacity; } if (dashes && dashes.length > 0) { ctx.lineDashOffset = dashes.offset || 0; ctx.setLineDash(dashes); } ctx.save(); ctx.scale(scale.x, scale.y); ctx.translate(cx, cy); if (!webgl.isHidden.test(fill)) { if (fill._renderer && fill._renderer.offset) { sx = fill._renderer.scale.x; sy = fill._renderer.scale.y; ctx.save(); ctx.translate( -fill._renderer.offset.x, -fill._renderer.offset.y ); ctx.scale(sx, sy); a = elem._size / fill._renderer.scale.y; b = elem._leading / fill._renderer.scale.y; ctx.font = [ elem._style, elem._weight, a + "px/", b + "px", elem._family ].join(" "); c = fill._renderer.offset.x / fill._renderer.scale.x; d = fill._renderer.offset.y / fill._renderer.scale.y; ctx.fillText(elem.value, c, d); ctx.restore(); } else { ctx.fillText(elem.value, 0, 0); } } if (!webgl.isHidden.test(stroke)) { if (stroke._renderer && stroke._renderer.offset) { sx = stroke._renderer.scale.x; sy = stroke._renderer.scale.y; ctx.save(); ctx.translate( -stroke._renderer.offset.x, -stroke._renderer.offset.y ); ctx.scale(sx, sy); a = elem._size / stroke._renderer.scale.y; b = elem._leading / stroke._renderer.scale.y; ctx.font = [ elem._style, elem._weight, a + "px/", b + "px", elem._family ].join(" "); c = stroke._renderer.offset.x / stroke._renderer.scale.x; d = stroke._renderer.offset.y / stroke._renderer.scale.y; e = linewidth / stroke._renderer.scale.x; ctx.lineWidth = e; ctx.strokeText(elem.value, c, d); ctx.restore(); } else { ctx.strokeText(elem.value, 0, 0); } } if (/(underline|strikethrough)/i.test(decoration)) { const metrics = ctx.measureText(elem.value); switch (decoration) { case "underline": y1 = metrics.actualBoundingBoxDescent; y2 = metrics.actualBoundingBoxDescent; break; case "strikethrough": y1 = 0; y2 = 0; break; } x1 = -metrics.width / 2; x2 = metrics.width / 2; ctx.lineWidth = Math.max(Math.floor(elem._size / 15), 1); ctx.strokeStyle = ctx.fillStyle; ctx.beginPath(); ctx.moveTo(x1, y1); ctx.lineTo(x2, y2); ctx.stroke(); } ctx.restore(); }, getBoundingClientRect: function(elem, rect) { const ctx = webgl.ctx; ctx.font = [elem._style, elem._weight, elem._size + "px/" + elem._leading + "px", elem._family].join(" "); ctx.textAlign = "center"; ctx.textBaseline = Renderer.Utils.baselines[elem._baseline] || elem._baseline; const metrics = ctx.measureText(elem._value); let width = metrics.width; let height = 1.15 * (metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent); if (this._linewidth && !webgl.isHidden.test(this._stroke)) { width += this._linewidth * 2; height += this._linewidth * 2; } const w = width / 2; const h = height / 2; switch (webgl.alignments[elem._alignment] || elem._alignment) { case webgl.alignments.left: if (elem.direction === "ltr") { rect.left = 0; rect.right = width; } else { rect.left = -width; rect.right = 0; } break; case webgl.alignments.right: if (elem.direction === "ltr") { rect.left = -width; rect.right = 0; } else { rect.left = 0; rect.right = width; } break; default: rect.left = -w; rect.right = w; } switch (elem._baseline) { case "bottom": rect.top = -height; rect.bottom = 0; break; case "top": rect.top = 0; rect.bottom = height; break; case "baseline": rect.top = -h * 1.5; rect.bottom = h * 0.5; break; default: rect.top = -h; rect.bottom = h; } rect.width = width; rect.height = height; if (!rect.centroid) { rect.centroid = {}; } rect.centroid.x = w; rect.centroid.y = h; }, render: function(gl, programs, forcedParent) { if (!this._visible || !this._opacity) { return this; } this._update(); const parent = forcedParent || this.parent; const program = programs[this._renderer.type]; const flagParentMatrix = parent._matrix.manual || parent._flagMatrix; const flagMatrix = this._matrix.manual || this._flagMatrix; const parentChanged = this._renderer.parent !== parent; const flagTexture = this._flagVertices || this._flagFill || this._fill instanceof LinearGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagEndPoints) || this._fill instanceof RadialGradient && (this._fill._flagSpread || this._fill._flagStops || this._fill._flagRadius || this._fill._flagCenter || this._fill._flagFocal) || this._fill instanceof Texture && (this._fill._flagLoaded && this._fill.loaded || this._fill._flagImage || this._fill._flagVideo || this._fill._flagRepeat || this._fill._flagOffset || this._fill._flagScale) || this._stroke instanceof LinearGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagEndPoints) || this._stroke instanceof RadialGradient && (this._stroke._flagSpread || this._stroke._flagStops || this._stroke._flagRadius || this._stroke._flagCenter || this._stroke._flagFocal) || this._stroke instanceof Texture && (this._stroke._flagLoaded && this._stroke.loaded || this._stroke._flagImage || this._stroke._flagVideo || this._stroke._flagRepeat || this._stroke._flagOffset || this._fill._flagScale) || this._flagStroke || this._flagLinewidth || this._flagOpacity || parent._flagOpacity || this._flagVisible || this._flagScale || this._flagValue || this._flagFamily || this._flagSize || this._flagLeading || this._flagAlignment || this._flagBaseline || this._flagStyle || this._flagWeight || this._flagDecoration || this.dashes && this.dashes.length > 0 || !this._renderer.texture; if (flagParentMatrix || flagMatrix || parentChanged) { if (!this._renderer.matrix) { this._renderer.matrix = new NumArray(9); } this._matrix.toTransformArray(true, transformation); multiplyMatrix(transformation, parent._renderer.matrix, this._renderer.matrix); if (!(this._renderer.scale instanceof Vector)) { this._renderer.scale = new Vector(); } if (this._scale instanceof Vector) { this._renderer.scale.x = this._scale.x * parent._renderer.scale.x; this._renderer.scale.y = this._scale.y * parent._renderer.scale.y; } else { this._renderer.scale.x = this._scale * parent._renderer.scale.x; this._renderer.scale.y = this._scale * parent._renderer.scale.y; } if (parentChanged) { this._renderer.parent = parent; } } if (this._mask) { gl.clear(gl.STENCIL_BUFFER_BIT); gl.enable(gl.STENCIL_TEST); gl.stencilFunc(gl.ALWAYS, 1, 0); gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE); gl.colorMask(false, false, false, false); webgl[this._mask._renderer.type].render.call(this._mask, gl, programs, this); gl.stencilFunc(gl.EQUAL, 1, 255); gl.stencilOp(gl.KEEP, gl.KEEP, gl.KEEP); gl.colorMask(true, true, true, true); } if (flagTexture) { if (!this._renderer.rect) { this._renderer.rect = {}; } this._renderer.opacity = this._opacity * parent._renderer.opacity; webgl.text.getBoundingClientRect(this, this._renderer.rect); webgl.updateTexture.call(webgl, gl, this); } else { if (this._fill && this._fill._update) { this._fill._update(); } if (this._stroke && this._stroke._update) { this._stroke._update(); } } if (this._clip && !forcedParent || !this._renderer.texture) { return this; } if (programs.current !== program) { gl.useProgram(program); gl.bindBuffer(gl.ARRAY_BUFFER, programs.buffers.position); gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(program.position); gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW); if (!programs.resolution.flagged) { gl.uniform2f( gl.getUniformLocation(program, "u_resolution"), programs.resolution.width, programs.resolution.height ); } programs.current = program; } if (programs.resolution.flagged) { gl.uniform2f( gl.getUniformLocation(program, "u_resolution"), programs.resolution.width, programs.resolution.height ); } gl.bindTexture(gl.TEXTURE_2D, this._renderer.texture); const rect = this._renderer.rect; gl.uniformMatrix3fv(program.matrix, false, this._renderer.matrix); gl.uniform4f(program.rect, rect.left, rect.top, rect.right, rect.bottom); gl.drawArrays(gl.TRIANGLES, 0, 6); if (this._mask) { gl.disable(gl.STENCIL_TEST); } return this.flagReset(); } }, "linear-gradient": { render: function(ctx, parent) { if (!ctx.canvas.getContext("2d") || !parent) { return; } this._update(); if (!this._renderer.effect || this._flagEndPoints || this._flagStops || this._flagUnits) { let rect; let lx = this.left._x; let ly = this.left._y; let rx = this.right._x; let ry = this.right._y; if (/objectBoundingBox/i.test(this._units)) { rect = parent.getBoundingClientRect(true); lx = (lx - 0.5) * rect.width; ly = (ly - 0.5) * rect.height; rx = (rx - 0.5) * rect.width; ry = (ry - 0.5) * rect.height; } this._renderer.effect = ctx.createLinearGradient(lx, ly, rx, ry); for (let i = 0; i < this.stops.length; i++) { const stop = this.stops[i]; this._renderer.effect.addColorStop(stop._offset, stop._color); } } return this.flagReset(); } }, "radial-gradient": { render: function(ctx, parent) { if (!ctx.canvas.getContext("2d") || !parent) { return; } this._update(); if (!this._renderer.effect || this._flagCenter || this._flagFocal || this._flagRadius || this._flagStops || this._flagUnits) { let rect; let cx = this.center._x; let cy = this.center._y; let fx = this.focal._x; let fy = this.focal._y; let radius = this._radius; if (/objectBoundingBox/i.test(this._units)) { rect = parent.getBoundingClientRect(true); cx = cx * rect.width * 0.5; cy = cy * rect.height * 0.5; fx = fx * rect.width * 0.5; fy = fy * rect.height * 0.5; radius *= Math.min(rect.width, rect.height) * 0.5; } this._renderer.effect = ctx.createRadialGradient( cx, cy, 0, fx, fy, radius ); for (let i = 0; i < this.stops.length; i++) { const stop = this.stops[i]; this._renderer.effect.addColorStop(stop._offset, stop._color); } } return this.flagReset(); } }, texture: { render: function(ctx, elem) { if (!ctx.canvas.getContext("2d")) { return; } this._update(); const image = this.image; if ((this._flagLoaded || this._flagImage || this._flagVideo || this._flagRepeat) && this.loaded) { this._renderer.effect = ctx.createPattern(image, this._repeat); } else if (!this._renderer.effect) { return this.flagReset(); } if (this._flagOffset || this._flagLoaded || this._flagScale) { if (!(this._renderer.offset instanceof Vector)) { this._renderer.offset = new Vector(); } this._renderer.offset.x = -this._offset.x; this._renderer.offset.y = -this._offset.y; if (image) { this._renderer.offset.x += image.width / 2; this._renderer.offset.y += image.height / 2; if (this._scale instanceof Vector) { this._renderer.offset.x *= this._scale.x; this._renderer.offset.y *= this._scale.y; } else { this._renderer.offset.x *= this._scale; this._renderer.offset.y *= this._scale; } } } if (this._flagScale || this._flagLoaded) { if (!(this._renderer.scale instanceof Vector)) { this._renderer.scale = new Vector(); } if (this._scale instanceof Vector) { this._renderer.scale.copy(this._scale); } else { this._renderer.scale.set(this._scale, this._scale); } } return this.flagReset(); } }, updateTexture: function(gl, elem) { this[elem._renderer.type].updateCanvas.call(webgl, gl, elem); if (this.canvas.width <= 0 || this.canvas.height <= 0) { if (elem._renderer.texture) { gl.deleteTexture(elem._renderer.texture); } delete elem._renderer.texture; return; } if (!elem._renderer.texture) { elem._renderer.texture = gl.createTexture(); } gl.bindTexture(gl.TEXTURE_2D, elem._renderer.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.canvas); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); }, program: { create: function(gl, shaders2) { let program, linked, error; program = gl.createProgram(); _.each(shaders2, function(s) { gl.attachShader(program, s); }); gl.linkProgram(program); linked = gl.getProgramParameter(program, gl.LINK_STATUS); if (!linked) { error = gl.getProgramInfoLog(program); gl.deleteProgram(program); throw new TwoError("unable to link program: " + error); } return program; } }, extensions: { init: function(gl) { const extensions = {}; const names = [ "EXT_texture_filter_anisotropic", "WEBGL_compressed_texture_s3tc", "OES_texture_float_linear", "WEBGL_multisampled_render_to_texture" ]; for (let i = 0; i < names.length; i++) { const name = names[i]; extensions[name] = webgl.extensions.get(gl, name); } return extensions; }, get: function(gl, name) { return gl.getExtension(name) || gl.getExtension(`MOZ_${name}`) || gl.getExtension(`WEBKIT_${name}`); } }, TextureRegistry: new Registry() }; webgl.ctx = webgl.canvas.getContext("2d"); var Renderer3 = class extends Events { constructor(params) { super(); let gl, program, vs, fs; this.domElement = params.domElement || document.createElement("canvas"); if (typeof params.offscreenElement !== "undefined") { webgl.canvas = params.offscreenElement; webgl.ctx = webgl.canvas.getContext("2d"); } this.scene = new Group(); this.scene.parent = this; this._renderer = { type: "renderer", matrix: new NumArray(identity), scale: 1, opacity: 1 }; this._flagMatrix = true; params = _.defaults(params || {}, { antialias: false, alpha: true, premultipliedAlpha: true, stencil: true, preserveDrawingBuffer: true, overdraw: false }); this.overdraw = params.overdraw; gl = this.ctx = this.domElement.getContext("webgl", params) || this.domElement.getContext("experimental-webgl", params); if (!this.ctx) { throw new TwoError( "unable to create a webgl context. Try using another renderer." ); } vs = shaders.create(gl, shaders.path.vertex, shaders.types.vertex); fs = shaders.create(gl, shaders.path.fragment, shaders.types.fragment); this.programs = { current: null, buffers: { position: gl.createBuffer() }, resolution: { width: 0, height: 0, ratio: 1, flagged: false } }; program = this.programs.path = webgl.program.create(gl, [vs, fs]); this.programs.text = this.programs.path; gl.extensions = webgl.extensions.init(gl); gl.renderer = this; program.position = gl.getAttribLocation(program, "a_position"); program.matrix = gl.getUniformLocation(program, "u_matrix"); program.rect = gl.getUniformLocation(program, "u_rect"); const positionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); gl.vertexAttribPointer(program.position, 2, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(program.position); gl.bufferData(gl.ARRAY_BUFFER, quad, gl.STATIC_DRAW); vs = shaders.create(gl, shaders.points.vertex, shaders.types.vertex); fs = shaders.create(gl, shaders.points.fragment, shaders.types.fragment); program = this.programs.points = webgl.program.create(gl, [vs, fs]); program.position = gl.getAttribLocation(program, "a_position"); program.matrix = gl.getUniformLocation(program, "u_matrix"); program.size = gl.getUniformLocation(program, "u_size"); gl.enable(gl.BLEND); gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA); } setSize(width, height, ratio) { let w, h; const ctx = this.ctx; this.width = width; this.height = height; this.ratio = typeof ratio === "undefined" ? getRatio(ctx) : ratio; this.domElement.width = width * this.ratio; this.domElement.height = height * this.ratio; if (_.isObject(this.domElement.style)) { _.extend(this.domElement.style, { width: width + "px", height: height + "px" }); } this._renderer.matrix[0] = this._renderer.matrix[4] = this._renderer.scale = this.ratio; this._flagMatrix = true; w = width * this.ratio; h = height * this.ratio; ctx.viewport(0, 0, w, h); this.programs.resolution.width = w; this.programs.resolution.height = h; this.programs.resolution.ratio = this.ratio; this.programs.resolution.flagged = true; return this.trigger(Events.Types.resize, width, height, ratio); } render() { const gl = this.ctx; if (!this.overdraw) { gl.clear(gl.COLOR_BUFFER_BIT); } webgl.group.render.call(this.scene, gl, this.programs); this._flagMatrix = false; this.programs.resolution.flagged = true; return this; } }; __publicField(Renderer3, "Utils", webgl); // src/two.js var Utils = _.extend({ Error: TwoError, getRatio, read, xhr }, _, CanvasShim, curves_exports, math_exports); var _Two = class { _events = new Events(); get _bound() { return this._events._bound; } set _bound(v) { this._events._bound = v; } addEventListener() { return this._events.addEventListener.apply(this, arguments); } on() { return this._events.addEventListener.apply(this, arguments); } bind() { return this._events.addEventListener.apply(this, arguments); } removeEventListener() { return this._events.removeEventListener.apply(this, arguments); } off() { return this._events.removeEventListener.apply(this, arguments); } unbind() { return this._events.removeEventListener.apply(this, arguments); } dispatchEvent() { return this._events.dispatchEvent.apply(this, arguments); } trigger() { return this._events.dispatchEvent.apply(this, arguments); } listen() { return this._events.listen.apply(this, arguments); } ignore() { return this._events.ignore.apply(this, arguments); } type = ""; renderer = null; scene = null; width = 0; height = 0; frameCount = 0; timeDelta = 0; playing = false; constructor(options) { const params = _.defaults(options || {}, { fullscreen: false, fitted: false, width: 640, height: 480, type: _Two.Types.svg, autostart: false }); _.each(params, function(v, k) { if (/fullscreen/i.test(k) || /autostart/i.test(k)) { return; } this[k] = v; }, this); if (_.isElement(params.domElement)) { const tagName = params.domElement.tagName.toLowerCase(); if (!/^(CanvasRenderer-canvas|WebGLRenderer-canvas|SVGRenderer-svg)$/.test(this.type + "-" + tagName)) { this.type = _Two.Types[tagName]; } } this.renderer = new _Two[this.type](this); this.setPlaying(params.autostart); this.frameCount = 0; if (params.fullscreen) { this.fit = fitToWindow.bind(this); this.fit.domElement = window; this.fit.attached = true; _.extend(document.body.style, { overflow: "hidden", margin: 0, padding: 0, top: 0, left: 0, right: 0, bottom: 0, position: "fixed" }); _.extend(this.renderer.domElement.style, { display: "block", top: 0, left: 0, right: 0, bottom: 0, position: "fixed" }); dom.bind(this.fit.domElement, "resize", this.fit); this.fit(); } else if (params.fitted) { this.fit = fitToParent.bind(this); _.extend(this.renderer.domElement.style, { display: "block" }); } else if (!_.isElement(params.domElement)) { this.renderer.setSize(params.width, params.height, this.ratio); this.width = params.width; this.height = params.height; } this.renderer.bind(Events.Types.resize, updateDimensions.bind(this)); this.scene = this.renderer.scene; _Two.Instances.push(this); if (params.autostart) { raf.init(); } } appendTo(elem) { elem.appendChild(this.renderer.domElement); if (this.fit) { if (this.fit.domElement !== window) { this.fit.domElement = elem; this.fit.attached = false; } this.update(); } return this; } play() { this.playing = true; raf.init(); return this.trigger(Events.Types.play); } pause() { this.playing = false; return this.trigger(Events.Types.pause); } setPlaying(p) { this.playing = p; } release(obj) { let i, v, child; if (!_.isObject(obj)) { return this.release(this.scene); } if (typeof obj.unbind === "function") { obj.unbind(); } if (obj.vertices) { if (typeof obj.vertices.unbind === "function") { obj.vertices.unbind(); } for (i = 0; i < obj.vertices.length; i++) { v = obj.vertices[i]; if (typeof v.unbind === "function") { v.unbind(); } if (v.controls) { if (v.controls.left && typeof v.controls.left.unbind === "function") { v.controls.left.unbind(); } if (v.controls.right && typeof v.controls.right.unbind === "function") { v.controls.right.unbind(); } } } } if (obj.children) { for (i = 0; i < obj.children.length; i++) { child = obj.children[i]; this.release(child); } if (typeof obj.children.unbind === "function") { obj.children.unbind(); } } return obj; } update() { const animated = !!this._lastFrame; const now = _.performance.now(); if (animated) { this.timeDelta = parseFloat((now - this._lastFrame).toFixed(3)); } this._lastFrame = now; if (this.fit && this.fit.domElement && !this.fit.attached) { dom.bind(this.fit.domElement, "resize", this.fit); this.fit.attached = true; this.fit(); } const width = this.width; const height = this.height; const renderer = this.renderer; if (width !== renderer.width || height !== renderer.height) { renderer.setSize(width, height, this.ratio); } this.trigger(Events.Types.update, this.frameCount, this.timeDelta); return this.render(); } render() { this.renderer.render(); return this.trigger(Events.Types.render, this.frameCount++); } add(objects) { if (!(objects instanceof Array)) { objects = Array.prototype.slice.call(arguments); } this.scene.add(objects); return this; } remove(objects) { if (!(objects instanceof Array)) { objects = Array.prototype.slice.call(arguments); } this.scene.remove(objects); return this; } clear() { this.scene.remove(this.scene.children); return this; } makeLine(x1, y1, x2, y2) { const line = new Line(x1, y1, x2, y2); this.scene.add(line); return line; } makeArrow(x1, y1, x2, y2, size) { const headlen = typeof size === "number" ? size : 10; const angle = Math.atan2(y2 - y1, x2 - x1); const vertices = [ new Anchor(x1, y1, void 0, void 0, void 0, void 0, Commands.move), new Anchor(x2, y2, void 0, void 0, void 0, void 0, Commands.line), new Anchor( x2 - headlen * Math.cos(angle - Math.PI / 4), y2 - headlen * Math.sin(angle - Math.PI / 4), void 0, void 0, void 0, void 0, Commands.line ), new Anchor(x2, y2, void 0, void 0, void 0, void 0, Commands.move), new Anchor( x2 - headlen * Math.cos(angle + Math.PI / 4), y2 - headlen * Math.sin(angle + Math.PI / 4), void 0, void 0, void 0, void 0, Commands.line ) ]; const path = new Path(vertices, false, false, true); path.noFill(); path.cap = "round"; path.join = "round"; this.scene.add(path); return path; } makeRectangle(x, y, width, height) { const rect = new Rectangle(x, y, width, height); this.scene.add(rect); return rect; } makeRoundedRectangle(x, y, width, height, sides) { const rect = new RoundedRectangle(x, y, width, height, sides); this.scene.add(rect); return rect; } makeCircle(x, y, radius, resolution) { const circle = new Circle(x, y, radius, resolution); this.scene.add(circle); return circle; } makeEllipse(x, y, rx, ry, resolution) { const ellipse = new Ellipse(x, y, rx, ry, resolution); this.scene.add(ellipse); return ellipse; } makeStar(x, y, outerRadius, innerRadius, sides) { const star = new Star(x, y, outerRadius, innerRadius, sides); this.scene.add(star); return star; } makeCurve(points) { const l = arguments.length; if (!Array.isArray(points)) { points = []; for (let i = 0; i < l; i += 2) { const x = arguments[i]; if (typeof x !== "number") { break; } const y = arguments[i + 1]; points.push(new Anchor(x, y)); } } const last = arguments[l - 1]; const curve = new Path(points, !(typeof last === "boolean" ? last : void 0), true); const rect = curve.getBoundingClientRect(); curve.center().translation.set(rect.left + rect.width / 2, rect.top + rect.height / 2); this.scene.add(curve); return curve; } makePolygon(x, y, radius, sides) { const poly = new Polygon(x, y, radius, sides); this.scene.add(poly); return poly; } makeArcSegment(x, y, innerRadius, outerRadius, startAngle, endAngle, resolution) { const arcSegment = new ArcSegment( x, y, innerRadius, outerRadius, startAngle, endAngle, resolution ); this.scene.add(arcSegment); return arcSegment; } makePoints(p) { const l = arguments.length; let vertices = p; if (!Array.isArray(p)) { vertices = []; for (let i = 0; i < l; i += 2) { const x = arguments[i]; if (typeof x !== "number") { break; } const y = arguments[i + 1]; vertices.push(new Vector(x, y)); } } const points = new Points(vertices); this.scene.add(points); return points; } makePath(p) { const l = arguments.length; let points = p; if (!Array.isArray(p)) { points = []; for (let i = 0; i < l; i += 2) { const x = arguments[i]; if (typeof x !== "number") { break; } const y = arguments[i + 1]; points.push(new Anchor(x, y)); } } const last = arguments[l - 1]; const path = new Path(points, !(typeof last === "boolean" ? last : void 0)); const rect = path.getBoundingClientRect(); if (typeof rect.top === "number" && typeof rect.left === "number" && typeof rect.right === "number" && typeof rect.bottom === "number") { path.center().translation.set(rect.left + rect.width / 2, rect.top + rect.height / 2); } this.scene.add(path); return path; } makeText(message, x, y, styles) { const text = new Text(message, x, y, styles); this.add(text); return text; } makeLinearGradient(x1, y1, x2, y2) { const stops = Array.prototype.slice.call(arguments, 4); const gradient = new LinearGradient(x1, y1, x2, y2, stops); this.add(gradient); return gradient; } makeRadialGradient(x1, y1, radius) { const stops = Array.prototype.slice.call(arguments, 3); const gradient = new RadialGradient(x1, y1, radius, stops); this.add(gradient); return gradient; } makeSprite(pathOrTexture, x, y, columns, rows, frameRate, autostart) { const sprite = new Sprite(pathOrTexture, x, y, columns, rows, frameRate); if (autostart) { sprite.play(); } this.add(sprite); return sprite; } makeImageSequence(pathsOrTextures, x, y, frameRate, autostart) { const imageSequence = new ImageSequence(pathsOrTextures, x, y, frameRate); if (autostart) { imageSequence.play(); } this.add(imageSequence); return imageSequence; } makeTexture(pathOrSource, callback) { const texture = new Texture(pathOrSource, callback); return texture; } makeGroup(objects) { if (!(objects instanceof Array)) { objects = Array.prototype.slice.call(arguments); } const group = new Group(); this.scene.add(group); group.add(objects); return group; } interpret(svg2, shallow, add) { const tag = svg2.tagName.toLowerCase(); add = typeof add !== "undefined" ? add : true; if (!(tag in read)) { return null; } const node = read[tag].call(this, svg2); if (add) { this.add(shallow && node instanceof Group ? node.children : node); } else if (node.parent) { node.remove(); } return node; } load(pathOrSVGContent, callback) { const group = new Group(); let elem, i, child; const attach = function(data) { dom.temp.innerHTML = data; for (i = 0; i < dom.temp.children.length; i++) { elem = dom.temp.children[i]; child = this.interpret(elem, false, false); if (child !== null) { group.add(child); } } if (typeof callback === "function") { const svg2 = dom.temp.children.length <= 1 ? dom.temp.children[0] : dom.temp.children; callback(group, svg2); } }.bind(this); if (/\.svg$/i.test(pathOrSVGContent)) { xhr(pathOrSVGContent, attach); return group; } attach(pathOrSVGContent); return group; } }; var Two = _Two; __publicField(Two, "nextFrameID", Constants.nextFrameID); __publicField(Two, "Types", Constants.Types); __publicField(Two, "Version", Constants.Version); __publicField(Two, "PublishDate", Constants.PublishDate); __publicField(Two, "Identifier", Constants.Identifier); __publicField(Two, "Resolution", Constants.Resolution); __publicField(Two, "AutoCalculateImportedMatrices", Constants.AutoCalculateImportedMatrices); __publicField(Two, "Instances", Constants.Instances); __publicField(Two, "uniqueId", Constants.uniqueId); __publicField(Two, "Anchor", Anchor); __publicField(Two, "Collection", Collection); __publicField(Two, "Events", Events); __publicField(Two, "Group", Group); __publicField(Two, "Matrix", Matrix2); __publicField(Two, "Path", Path); __publicField(Two, "Registry", Registry); __publicField(Two, "Shape", Shape); __publicField(Two, "Text", Text); __publicField(Two, "Vector", Vector); __publicField(Two, "Gradient", Gradient); __publicField(Two, "ImageSequence", ImageSequence); __publicField(Two, "LinearGradient", LinearGradient); __publicField(Two, "RadialGradient", RadialGradient); __publicField(Two, "Sprite", Sprite); __publicField(Two, "Stop", Stop); __publicField(Two, "Texture", Texture); __publicField(Two, "ArcSegment", ArcSegment); __publicField(Two, "Circle", Circle); __publicField(Two, "Ellipse", Ellipse); __publicField(Two, "Line", Line); __publicField(Two, "Points", Points); __publicField(Two, "Polygon", Polygon); __publicField(Two, "Rectangle", Rectangle); __publicField(Two, "RoundedRectangle", RoundedRectangle); __publicField(Two, "Star", Star); __publicField(Two, "CanvasRenderer", Renderer); __publicField(Two, "SVGRenderer", Renderer2); __publicField(Two, "WebGLRenderer", Renderer3); __publicField(Two, "Commands", Commands); __publicField(Two, "Utils", Utils); function fitToWindow() { const wr = document.body.getBoundingClientRect(); const width = this.width = wr.width; const height = this.height = wr.height; this.renderer.setSize(width, height, this.ratio); } function fitToParent() { const parent = this.renderer.domElement.parentElement; if (!parent) { console.warn("Two.js: Attempting to fit to parent, but no parent found."); return; } const wr = parent.getBoundingClientRect(); const width = this.width = wr.width; const height = this.height = wr.height; this.renderer.setSize(width, height, this.ratio); } function updateDimensions(width, height) { this.width = width; this.height = height; this.trigger(Events.Types.resize, width, height); } var raf = dom.getRequestAnimationFrame(); function loop() { for (let i = 0; i < Two.Instances.length; i++) { const t = Two.Instances[i]; if (t.playing) { t.update(); } } Two.nextFrameID = raf(loop); } raf.init = function() { loop(); raf.init = function() { }; }; return __toCommonJS(two_exports); })().default; (function(){if(typeof exports==='object'&&typeof module!=='undefined'){module.exports=Two}})()