diff --git a/CHANGELOG.md b/CHANGELOG.md index 66c63c84e4b..6e2dd637636 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,17 +3,17 @@ ## [5.0.0] +- fix(fabric.Canvas): unflag contextLost after a full re-render [`#7646`](https://github.com/fabricjs/fabric.js/pull/7646) +- **BREAKING**: remove 4.x deprecated code [`#7630`](https://github.com/fabricjs/fabric.js/pull/7630) +- feat(fabric.StaticCanvas, fabric.Canvas): limit breaking changes [`#7627`](https://github.com/fabricjs/fabric.js/pull/7627) +- feat(animation): animations registry [`#7528`](https://github.com/fabricjs/fabric.js/pull/7528) +- docs(): Remove not working badges [`#7623`](https://github.com/fabricjs/fabric.js/pull/7623) +- ci(): add auto-changelog package to quickly draft a changelog [`#7615`](https://github.com/fabricjs/fabric.js/pull/7615) - feat(fabric.EraserBrush): added `eraser` property to Object instead of attaching to `clipPath`, remove hacky `getClipPath`/`setClipPath` [#7470](https://github.com/fabricjs/fabric.js/pull/7470), see **BREAKING** comments. - feat(fabric.EraserBrush): support `inverted` option to undo erasing [#7470](https://github.com/fabricjs/fabric.js/pull/7470) - fix(fabric.EraserBrush): fix doubling opaic objects while erasing [#7445](https://github.com/fabricjs/fabric.js/issues/7445) [#7470](https://github.com/fabricjs/fabric.js/pull/7470) - -**BREAKING**: - -- fabric.EraserBrush: The Eraser object is now a subclass of Group. This means that loading from JSON will break between versions. +- **BREAKING**: fabric.EraserBrush: The Eraser object is now a subclass of Group. This means that loading from JSON will break between versions. Use this [code](https://gist.github.com/ShaMan123/6c5c4ca2cc720a2700848a2deb6addcd) to transform your json payload to the new version. - - -## [next] - feat(fabric.Canvas): fire an extra mouse up for the original control of the initial target [`#7612`](https://github.com/fabricjs/fabric.js/pull/7612) - fix(fabric.Object) bounding box display with skewY when outside group [`#7611`](https://github.com/fabricjs/fabric.js/pull/7611) - fix(fabric.text) fix rtl/ltr performance issues [`#7610`](https://github.com/fabricjs/fabric.js/pull/7610) @@ -21,9 +21,9 @@ Use this [code](https://gist.github.com/ShaMan123/6c5c4ca2cc720a2700848a2deb6add - feat(): `drop:before` event [`#7442`](https://github.com/fabricjs/fabric.js/pull/7442) - ci(): Add codeql analysis step [`#7588`](https://github.com/fabricjs/fabric.js/pull/7588) - security(): update onchange to solve security issue [`#7591`](https://github.com/fabricjs/fabric.js/pull/7591) -- fix(): MAJOR prevent render canvas with quality less than 100% [`#7537`](https://github.com/fabricjs/fabric.js/pull/7537) +- **BREAKING**: fix(): MAJOR prevent render canvas with quality less than 100% [`#7537`](https://github.com/fabricjs/fabric.js/pull/7537) - docs(): fix broken link [`#7579`](https://github.com/fabricjs/fabric.js/pull/7579) -- Deps(): MAJOR update to jsdom 19 node 14 [`#7587`](https://github.com/fabricjs/fabric.js/pull/7587) +- **BREAKING**: Deps(): MAJOR update to jsdom 19 node 14 [`#7587`](https://github.com/fabricjs/fabric.js/pull/7587) - Fix(): JSDOM transative vulnerability [`#7510`](https://github.com/fabricjs/fabric.js/pull/7510) - fix(fabric.parser): attempt to resolve some issues with regexp [`#7520`](https://github.com/fabricjs/fabric.js/pull/7520) - fix(fabric.IText) fix for possible error on copy paste [`#7526`](https://github.com/fabricjs/fabric.js/pull/7526) diff --git a/HEADER.js b/HEADER.js index 416b2451946..6071a959136 100644 --- a/HEADER.js +++ b/HEADER.js @@ -1,6 +1,6 @@ /*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */ -var fabric = fabric || { version: '4.6.0' }; +var fabric = fabric || { version: '5.0.0' }; if (typeof exports !== 'undefined') { exports.fabric = fabric; } diff --git a/README.md b/README.md index e195d3aff44..3e559718fc7 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ Fabric.js allows you to easily create simple shapes like rectangles, circles, tr - Opera 9.64+ - Chrome (all versions) - Edge (chromium based, all versions) -- IE11 and Edge legacy, supported but deprecated. +- IE11 and Edge legacy, not supported. Fabric up to 5.0 is written with ES5 in mind, but no specific tests are run for those browsers. You can [run automated unit tests](http://fabricjs.com/test/unit/) right in the browser. diff --git a/dist/fabric.js b/dist/fabric.js index 86536ce06be..2ee10b2b0ac 100644 --- a/dist/fabric.js +++ b/dist/fabric.js @@ -1,7 +1,7 @@ /* build: `node build.js modules=ALL exclude=gestures,accessors,erasing requirejs minifier=uglifyjs` */ /*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */ -var fabric = fabric || { version: '4.6.0' }; +var fabric = fabric || { version: '5.0.0' }; if (typeof exports !== 'undefined') { exports.fabric = fabric; } @@ -762,6 +762,135 @@ fabric.CommonMethods = { }; }, + /** + * Creates a vetor from points represented as a point + * @static + * @memberOf fabric.util + * + * @typedef {Object} Point + * @property {number} x + * @property {number} y + * + * @param {Point} from + * @param {Point} to + * @returns {Point} vector + */ + createVector: function (from, to) { + return new fabric.Point(to.x - from.x, to.y - from.y); + }, + + /** + * Calculates angle between 2 vectors using dot product + * @static + * @memberOf fabric.util + * @param {Point} a + * @param {Point} b + * @returns the angle in radian between the vectors + */ + calcAngleBetweenVectors: function (a, b) { + return Math.acos((a.x * b.x + a.y * b.y) / (Math.hypot(a.x, a.y) * Math.hypot(b.x, b.y))); + }, + + /** + * @static + * @memberOf fabric.util + * @param {Point} v + * @returns {Point} vector representing the unit vector of pointing to the direction of `v` + */ + getHatVector: function (v) { + return new fabric.Point(v.x, v.y).multiply(1 / Math.hypot(v.x, v.y)); + }, + + /** + * @static + * @memberOf fabric.util + * @param {Point} A + * @param {Point} B + * @param {Point} C + * @returns {{ vector: Point, angle: number }} vector representing the bisector of A and A's angle + */ + getBisector: function (A, B, C) { + var AB = fabric.util.createVector(A, B), AC = fabric.util.createVector(A, C); + var alpha = fabric.util.calcAngleBetweenVectors(AB, AC); + // check if alpha is relative to AB->BC + var ro = fabric.util.calcAngleBetweenVectors(fabric.util.rotateVector(AB, alpha), AC); + var phi = alpha * (ro === 0 ? 1 : -1) / 2; + return { + vector: fabric.util.getHatVector(fabric.util.rotateVector(AB, phi)), + angle: alpha + }; + }, + + /** + * Project stroke width on points returning 2 projections for each point as follows: + * - `miter`: 2 points corresponding to the outer boundary and the inner boundary of stroke. + * - `bevel`: 2 points corresponding to the bevel boundaries, tangent to the bisector. + * - `round`: same as `bevel` + * Used to calculate object's bounding box + * @static + * @memberOf fabric.util + * @param {Point[]} points + * @param {Object} options + * @param {number} options.strokeWidth + * @param {'miter'|'bevel'|'round'} options.strokeLineJoin + * @param {number} options.strokeMiterLimit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit + * @param {boolean} options.strokeUniform + * @param {number} options.scaleX + * @param {number} options.scaleY + * @param {boolean} [openPath] whether the shape is open or not, affects the calculations of the first and last points + * @returns {fabric.Point[]} array of size 2n/4n of all suspected points + */ + projectStrokeOnPoints: function (points, options, openPath) { + var coords = [], s = options.strokeWidth / 2, + strokeUniformScalar = options.strokeUniform ? + new fabric.Point(1 / options.scaleX, 1 / options.scaleY) : new fabric.Point(1, 1), + getStrokeHatVector = function (v) { + var scalar = s / (Math.hypot(v.x, v.y)); + return new fabric.Point(v.x * scalar * strokeUniformScalar.x, v.y * scalar * strokeUniformScalar.y); + }; + if (points.length <= 1) {return coords;} + points.forEach(function (p, index) { + var A = new fabric.Point(p.x, p.y), B, C; + if (index === 0) { + C = points[index + 1]; + B = openPath ? getStrokeHatVector(fabric.util.createVector(C, A)).addEquals(A) : points[points.length - 1]; + } + else if (index === points.length - 1) { + B = points[index - 1]; + C = openPath ? getStrokeHatVector(fabric.util.createVector(B, A)).addEquals(A) : points[0]; + } + else { + B = points[index - 1]; + C = points[index + 1]; + } + var bisector = fabric.util.getBisector(A, B, C), + bisectorVector = bisector.vector, + alpha = bisector.angle, + scalar, + miterVector; + if (options.strokeLineJoin === 'miter') { + scalar = -s / Math.sin(alpha / 2); + miterVector = new fabric.Point( + bisectorVector.x * scalar * strokeUniformScalar.x, + bisectorVector.y * scalar * strokeUniformScalar.y + ); + if (Math.hypot(miterVector.x, miterVector.y) / s <= options.strokeMiterLimit) { + coords.push(A.add(miterVector)); + coords.push(A.subtract(miterVector)); + return; + } + } + scalar = -s * Math.SQRT2; + miterVector = new fabric.Point( + bisectorVector.x * scalar * strokeUniformScalar.x, + bisectorVector.y * scalar * strokeUniformScalar.y + ); + coords.push(A.add(miterVector)); + coords.push(A.subtract(miterVector)); + }); + return coords; + }, + /** * Apply transform t to point p * @static @@ -1074,6 +1203,25 @@ fabric.CommonMethods = { }); }, + /** + * Creates corresponding fabric instances residing in an object, e.g. `clipPath` + * @see {@link fabric.Object.ENLIVEN_PROPS} + * @param {Object} object + * @param {Object} [context] assign enlived props to this object (pass null to skip this) + * @param {(objects:fabric.Object[]) => void} callback + */ + enlivenObjectEnlivables: function (object, context, callback) { + var enlivenProps = fabric.Object.ENLIVEN_PROPS.filter(function (key) { return !!object[key]; }); + fabric.util.enlivenObjects(enlivenProps.map(function (key) { return object[key]; }), function (enlivedProps) { + var objects = {}; + enlivenProps.forEach(function (key, index) { + objects[key] = enlivedProps[index]; + context && (context[key] = enlivedProps[index]); + }); + callback && callback(objects); + }); + }, + /** * Create and wait for loading of patterns * @static @@ -1165,49 +1313,6 @@ fabric.CommonMethods = { } }, - /** - * WARNING: THIS WAS TO SUPPORT OLD BROWSERS. deprecated. - * WILL BE REMOVED IN FABRIC 5.0 - * Draws a dashed line between two points - * - * This method is used to draw dashed line around selection area. - * See dotted stroke in canvas - * - * @param {CanvasRenderingContext2D} ctx context - * @param {Number} x start x coordinate - * @param {Number} y start y coordinate - * @param {Number} x2 end x coordinate - * @param {Number} y2 end y coordinate - * @param {Array} da dash array pattern - * @deprecated - */ - drawDashedLine: function(ctx, x, y, x2, y2, da) { - var dx = x2 - x, - dy = y2 - y, - len = sqrt(dx * dx + dy * dy), - rot = atan2(dy, dx), - dc = da.length, - di = 0, - draw = true; - - ctx.save(); - ctx.translate(x, y); - ctx.moveTo(0, 0); - ctx.rotate(rot); - - x = 0; - while (len > x) { - x += da[di++ % dc]; - if (x > len) { - x = len; - } - ctx[draw ? 'lineTo' : 'moveTo'](x, 0); - draw = !draw; - } - - ctx.restore(); - }, - /** * Creates canvas element * @static @@ -1335,7 +1440,7 @@ fabric.CommonMethods = { * @param {Boolean} [options.flipX] * @param {Boolean} [options.flipY] * @param {Number} [options.skewX] - * @param {Number} [options.skewX] + * @param {Number} [options.skewY] * @return {Number[]} transform matrix */ calcDimensionsMatrix: function(options) { @@ -1689,7 +1794,50 @@ fabric.CommonMethods = { x: bbox.width, y: bbox.height, }; - } + }, + + /** + * Merges 2 clip paths into one visually equal clip path + * + * **IMPORTANT**:\ + * Does **NOT** clone the arguments, clone them proir if necessary. + * + * Creates a wrapper (group) that contains one clip path and is clipped by the other so content is kept where both overlap. + * Use this method if both the clip paths may have nested clip paths of their own, so assigning one to the other's clip path property is not possible. + * + * In order to handle the `inverted` property we follow logic described in the following cases:\ + * **(1)** both clip paths are inverted - the clip paths pass the inverted prop to the wrapper and loose it themselves.\ + * **(2)** one is inverted and the other isn't - the wrapper shouldn't become inverted and the inverted clip path must clip the non inverted one to produce an identical visual effect.\ + * **(3)** both clip paths are not inverted - wrapper and clip paths remain unchanged. + * + * @memberOf fabric.util + * @param {fabric.Object} c1 + * @param {fabric.Object} c2 + * @returns {fabric.Object} merged clip path + */ + mergeClipPaths: function (c1, c2) { + var a = c1, b = c2; + if (a.inverted && !b.inverted) { + // case (2) + a = c2; + b = c1; + } + // `b` becomes `a`'s clip path so we transform `b` to `a` coordinate plane + fabric.util.applyTransformToObject( + b, + fabric.util.multiplyTransformMatrices( + fabric.util.invertTransform(a.calcTransformMatrix()), + b.calcTransformMatrix() + ) + ); + // assign the `inverted` prop to the wrapping group + var inverted = a.inverted && b.inverted; + if (inverted) { + // case (1) + a.inverted = b.inverted = false; + } + return new fabric.Group([a], { clipPath: b, inverted: inverted }); + }, }; })(typeof exports !== 'undefined' ? exports : this); @@ -2203,15 +2351,15 @@ fabric.CommonMethods = { p, nextLen, nextStep = 0.01, angleFinder = segInfo.angleFinder, lastPerc; // nextStep > 0.0001 covers 0.00015625 that 1/64th of 1/100 // the path - while (tmpLen < distance && perc <= 1 && nextStep > 0.0001) { + while (tmpLen < distance && nextStep > 0.0001) { p = iterator(perc); lastPerc = perc; nextLen = calcLineLength(tempP.x, tempP.y, p.x, p.y); // compare tmpLen each cycle with distance, decide next perc to test. if ((nextLen + tmpLen) > distance) { // we discard this step and we make smaller steps. - nextStep /= 2; perc -= nextStep; + nextStep /= 2; } else { tempP = p; @@ -2507,50 +2655,6 @@ fabric.CommonMethods = { }); } - /** - * Calculate bounding box of a elliptic-arc - * @deprecated - * @param {Number} fx start point of arc - * @param {Number} fy - * @param {Number} rx horizontal radius - * @param {Number} ry vertical radius - * @param {Number} rot angle of horizontal axis - * @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points - * @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction - * @param {Number} tx end point of arc - * @param {Number} ty - */ - function getBoundsOfArc(fx, fy, rx, ry, rot, large, sweep, tx, ty) { - - var fromX = 0, fromY = 0, bound, bounds = [], - segs = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot); - - for (var i = 0, len = segs.length; i < len; i++) { - bound = getBoundsOfCurve(fromX, fromY, segs[i][1], segs[i][2], segs[i][3], segs[i][4], segs[i][5], segs[i][6]); - bounds.push({ x: bound[0].x + fx, y: bound[0].y + fy }); - bounds.push({ x: bound[1].x + fx, y: bound[1].y + fy }); - fromX = segs[i][5]; - fromY = segs[i][6]; - } - return bounds; - }; - - /** - * Draws arc - * @deprecated - * @param {CanvasRenderingContext2D} ctx - * @param {Number} fx - * @param {Number} fy - * @param {Array} coords coords of the arc, without the front 'A/a' - */ - function drawArc(ctx, fx, fy, coords) { - coords = coords.slice(0).unshift('X'); // command A or a does not matter - var beziers = fromArcToBeziers(fx, fy, coords); - beziers.forEach(function(bezier) { - ctx.bezierCurveTo.apply(ctx, bezier.slice(1)); - }); - }; - /** * Join path commands to go back to svg format * @param {Array} pathData fabricJS parsed path commands @@ -2566,16 +2670,6 @@ fabric.CommonMethods = { fabric.util.getBoundsOfCurve = getBoundsOfCurve; fabric.util.getPointOnPath = getPointOnPath; fabric.util.transformPath = transformPath; - /** - * Typo of `fromArcToBeziers` kept for not breaking the api once corrected. - * Will be removed in fabric 5.0 - * @deprecated - */ - fabric.util.fromArcToBeizers = fromArcToBeziers; - // kept because we do not want to make breaking changes. - // but useless and deprecated. - fabric.util.getBoundsOfArc = getBoundsOfArc; - fabric.util.drawArc = drawArc; })(); @@ -3476,7 +3570,117 @@ fabric.log = console.log; fabric.warn = console.warn; -(function() { +(function () { + + var extend = fabric.util.object.extend, + clone = fabric.util.object.clone; + + /** + * @typedef {Object} AnimationOptions + * @property {Function} [options.onChange] Callback; invoked on every value change + * @property {Function} [options.onComplete] Callback; invoked when value change is completed + * @property {Number} [options.startValue=0] Starting value + * @property {Number} [options.endValue=100] Ending value + * @property {Number} [options.byValue=100] Value to modify the property by + * @property {Function} [options.easing] Easing function + * @property {Number} [options.duration=500] Duration of change (in ms) + * @property {Function} [options.abort] Additional function with logic. If returns true, animation aborts. + * + * @typedef {() => void} CancelFunction + * + * @typedef {Object} AnimationCurrentState + * @property {number} currentValue value in range [`startValue`, `endValue`] + * @property {number} completionRate value in range [0, 1] + * @property {number} durationRate value in range [0, 1] + * + * @typedef {(AnimationOptions & AnimationCurrentState & { cancel: CancelFunction }} AnimationContext + */ + + /** + * Array holding all running animations + * @memberof fabric + * @type {AnimationContext[]} + */ + var RUNNING_ANIMATIONS = []; + fabric.util.object.extend(RUNNING_ANIMATIONS, { + + /** + * cancel all running animations at the next requestAnimFrame + * @returns {AnimationContext[]} + */ + cancelAll: function () { + var animations = this.splice(0); + animations.forEach(function (animation) { + animation.cancel(); + }); + return animations; + }, + + /** + * cancel all running animations attached to canvas at the next requestAnimFrame + * @param {fabric.Canvas} canvas + * @returns {AnimationContext[]} + */ + cancelByCanvas: function (canvas) { + if (!canvas) { + return []; + } + var cancelled = this.filter(function (animation) { + return typeof animation.target === 'object' && animation.target.canvas === canvas; + }); + cancelled.forEach(function (animation) { + animation.cancel(); + }); + return cancelled; + }, + + /** + * cancel all running animations for target at the next requestAnimFrame + * @param {*} target + * @returns {AnimationContext[]} + */ + cancelByTarget: function (target) { + var cancelled = this.findAnimationsByTarget(target); + cancelled.forEach(function (animation) { + animation.cancel(); + }); + return cancelled; + }, + + /** + * + * @param {CancelFunction} cancelFunc the function returned by animate + * @returns {number} + */ + findAnimationIndex: function (cancelFunc) { + return this.indexOf(this.findAnimation(cancelFunc)); + }, + + /** + * + * @param {CancelFunction} cancelFunc the function returned by animate + * @returns {AnimationContext | undefined} animation's options object + */ + findAnimation: function (cancelFunc) { + return this.find(function (animation) { + return animation.cancel === cancelFunc; + }); + }, + + /** + * + * @param {*} target the object that is assigned to the target property of the animation context + * @returns {AnimationContext[]} array of animation options object associated with target + */ + findAnimationsByTarget: function (target) { + if (!target) { + return []; + } + return this.filter(function (animation) { + return animation.target === target; + }); + } + }); function noop() { return false; @@ -3489,22 +3693,30 @@ fabric.warn = console.warn; /** * Changes value from one to another within certain period of time, invoking callbacks as value is being changed. * @memberOf fabric.util - * @param {Object} [options] Animation options - * @param {Function} [options.onChange] Callback; invoked on every value change - * @param {Function} [options.onComplete] Callback; invoked when value change is completed - * @param {Number} [options.startValue=0] Starting value - * @param {Number} [options.endValue=100] Ending value - * @param {Number} [options.byValue=100] Value to modify the property by - * @param {Function} [options.easing] Easing function - * @param {Number} [options.duration=500] Duration of change (in ms) - * @param {Function} [options.abort] Additional function with logic. If returns true, onComplete is called. - * @returns {Function} abort function + * @param {AnimationOptions} [options] Animation options + * @returns {CancelFunction} cancel function */ function animate(options) { - var cancel = false; - requestAnimFrame(function(timestamp) { - options || (options = { }); + options || (options = {}); + var cancel = false, + context, + removeFromRegistry = function () { + var index = fabric.runningAnimations.indexOf(context); + return index > -1 && fabric.runningAnimations.splice(index, 1)[0]; + }; + + context = extend(clone(options), { + cancel: function () { + cancel = true; + return removeFromRegistry(); + }, + currentValue: 'startValue' in options ? options.startValue : 0, + completionRate: 0, + durationRate: 0 + }); + fabric.runningAnimations.push(context); + requestAnimFrame(function(timestamp) { var start = timestamp || +new Date(), duration = options.duration || 500, finish = start + duration, time, @@ -3519,25 +3731,31 @@ fabric.warn = console.warn; options.onStart && options.onStart(); (function tick(ticktime) { - // TODO: move abort call after calculation - // and pass (current,valuePerc, timePerc) as arguments time = ticktime || +new Date(); var currentTime = time > finish ? duration : (time - start), timePerc = currentTime / duration, current = easing(currentTime, startValue, byValue, duration), valuePerc = Math.abs((current - startValue) / byValue); + // update context + context.currentValue = current; + context.completionRate = valuePerc; + context.durationRate = timePerc; if (cancel) { return; } if (abort(current, valuePerc, timePerc)) { - // remove this in 4.0 - // does to even make sense to abort and run onComplete? - onComplete(endValue, 1, 1); + removeFromRegistry(); return; } if (time > finish) { + // update context + context.currentValue = endValue; + context.completionRate = 1; + context.durationRate = 1; + // execute callbacks onChange(endValue, 1, 1); onComplete(endValue, 1, 1); + removeFromRegistry(); return; } else { @@ -3546,9 +3764,8 @@ fabric.warn = console.warn; } })(start); }); - return function() { - cancel = true; - }; + + return context.cancel; } var _requestAnimFrame = fabric.window.requestAnimationFrame || @@ -3580,6 +3797,7 @@ fabric.warn = console.warn; fabric.util.animate = animate; fabric.util.requestAnimFrame = requestAnimFrame; fabric.util.cancelAnimFrame = cancelAnimFrame; + fabric.runningAnimations = RUNNING_ANIMATIONS; })(); @@ -5062,22 +5280,26 @@ fabric.warn = console.warn; if (styleContents.trim() === '') { continue; } - rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g); - rules = rules.map(function(rule) { return rule.trim(); }); + // recovers all the rule in this form `body { style code... }` + // rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g); + rules = styleContents.split('}'); + // remove empty rules. + rules = rules.filter(function(rule) { return rule.trim(); }); + // at this point we have hopefully an array of rules `body { style code... ` // eslint-disable-next-line no-loop-func rules.forEach(function(rule) { - var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/), - ruleObj = { }, declaration = match[2].trim(), - propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/); + var match = rule.split('{'), + ruleObj = { }, declaration = match[1].trim(), + propertyValuePairs = declaration.split(';').filter(function(pair) { return pair.trim(); }); for (i = 0, len = propertyValuePairs.length; i < len; i++) { - var pair = propertyValuePairs[i].split(/\s*:\s*/), - property = pair[0], - value = pair[1]; + var pair = propertyValuePairs[i].split(':'), + property = pair[0].trim(), + value = pair[1].trim(); ruleObj[property] = value; } - rule = match[1]; + rule = match[0].trim(); rule.split(',').forEach(function(_rule) { _rule = _rule.replace(/^svg/i, '').trim(); if (_rule === '') { @@ -8652,8 +8874,12 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp imageSmoothingEnabled: true, /** - * The transformation (in the format of Canvas transform) which focuses the viewport + * The transformation (a Canvas 2D API transform matrix) which focuses the viewport * @type Array + * @example Default transform + * canvas.viewportTransform = [1, 0, 0, 1, 0, 0]; + * @example Scale by 70% and translate toward bottom-right by 50, without skewing + * canvas.viewportTransform = [0.7, 0, 0, 0.7, 50, 50]; * @default */ viewportTransform: fabric.iMatrix.concat(), @@ -8747,7 +8973,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp * @private */ _isRetinaScaling: function() { - return (fabric.devicePixelRatio !== 1 && this.enableRetinaScaling); + return (fabric.devicePixelRatio > 1 && this.enableRetinaScaling); }, /** @@ -8755,7 +8981,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp * @return {Number} retinaScaling if applied, otherwise 1; */ getRetinaScaling: function() { - return this._isRetinaScaling() ? fabric.devicePixelRatio : 1; + return this._isRetinaScaling() ? Math.max(1, fabric.devicePixelRatio) : 1; }, /** @@ -9122,7 +9348,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp } } if (this._isCurrentlyDrawing) { - this.freeDrawingBrush && this.freeDrawingBrush._setBrushStyles(); + this.freeDrawingBrush && this.freeDrawingBrush._setBrushStyles(this.contextTop); } this._initRetinaScaling(); this.calcOffset(); @@ -9189,8 +9415,8 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp }, /** - * Sets viewport transform of this canvas instance - * @param {Array} vpt the transform in the form of context.transform + * Sets viewport transformation of this canvas instance + * @param {Array} vpt a Canvas 2D API transform matrix * @return {fabric.Canvas} instance * @chainable true */ @@ -10277,6 +10503,10 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp } this.forEachObject(function(object) { object.dispose && object.dispose(); + // animation module is still optional + if (fabric.runningAnimations) { + fabric.runningAnimations.cancelByTarget(object); + } }); this._objects = []; if (this.backgroundImage && this.backgroundImage.dispose) { @@ -10291,7 +10521,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp this.contextContainer = null; // restore canvas style this.lowerCanvasEl.classList.remove('lower-canvas'); - this.lowerCanvasEl.style = this._originalCanvasStyle; + fabric.util.setStyle(this.lowerCanvasEl, this._originalCanvasStyle); delete this._originalCanvasStyle; // restore canvas size to original size in case retina scaling was applied this.lowerCanvasEl.setAttribute('width', this.width); @@ -10459,9 +10689,9 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype /** * Sets brush styles * @private + * @param {CanvasRenderingContext2D} ctx */ - _setBrushStyles: function() { - var ctx = this.canvas.contextTop; + _setBrushStyles: function (ctx) { ctx.strokeStyle = this.color; ctx.lineWidth = this.width; ctx.lineCap = this.strokeLineCap; @@ -10546,6 +10776,22 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ decimate: 0.4, + /** + * Draws a straight line between last recorded point to current pointer + * Used for `shift` functionality + * + * @type boolean + * @default false + */ + drawStraightLine: false, + + /** + * The event modifier key that makes the brush draw a straight line. + * If `null` or 'none' or any other string that is not a modifier key the feature is disabled. + * @type {'altKey' | 'shiftKey' | 'ctrlKey' | 'none' | undefined | null} + */ + straightLineKey: 'shiftKey', + /** * Constructor * @param {fabric.Canvas} canvas @@ -10556,6 +10802,10 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype this._points = []; }, + needsFullRender: function () { + return this.callSuper('needsFullRender') || this._hasStraightLine; + }, + /** * Invoked inside on mouse down and mouse move * @param {Object} pointer @@ -10574,6 +10824,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype if (!this.canvas._isMainEvent(options.e)) { return; } + this.drawStraightLine = options.e[this.straightLineKey]; this._prepareForDrawing(pointer); // capture coordinates immediately // this allows to draw dots (when movement never occurs) @@ -10589,6 +10840,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype if (!this.canvas._isMainEvent(options.e)) { return; } + this.drawStraightLine = options.e[this.straightLineKey]; if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) { return; } @@ -10621,6 +10873,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype if (!this.canvas._isMainEvent(options.e)) { return true; } + this.drawStraightLine = false; this.oldEnd = undefined; this._finalizeAndAddPath(); return false; @@ -10647,6 +10900,10 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) { return false; } + if (this.drawStraightLine && this._points.length > 1) { + this._hasStraightLine = true; + this._points.pop(); + } this._points.push(point); return true; }, @@ -10657,8 +10914,9 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ _reset: function() { this._points = []; - this._setBrushStyles(); + this._setBrushStyles(this.canvas.contextTop); this._setShadow(); + this._hasStraightLine = false; }, /** @@ -10673,12 +10931,13 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype /** * Draw a smooth path on the topCanvas using quadraticCurveTo * @private + * @param {CanvasRenderingContext2D} [ctx] */ - _render: function() { - var ctx = this.canvas.contextTop, i, len, + _render: function(ctx) { + var i, len, p1 = this._points[0], p2 = this._points[1]; - + ctx = ctx || this.canvas.contextTop; this._saveAndTransform(ctx); ctx.beginPath(); //if we only have 2 points in the path and they are the same @@ -11212,17 +11471,19 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab /** * Creates "pattern" instance property + * @param {CanvasRenderingContext2D} ctx */ - getPattern: function() { - return this.canvas.contextTop.createPattern(this.source || this.getPatternSrc(), 'repeat'); + getPattern: function(ctx) { + return ctx.createPattern(this.source || this.getPatternSrc(), 'repeat'); }, /** * Sets brush styles + * @param {CanvasRenderingContext2D} ctx */ - _setBrushStyles: function() { - this.callSuper('_setBrushStyles'); - this.canvas.contextTop.strokeStyle = this.getPattern(); + _setBrushStyles: function(ctx) { + this.callSuper('_setBrushStyles', ctx); + ctx.strokeStyle = this.getPattern(ctx); }, /** @@ -11281,15 +11542,11 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab * @fires dragover * @fires dragenter * @fires dragleave + * @fires drop:before before drop event. same native event. This is added to handle edge cases * @fires drop * @fires after:render at the end of the render process, receives the context in the callback * @fires before:render at start the render process, receives the context in the callback * - * the following events are deprecated: - * @fires object:rotated at the end of a rotation transform - * @fires object:scaled at the end of a scale transform - * @fires object:moved at the end of translation transform - * @fires object:skewed at the end of a skew transform */ fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ { @@ -11474,13 +11731,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab */ freeDrawingCursor: 'crosshair', - /** - * Cursor value used for rotation point - * @type String - * @default - */ - rotationCursor: 'crosshair', - /** * Cursor value used for disabled elements ( corners with disabled action ) * @type String @@ -11586,6 +11836,13 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab */ targets: [], + /** + * When the option is enabled, PointerEvent is used instead of MouseEvent. + * @type Boolean + * @default + */ + enablePointerEvents: false, + /** * Keep track of the hovered target * @type fabric.Object @@ -11661,6 +11918,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab } if (this.hasLostContext) { this.renderTopLayer(this.contextTop); + this.hasLostContext = false; } var canvasToDrawOn = this.contextContainer; this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender()); @@ -12330,17 +12588,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab e: e, selected: added, deselected: removed, - // added for backward compatibility - // deprecated - updated: added[0] || removed[0], - target: this._activeObject, }); } else if (objects.length > 0) { this.fire('selection:created', { e: e, selected: added, - target: this._activeObject, }); } else if (oldObjects.length > 0) { @@ -12664,7 +12917,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab this._onDragOver = this._onDragOver.bind(this); this._onDragEnter = this._simpleEventHandler.bind(this, 'dragenter'); this._onDragLeave = this._simpleEventHandler.bind(this, 'dragleave'); - this._onDrop = this._simpleEventHandler.bind(this, 'drop'); + this._onDrop = this._onDrop.bind(this); this.eventsBound = true; }, @@ -12776,6 +13029,18 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab this._fireEnterLeaveEvents(target, e); }, + /** + * `drop:before` is a an event that allow you to schedule logic + * before the `drop` event. Prefer `drop` event always, but if you need + * to run some drop-disabling logic on an event, since there is no way + * to handle event handlers ordering, use `drop:before` + * @param {Event} e + */ + _onDrop: function (e) { + this._simpleEventHandler('drop:before', e); + return this._simpleEventHandler('drop', e); + }, + /** * @private * @param {Event} e Event object fired on mousedown @@ -13008,25 +13273,34 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab ); } } + var corner, pointer; if (target) { + corner = target._findTargetCorner( + this.getPointer(e, true), + fabric.util.isTouchEvent(e) + ); if (target.selectable && target !== this._activeObject && target.activeOn === 'up') { this.setActiveObject(target, e); shouldRender = true; } else { - var corner = target._findTargetCorner( - this.getPointer(e, true), - fabric.util.isTouchEvent(e) - ); var control = target.controls[corner], mouseUpHandler = control && control.getMouseUpHandler(e, target, control); if (mouseUpHandler) { - var pointer = this.getPointer(e); + pointer = this.getPointer(e); mouseUpHandler(e, transform, pointer.x, pointer.y); } } target.isMoving = false; } + // if we are ending up a transform on a different control or a new object + // fire the original mouse up from the corner that started the transform + if (transform && (transform.target !== target || transform.corner !== corner)) { + var originalControl = transform.target && transform.target.controls[transform.corner], + originalMouseUpHandler = originalControl && originalControl.getMouseUpHandler(e, target, control); + pointer = pointer || this.getPointer(e); + originalMouseUpHandler && originalMouseUpHandler(e, transform, pointer.x, pointer.y); + } this._setCursorFromEvent(e, target); this._handleEvent(e, 'up', LEFT_CLICK, isClick); this._groupSelector = null; @@ -13108,7 +13382,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab var transform = this._currentTransform, target = transform.target, - eventName, options = { e: e, target: target, @@ -13123,59 +13396,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab target.setCoords(); if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) { - if (transform.actionPerformed) { - // this is not friendly to the new control api. - // is deprecated. - eventName = this._addEventOptions(options, transform); - this._fire(eventName, options); - } this._fire('modified', options); } }, - /** - * Mutate option object in order to add by property and give back the event name. - * @private - * @deprecated since 4.2.0 - * @param {Object} options to mutate - * @param {Object} transform to inspect action from - */ - _addEventOptions: function(options, transform) { - // we can probably add more details at low cost - // scale change, rotation changes, translation changes - var eventName, by; - switch (transform.action) { - case 'scaleX': - eventName = 'scaled'; - by = 'x'; - break; - case 'scaleY': - eventName = 'scaled'; - by = 'y'; - break; - case 'skewX': - eventName = 'skewed'; - by = 'x'; - break; - case 'skewY': - eventName = 'skewed'; - by = 'y'; - break; - case 'scale': - eventName = 'scaled'; - by = 'equally'; - break; - case 'rotate': - eventName = 'rotated'; - break; - case 'drag': - eventName = 'moved'; - break; - } - options.by = by; - return eventName; - }, - /** * @private * @param {Event} e Event object fired on mousedown @@ -14615,6 +14839,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati /** * When `false`, the stoke width will scale with the object. * When `true`, the stroke will always match the exact pixel size entered for stroke width. + * this Property does not work on Text classes or drawing call that uses strokeText,fillText methods * default to false * @since 2.6.0 * @type Boolean @@ -15265,26 +15490,26 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati /** * Execute the drawing operation for an object clipPath * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {fabric.Object} clipPath */ - drawClipPathOnCache: function(ctx) { - var path = this.clipPath; + drawClipPathOnCache: function(ctx, clipPath) { ctx.save(); // DEBUG: uncomment this line, comment the following // ctx.globalAlpha = 0.4 - if (path.inverted) { + if (clipPath.inverted) { ctx.globalCompositeOperation = 'destination-out'; } else { ctx.globalCompositeOperation = 'destination-in'; } //ctx.scale(1 / 2, 1 / 2); - if (path.absolutePositioned) { + if (clipPath.absolutePositioned) { var m = fabric.util.invertTransform(this.calcTransformMatrix()); ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]); } - path.transform(ctx); - ctx.scale(1 / path.zoomX, 1 / path.zoomY); - ctx.drawImage(path._cacheCanvas, -path.cacheTranslationX, -path.cacheTranslationY); + clipPath.transform(ctx); + ctx.scale(1 / clipPath.zoomX, 1 / clipPath.zoomY); + ctx.drawImage(clipPath._cacheCanvas, -clipPath.cacheTranslationX, -clipPath.cacheTranslationY); ctx.restore(); }, @@ -15303,22 +15528,26 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati this._renderBackground(ctx); } this._render(ctx); - this._drawClipPath(ctx); + this._drawClipPath(ctx, this.clipPath); this.fill = originalFill; this.stroke = originalStroke; }, - _drawClipPath: function(ctx) { - var path = this.clipPath; - if (!path) { return; } + /** + * Prepare clipPath state and cache and draw it on instance's cache + * @param {CanvasRenderingContext2D} ctx + * @param {fabric.Object} clipPath + */ + _drawClipPath: function (ctx, clipPath) { + if (!clipPath) { return; } // needed to setup a couple of variables // path canvas gets overridden with this one. // TODO find a better solution? - path.canvas = this.canvas; - path.shouldCache(); - path._transformDone = true; - path.renderCache({ forClipping: true }); - this.drawClipPathOnCache(ctx); + clipPath.canvas = this.canvas; + clipPath.shouldCache(); + clipPath._transformDone = true; + clipPath.renderCache({ forClipping: true }); + this.drawClipPathOnCache(ctx, clipPath); }, /** @@ -15462,6 +15691,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati /** * Renders controls and borders for the object + * the context here is not transformed * @param {CanvasRenderingContext2D} ctx Context to render on * @param {Object} [styleOverride] properties to override the object style */ @@ -15480,7 +15710,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati if (!this.group) { ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1; } - ctx.rotate(degreesToRadians(options.angle)); + if (this.flipX) { + options.angle -= 180; + } + ctx.rotate(degreesToRadians(this.group ? options.angle : this.angle)); if (styleOverride.forActiveSelection || this.group) { drawBorders && this.drawBordersInGroup(ctx, options, styleOverride); } @@ -16016,6 +16249,15 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati if (this.globalCompositeOperation) { ctx.globalCompositeOperation = this.globalCompositeOperation; } + }, + + /** + * cancel instance's running animations + */ + dispose: function () { + if (fabric.runningAnimations) { + fabric.runningAnimations.cancelByTarget(this); + } } }); @@ -16033,6 +16275,15 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati */ fabric.Object.NUM_FRACTION_DIGITS = 2; + /** + * Defines which properties should be enlivened from the object passed to {@link fabric.Object._fromObject} + * @static + * @memberOf fabric.Object + * @constant + * @type string[] + */ + fabric.Object.ENLIVEN_PROPS = ['clipPath']; + fabric.Object._fromObject = function(className, object, callback, extraParam) { var klass = fabric[className]; object = clone(object, true); @@ -16043,8 +16294,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati if (typeof patterns[1] !== 'undefined') { object.stroke = patterns[1]; } - fabric.util.enlivenObjects([object.clipPath], function(enlivedProps) { - object.clipPath = enlivedProps[0]; + fabric.util.enlivenObjectEnlivables(object, object, function () { var instance = extraParam ? new klass(object[extraParam], object) : new klass(object); callback && callback(instance); }); @@ -16365,7 +16615,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati /** * Describe object's corner position in canvas element coordinates. * includes padding. Used of object detection. - * set and refreshed with setCoords and calcCoords. + * set and refreshed with setCoords. * @memberOf fabric.Object.prototype */ lineCoords: null, @@ -16749,21 +16999,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati return this.scale(value / this.height / boundingRectFactor); }, - /** - * Calculates and returns the .coords of an object. - * unused by the library, only for the end dev. - * @return {Object} Object with tl, tr, br, bl .... - * @chainable - * @deprecated - */ - calcCoords: function(absolute) { - // this is a compatibility function to avoid removing calcCoords now. - if (absolute) { - return this.calcACoords(); - } - return this.calcOCoords(); - }, - calcLineCoords: function() { var vpt = this.getViewportTransform(), padding = this.padding, angle = degreesToRadians(this.angle), @@ -16838,7 +17073,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * oCoords are used to find the corners * aCoords are used to quickly find an object on the canvas * lineCoords are used to quickly find object during pointer events. - * See {@link https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords|When-to-call-setCoords} + * See {@link https://github.com/fabricjs/fabric.js/wiki/When-to-call-setCoords} and {@link http://fabricjs.com/fabric-gotchas} + * * @param {Boolean} [skipCorners] skip calculation of oCoords. * @return {fabric.Object} thisArg * @chainable @@ -16935,23 +17171,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati return cache.value; }, - /* - * Calculate object dimensions from its properties - * @private - * @deprecated since 3.4.0, please use fabric.util._calcDimensionsTransformMatrix - * not including or including flipX, flipY to emulate the flipping boolean - * @return {Object} .x width dimension - * @return {Object} .y height dimension - */ - _calcDimensionsTransformMatrix: function(skewX, skewY, flipping) { - return util.calcDimensionsMatrix({ - skewX: skewX, - skewY: skewY, - scaleX: this.scaleX * (flipping && this.flipX ? -1 : 1), - scaleY: this.scaleY * (flipping && this.flipY ? -1 : 1) - }); - }, - /* * Calculate object dimensions from its properties * @private @@ -17816,8 +18035,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties * @param {Function} [callbacks.onComplete] Invoked on completion * @param {Function} [callbacks.onChange] Invoked on every step of animation - * @return {fabric.Canvas} thisArg - * @chainable + * @return {fabric.AnimationContext} context */ fxCenterObjectH: function (object, callbacks) { callbacks = callbacks || { }; @@ -17827,7 +18045,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati onChange = callbacks.onChange || empty, _this = this; - fabric.util.animate({ + return fabric.util.animate({ + target: this, startValue: object.left, endValue: this.getCenter().left, duration: this.FX_DURATION, @@ -17841,8 +18060,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati onComplete(); } }); - - return this; }, /** @@ -17851,8 +18068,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties * @param {Function} [callbacks.onComplete] Invoked on completion * @param {Function} [callbacks.onChange] Invoked on every step of animation - * @return {fabric.Canvas} thisArg - * @chainable + * @return {fabric.AnimationContext} context */ fxCenterObjectV: function (object, callbacks) { callbacks = callbacks || { }; @@ -17862,7 +18078,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati onChange = callbacks.onChange || empty, _this = this; - fabric.util.animate({ + return fabric.util.animate({ + target: this, startValue: object.top, endValue: this.getCenter().top, duration: this.FX_DURATION, @@ -17876,8 +18093,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati onComplete(); } }); - - return this; }, /** @@ -17886,8 +18101,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties * @param {Function} [callbacks.onComplete] Invoked on completion * @param {Function} [callbacks.onChange] Invoked on every step of animation - * @return {fabric.Canvas} thisArg - * @chainable + * @return {fabric.AnimationContext} context */ fxRemove: function (object, callbacks) { callbacks = callbacks || { }; @@ -17897,7 +18111,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati onChange = callbacks.onChange || empty, _this = this; - fabric.util.animate({ + return fabric.util.animate({ + target: this, startValue: object.opacity, endValue: 0, duration: this.FX_DURATION, @@ -17911,8 +18126,6 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati onComplete(); } }); - - return this; } }); @@ -17923,7 +18136,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @param {Number|Object} value Value to animate property to (if string was given first) or options object * @return {fabric.Object} thisArg * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation} - * @chainable + * @return {fabric.AnimationContext | fabric.AnimationContext[]} animation context (or an array if passed multiple properties) * * As object — multiple properties * @@ -17936,22 +18149,22 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * object.animate('left', { duration: ... }); * */ - animate: function() { + animate: function () { if (arguments[0] && typeof arguments[0] === 'object') { - var propsToAnimate = [], prop, skipCallbacks; + var propsToAnimate = [], prop, skipCallbacks, out = []; for (prop in arguments[0]) { propsToAnimate.push(prop); } for (var i = 0, len = propsToAnimate.length; i < len; i++) { prop = propsToAnimate[i]; skipCallbacks = i !== len - 1; - this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks); + out.push(this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks)); } + return out; } else { - this._animate.apply(this, arguments); + return this._animate.apply(this, arguments); } - return this; }, /** @@ -17999,6 +18212,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot } var _options = { + target: this, startValue: options.from, endValue: to, byValue: options.by, @@ -18370,7 +18584,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot 'use strict'; var fabric = global.fabric || (global.fabric = { }), - pi = Math.PI; + degreesToRadians = fabric.util.degreesToRadians; if (fabric.Circle) { fabric.warn('fabric.Circle is already defined.'); @@ -18400,22 +18614,20 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot radius: 0, /** - * Start angle of the circle, moving clockwise - * deprecated type, this should be in degree, this was an oversight. + * degrees of start of the circle. * probably will change to degrees in next major version - * @type Number + * @type Number 0 - 359 * @default 0 */ startAngle: 0, /** * End angle of the circle - * deprecated type, this should be in degree, this was an oversight. * probably will change to degrees in next major version - * @type Number - * @default 2Pi + * @type Number 1 - 360 + * @default 360 */ - endAngle: pi * 2, + endAngle: 360, cacheProperties: fabric.Object.prototype.cacheProperties.concat('radius', 'startAngle', 'endAngle'), @@ -18453,7 +18665,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ _toSVG: function() { var svgString, x = 0, y = 0, - angle = (this.endAngle - this.startAngle) % ( 2 * pi); + angle = (this.endAngle - this.startAngle) % 360; if (angle === 0) { svgString = [ @@ -18464,14 +18676,17 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot ]; } else { - var startX = fabric.util.cos(this.startAngle) * this.radius, - startY = fabric.util.sin(this.startAngle) * this.radius, - endX = fabric.util.cos(this.endAngle) * this.radius, - endY = fabric.util.sin(this.endAngle) * this.radius, - largeFlag = angle > pi ? '1' : '0'; + var start = degreesToRadians(this.startAngle), + end = degreesToRadians(this.endAngle), + radius = this.radius, + startX = fabric.util.cos(start) * radius, + startY = fabric.util.sin(start) * radius, + endX = fabric.util.cos(end) * radius, + endY = fabric.util.sin(end) * radius, + largeFlag = angle > 180 ? '1' : '0'; svgString = [ '\n' ]; @@ -18490,8 +18705,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot 0, 0, this.radius, - this.startAngle, - this.endAngle, false); + degreesToRadians(this.startAngle), + degreesToRadians(this.endAngle), + false + ); this._renderPaintInOrder(ctx); }, @@ -19049,7 +19266,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot extend = fabric.util.object.extend, min = fabric.util.array.min, max = fabric.util.array.max, - toFixed = fabric.util.toFixed; + toFixed = fabric.util.toFixed, + projectStrokeOnPoints = fabric.util.projectStrokeOnPoints; if (fabric.Polyline) { fabric.warn('fabric.Polyline is already defined'); @@ -19078,6 +19296,17 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ points: null, + /** + * WARNING: Feature in progress + * Calculate the exact bounding box taking in account strokeWidth on acute angles + * this will be turned to true by default on fabric 6.0 + * maybe will be left in as an optimization since calculations may be slow + * @deprecated + * @type Boolean + * @default false + */ + exactBoundingBox: false, + cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'), /** @@ -19106,13 +19335,25 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot this._setPositionDimensions(options); }, + /** + * @private + */ + _projectStrokeOnPoints: function () { + return projectStrokeOnPoints(this.points, this, true); + }, + _setPositionDimensions: function(options) { - var calcDim = this._calcDimensions(options), correctLeftTop; - this.width = calcDim.width; - this.height = calcDim.height; + var calcDim = this._calcDimensions(options), correctLeftTop, + correctSize = this.exactBoundingBox ? this.strokeWidth : 0; + this.width = calcDim.width - correctSize; + this.height = calcDim.height - correctSize; if (!options.fromSVG) { correctLeftTop = this.translateToGivenOrigin( - { x: calcDim.left - this.strokeWidth / 2, y: calcDim.top - this.strokeWidth / 2 }, + { + // this looks bad, but is one way to keep it optional for now. + x: calcDim.left - this.strokeWidth / 2 + correctSize / 2, + y: calcDim.top - this.strokeWidth / 2 + correctSize / 2 + }, 'left', 'top', this.originX, @@ -19126,8 +19367,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot this.top = options.fromSVG ? calcDim.top : correctLeftTop.y; } this.pathOffset = { - x: calcDim.left + this.width / 2, - y: calcDim.top + this.height / 2 + x: calcDim.left + this.width / 2 + correctSize / 2, + y: calcDim.top + this.height / 2 + correctSize / 2 }; }, @@ -19143,7 +19384,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ _calcDimensions: function() { - var points = this.points, + var points = this.exactBoundingBox ? this._projectStrokeOnPoints() : this.points, minX = min(points, 'x') || 0, minY = min(points, 'y') || 0, maxX = max(points, 'x') || 0, @@ -19155,7 +19396,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot left: minX, top: minY, width: width, - height: height + height: height, }; }, @@ -19291,7 +19532,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot 'use strict'; - var fabric = global.fabric || (global.fabric = { }); + var fabric = global.fabric || (global.fabric = {}), + projectStrokeOnPoints = fabric.util.projectStrokeOnPoints; if (fabric.Polygon) { fabric.warn('fabric.Polygon is already defined'); @@ -19313,6 +19555,13 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ type: 'polygon', + /** + * @private + */ + _projectStrokeOnPoints: function () { + return projectStrokeOnPoints(this.points, this); + }, + /** * @private * @param {CanvasRenderingContext2D} ctx Context to render on @@ -19370,6 +19619,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot min = fabric.util.array.min, max = fabric.util.array.max, extend = fabric.util.object.extend, + clone = fabric.util.object.clone, _toString = Object.prototype.toString, toFixed = fabric.util.toFixed; @@ -19411,23 +19661,26 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @param {Object} [options] Options object * @return {fabric.Path} thisArg */ - initialize: function(path, options) { - options = options || { }; + initialize: function (path, options) { + options = clone(options || {}); + delete options.path; this.callSuper('initialize', options); - if (!path) { - path = []; - } + this._setPath(path || [], options); + }, + /** + * @private + * @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens) + * @param {Object} [options] Options object + */ + _setPath: function (path, options) { var fromArray = _toString.call(path) === '[object Array]'; this.path = fabric.util.makePathSimpler( fromArray ? path : fabric.util.parsePath(path) ); - if (!this.path) { - return; - } - fabric.Polyline.prototype._setPositionDimensions.call(this, options); + fabric.Polyline.prototype._setPositionDimensions.call(this, options || {}); }, /** @@ -20084,7 +20337,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot for (var i = 0, len = this._objects.length; i < len; i++) { this._objects[i].render(ctx); } - this._drawClipPath(ctx); + this._drawClipPath(ctx, this.clipPath); }, /** @@ -20130,25 +20383,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot return this; }, - /** - * Realises the transform from this group onto the supplied object - * i.e. it tells you what would happen if the supplied object was in - * the group, and then the group was destroyed. It mutates the supplied - * object. - * Warning: this method is not useful anymore, it has been kept to no break the api. - * is not used in the fabricJS codebase - * this method will be reduced to using the utility. - * @private - * @deprecated - * @param {fabric.Object} object - * @param {Array} parentMatrix parent transformation - * @return {fabric.Object} transformedObject - */ - realizeTransform: function(object, parentMatrix) { - fabric.util.addTransformToObject(object, parentMatrix); - return object; - }, - /** * Destroys a group (restoring state of its objects) * @return {fabric.Group} thisArg @@ -20163,6 +20397,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot return this._restoreObjectsState(); }, + dispose: function () { + this.callSuper('dispose'); + this.forEachObject(function (object) { + object.dispose && object.dispose(); + }); + this._objects = []; + }, + /** * make a group an active selection, remove the group from canvas * the group has to be on canvas for this to work. @@ -20326,11 +20568,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot }); return; } - fabric.util.enlivenObjects(objects, function(enlivenedObjects) { - fabric.util.enlivenObjects([object.clipPath], function(enlivedClipPath) { - var options = fabric.util.object.clone(object, true); - options.clipPath = enlivedClipPath[0]; - delete options.objects; + fabric.util.enlivenObjects(objects, function (enlivenedObjects) { + var options = fabric.util.object.clone(object, true); + delete options.objects; + fabric.util.enlivenObjectEnlivables(object, options, function () { callback && callback(new fabric.Group(enlivenedObjects, options, true)); }); }); @@ -20700,7 +20941,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot /** * Delete textures, reference to elements and eventually JSDOM cleanup */ - dispose: function() { + dispose: function () { + this.callSuper('dispose'); this.removeTexture(this.cacheKey); this.removeTexture(this.cacheKey + '_filtered'); this._cacheContext = undefined; @@ -21210,8 +21452,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot object.filters = filters || []; fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) { object.resizeFilter = resizeFilters[0]; - fabric.util.enlivenObjects([object.clipPath], function(enlivedProps) { - object.clipPath = enlivedProps[0]; + fabric.util.enlivenObjectEnlivables(object, object, function () { var image = new fabric.Image(img, object); callback(image, false); }); @@ -21282,8 +21523,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @chainable */ straighten: function() { - this.rotate(this._getAngleValueForStraighten()); - return this; + return this.rotate(this._getAngleValueForStraighten()); }, /** @@ -21292,7 +21532,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @param {Function} [callbacks.onComplete] Invoked on completion * @param {Function} [callbacks.onChange] Invoked on every step of animation * @return {fabric.Object} thisArg - * @chainable */ fxStraighten: function(callbacks) { callbacks = callbacks || { }; @@ -21302,7 +21541,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot onChange = callbacks.onChange || empty, _this = this; - fabric.util.animate({ + return fabric.util.animate({ + target: this, startValue: this.get('angle'), endValue: this._getAngleValueForStraighten(), duration: this.FX_DURATION, @@ -21315,8 +21555,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot onComplete(); }, }); - - return this; } }); @@ -21338,13 +21576,11 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated * @param {fabric.Object} object Object to straighten * @return {fabric.Canvas} thisArg - * @chainable */ fxStraightenObject: function (object) { - object.fxStraighten({ + return object.fxStraighten({ onChange: this.requestRenderAllBound }); - return this; } }); @@ -25511,7 +25747,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { var additionalProps = ('fontFamily fontWeight fontSize text underline overline linethrough' + ' textAlign fontStyle lineHeight textBackgroundColor charSpacing styles' + - ' direction path pathStartOffset pathSide').split(' '); + ' direction path pathStartOffset pathSide pathAlign').split(' '); /** * Text class @@ -25540,7 +25776,8 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { 'styles', 'path', 'pathStartOffset', - 'pathSide' + 'pathSide', + 'pathAlign' ], /** @@ -25737,6 +25974,16 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { */ pathSide: 'left', + /** + * How text is aligned to the path. This property determines + * the perpendicular position of each character relative to the path. + * (one of "baseline", "center", "ascender", "descender") + * This feature is in BETA, and its behavior may change + * @type String + * @default + */ + pathAlign: 'baseline', + /** * @private */ @@ -25880,6 +26127,8 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { /** * Return a context for measurement of text string. * if created it gets stored for reuse + * this is for internal use, please do not use it + * @private * @param {String} text Text string * @param {Object} [options] Options object * @return {fabric.Text} thisArg @@ -26051,7 +26300,20 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { * @param {String} [charStyle.fontStyle] Font style (italic|normal) */ _setTextStyles: function(ctx, charStyle, forMeasuring) { - ctx.textBaseline = 'alphabetic'; + ctx.textBaseline = 'alphabetical'; + if (this.path) { + switch (this.pathAlign) { + case 'center': + ctx.textBaseline = 'middle'; + break; + case 'ascender': + ctx.textBaseline = 'top'; + break; + case 'descender': + ctx.textBaseline = 'bottom'; + break; + } + } ctx.font = this._getFontDeclaration(charStyle, forMeasuring); }, @@ -26516,16 +26778,17 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { path = this.path, shortCut = !isJustify && this.charSpacing === 0 && this.isEmptyStyles(lineIndex) && !path, isLtr = this.direction === 'ltr', sign = this.direction === 'ltr' ? 1 : -1, - drawingLeft; - + drawingLeft, currentDirection = ctx.canvas.getAttribute('dir'); ctx.save(); + if (currentDirection !== this.direction) { + ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl'); + ctx.direction = isLtr ? 'ltr' : 'rtl'; + ctx.textAlign = isLtr ? 'left' : 'right'; + } top -= lineHeight * this._fontSizeFraction / this.lineHeight; if (shortCut) { // render all the line in one pass without checking // drawingLeft = isLtr ? left : left - this.getLineWidth(lineIndex); - ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl'); - ctx.direction = isLtr ? 'ltr' : 'rtl'; - ctx.textAlign = isLtr ? 'left' : 'right'; this._renderChar(method, ctx, lineIndex, 0, line.join(''), left, top, lineHeight); ctx.restore(); return; @@ -26562,9 +26825,6 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { } else { drawingLeft = left; - ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl'); - ctx.direction = isLtr ? 'ltr' : 'rtl'; - ctx.textAlign = isLtr ? 'left' : 'right'; this._renderChar(method, ctx, lineIndex, i, charsToRender, drawingLeft, top, lineHeight); } charsToRender = ''; @@ -26815,19 +27075,12 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { * @return {Number} Line width */ getLineWidth: function(lineIndex) { - if (this.__lineWidths[lineIndex]) { + if (this.__lineWidths[lineIndex] !== undefined) { return this.__lineWidths[lineIndex]; } - var width, line = this._textLines[lineIndex], lineInfo; - - if (line === '') { - width = 0; - } - else { - lineInfo = this.measureLine(lineIndex); - width = lineInfo.width; - } + var lineInfo = this.measureLine(lineIndex); + var width = lineInfo.width; this.__lineWidths[lineIndex] = width; return width; }, @@ -28924,7 +29177,13 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { this.insertCharStyleObject(cursorLoc.lineIndex + i, 0, addedLines[i], copiedStyle); } else if (copiedStyle) { - this.styles[cursorLoc.lineIndex + i][0] = copiedStyle[0]; + // this test is required in order to close #6841 + // when a pasted buffer begins with a newline then + // this.styles[cursorLoc.lineIndex + i] and copiedStyle[0] + // may be undefined for some reason + if (this.styles[cursorLoc.lineIndex + i] && copiedStyle[0]) { + this.styles[cursorLoc.lineIndex + i][0] = copiedStyle[0]; + } } copiedStyle = copiedStyle && copiedStyle.slice(addedLines[i] + 1); } diff --git a/dist/fabric.min.js b/dist/fabric.min.js index 34c1ff02fd9..53e549826fc 100644 --- a/dist/fabric.min.js +++ b/dist/fabric.min.js @@ -1 +1 @@ -var jsdom,virtualWindow,fabric=fabric||{version:"4.6.0"};function resizeCanvasIfNeeded(t){var e=t.targetCanvas,i=e.width,r=e.height,n=t.destinationWidth,t=t.destinationHeight;i===n&&r===t||(e.width=n,e.height=t)}function copyGLTo2DDrawImage(t,e){var i=t.canvas,r=e.targetCanvas,t=r.getContext("2d");t.translate(0,r.height),t.scale(1,-1);e=i.height-r.height;t.drawImage(i,0,e,r.width,r.height,0,0,r.width,r.height)}function copyGLTo2DPutImageData(t,e){var i=e.targetCanvas.getContext("2d"),r=e.destinationWidth,n=e.destinationHeight,s=r*n*4,e=new Uint8Array(this.imageBuffer,0,s),s=new Uint8ClampedArray(this.imageBuffer,0,s);t.readPixels(0,0,r,n,t.RGBA,t.UNSIGNED_BYTE,e);n=new ImageData(s,r,n);i.putImageData(n,0,0)}"undefined"!=typeof exports?exports.fabric=fabric:"function"==typeof define&&define.amd&&define([],function(){return fabric}),"undefined"!=typeof document&&"undefined"!=typeof window?(document instanceof("undefined"!=typeof HTMLDocument?HTMLDocument:Document)?fabric.document=document:fabric.document=document.implementation.createHTMLDocument(""),fabric.window=window):(jsdom=require("jsdom"),virtualWindow=new jsdom.JSDOM(decodeURIComponent("%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E"),{features:{FetchExternalResources:["img"]},resources:"usable"}).window,fabric.document=virtualWindow.document,fabric.jsdomImplForWrapper=require("jsdom/lib/jsdom/living/generated/utils").implForWrapper,fabric.nodeCanvas=require("jsdom/lib/jsdom/utils").Canvas,fabric.window=virtualWindow,DOMParser=fabric.window.DOMParser),fabric.isTouchSupported="ontouchstart"in fabric.window||"ontouchstart"in fabric.document||fabric.window&&fabric.window.navigator&&0_)for(var C=1,S=v.length;Ct[i-2].x?1:s.x===t[i-2].x?0:-1,h=s.y>t[i-2].y?1:s.y===t[i-2].y?0:-1),n.push(["L",s.x+c*e,s.y+h*e]),n},fabric.util.getPathSegmentsInfo=l,fabric.util.getBoundsOfCurve=v,fabric.util.getPointOnPath=function(t,e,i){i=i||l(t);for(var r=0;0/g,">")},graphemeSplit:function(t){for(var e,i=0,r=[],i=0;it.x&&this.y>t.y},gte:function(t){return this.x>=t.x&&this.y>=t.y},lerp:function(t,e){return void 0===e&&(e=.5),e=Math.max(Math.min(1,e),0),new i(this.x+(t.x-this.x)*e,this.y+(t.y-this.y)*e)},distanceFrom:function(t){var e=this.x-t.x,t=this.y-t.y;return Math.sqrt(e*e+t*t)},midPointFrom:function(t){return this.lerp(t)},min:function(t){return new i(Math.min(this.x,t.x),Math.min(this.y,t.y))},max:function(t){return new i(Math.max(this.x,t.x),Math.max(this.y,t.y))},toString:function(){return this.x+","+this.y},setXY:function(t,e){return this.x=t,this.y=e,this},setX:function(t){return this.x=t,this},setY:function(t){return this.y=t,this},setFromPoint:function(t){return this.x=t.x,this.y=t.y,this},swap:function(t){var e=this.x,i=this.y;this.x=t.x,this.y=t.y,t.x=e,t.y=i},clone:function(){return new i(this.x,this.y)}}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var a=t.fabric||(t.fabric={});function c(t){this.status=t,this.points=[]}a.Intersection?a.warn("fabric.Intersection is already defined"):(a.Intersection=c,a.Intersection.prototype={constructor:c,appendPoint:function(t){return this.points.push(t),this},appendPoints:function(t){return this.points=this.points.concat(t),this}},a.Intersection.intersectLineLine=function(t,e,i,r){var n,s=(r.x-i.x)*(t.y-i.y)-(r.y-i.y)*(t.x-i.x),o=(e.x-t.x)*(t.y-i.y)-(e.y-t.y)*(t.x-i.x),r=(r.y-i.y)*(e.x-t.x)-(r.x-i.x)*(e.y-t.y);return 0!=r?(i=o/r,0<=(r=s/r)&&r<=1&&0<=i&&i<=1?(n=new c("Intersection")).appendPoint(new a.Point(t.x+r*(e.x-t.x),t.y+r*(e.y-t.y))):n=new c):n=new c(0==s||0==o?"Coincident":"Parallel"),n},a.Intersection.intersectLinePolygon=function(t,e,i){for(var r,n,s=new c,o=i.length,a=0;a=t&&(i.x-=t),i.x<=-t&&(i.x+=t),i.y>=t&&(i.y-=t),i.y<=t&&(i.y+=t),i.x-=o.offsetX,i.y-=o.offsetY,i}function w(t){return t.flipX!==t.flipY}function O(t,e,i,r,n){0!==t[e]&&(r=n/t._getTransformedDimensions()[r]*t[i],t.set(i,r))}function k(t,e,i,r){var n,s=e.target,o=s._getTransformedDimensions(0,s.skewY),i=T(e,e.originX,e.originY,i,r),r=Math.abs(2*i.x)-o.x,i=s.skewX;r<2?n=0:(n=g(Math.atan2(r/s.scaleX,o.y/s.scaleY)),e.originX===c&&e.originY===u&&(n=-n),e.originX===l&&e.originY===h&&(n=-n),w(s)&&(n=-n));e=i!==n;return e&&(i=s._getTransformedDimensions().y,s.set("skewX",n),O(s,"skewY","scaleY","y",i)),e}function P(t,e,i,r){var n,s=e.target,o=s._getTransformedDimensions(s.skewX,0),i=T(e,e.originX,e.originY,i,r),r=Math.abs(2*i.y)-o.y,i=s.skewY;r<2?n=0:(n=g(Math.atan2(r/s.scaleY,o.x/s.scaleX)),e.originX===c&&e.originY===u&&(n=-n),e.originX===l&&e.originY===h&&(n=-n),w(s)&&(n=-n));e=i!==n;return e&&(i=s._getTransformedDimensions().x,s.set("skewY",n),O(s,"skewX","scaleX","x",i)),e}function E(t,e,i,r,n){var s=e.target,o=s.lockScalingX,a=s.lockScalingY,c=(n=n||{}).by,h=b(t,s),n=_(s,c,h),t=e.gestureScale;if(n)return!1;if(t)l=e.scaleX*t,u=e.scaleY*t;else{if(n=T(e,e.originX,e.originY,i,r),t="y"!==c?p(n.x):1,f="x"!==c?p(n.y):1,e.signX||(e.signX=t),e.signY||(e.signY=f),s.lockScalingFlip&&(e.signX!==t||e.signY!==f))return!1;var l,u,i=s._getTransformedDimensions();u=h&&!c?(r=Math.abs(n.x)+Math.abs(n.y),h=e.original,r=r/(Math.abs(i.x*h.scaleX/s.scaleX)+Math.abs(i.y*h.scaleY/s.scaleY)),l=h.scaleX*r,h.scaleY*r):(l=Math.abs(n.x*s.scaleX/i.x),Math.abs(n.y*s.scaleY/i.y)),y(e)&&(l*=2,u*=2),e.signX!==t&&"y"!==c&&(e.originX=d[e.originX],l*=-1,e.signX=t),e.signY!==f&&"x"!==c&&(e.originY=d[e.originY],u*=-1,e.signY=f)}var e=s.scaleX,f=s.scaleY;return c?("x"===c&&s.set("scaleX",l),"y"===c&&s.set("scaleY",u)):(o||s.set("scaleX",l),a||s.set("scaleY",u)),e!==s.scaleX||f!==s.scaleY}o.scaleCursorStyleHandler=function(t,e,i){var r=b(t,i),t="";return 0!==e.x&&0===e.y?t="x":0===e.x&&0!==e.y&&(t="y"),_(i,t,r)?"not-allowed":(e=m(i,e),n[e]+"-resize")},o.skewCursorStyleHandler=function(t,e,i){var r="not-allowed";return 0!==e.x&&i.lockSkewingY||0!==e.y&&i.lockSkewingX?r:(e=m(i,e)%4,s[e]+"-resize")},o.scaleSkewCursorStyleHandler=function(t,e,i){return t[i.canvas.altActionKey]?o.skewCursorStyleHandler(t,e,i):o.scaleCursorStyleHandler(t,e,i)},o.rotationWithSnapping=S("rotating",C(function(t,e,i,r){var n=e,s=n.target,o=s.translateToOriginPoint(s.getCenterPoint(),n.originX,n.originY);return!s.lockRotation&&(e=Math.atan2(n.ey-o.y,n.ex-o.x),r=Math.atan2(r-o.y,i-o.x),i=g(r-e+n.theta),0r.r2,o=(this.gradientTransform||fabric.iMatrix).concat(),a=-this.offsetX,c=-this.offsetY,h=!!e.additionalTransform,l="pixels"===this.gradientUnits?"userSpaceOnUse":"objectBoundingBox";if(n.sort(function(t,e){return t.offset-e.offset}),"objectBoundingBox"==l?(a/=t.width,c/=t.height):(a+=t.width/2,c+=t.height/2),"path"===t.type&&"percentage"!==this.gradientUnits&&(a-=t.pathOffset.x,c-=t.pathOffset.y),o[4]-=a,o[5]-=c,l='id="SVGID_'+this.id+'" gradientUnits="'+l+'"',l+=' gradientTransform="'+(h?e.additionalTransform+" ":"")+fabric.util.matrixToSVG(o)+'" ',"linear"===this.type?i=["\n']:"radial"===this.type&&(i=["\n']),"radial"===this.type){if(s)for((n=n.concat()).reverse(),f=0,d=n.length;f\n')}return i.push("linear"===this.type?"\n":"\n"),i.join("")},toLive:function(t){var e,i,r,n=fabric.util.object.clone(this.coords);if(this.type){for("linear"===this.type?e=t.createLinearGradient(n.x1,n.y1,n.x2,n.y2):"radial"===this.type&&(e=t.createRadialGradient(n.x1,n.y1,n.r1,n.x2,n.y2,n.r2)),i=0,r=this.colorStops.length;i\n\n\n'},setOptions:function(t){for(var e in t)this[e]=t[e]},toLive:function(t){var e=this.source;if(!e)return"";if(void 0!==e.src){if(!e.complete)return"";if(0===e.naturalWidth||0===e.naturalHeight)return""}return t.createPattern(e,this.repeat)}})}(),function(t){"use strict";var o=t.fabric||(t.fabric={}),a=o.util.toFixed;o.Shadow?o.warn("fabric.Shadow is already defined."):(o.Shadow=o.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,nonScaling:!1,initialize:function(t){for(var e in t="string"==typeof t?this._parseShadow(t):t)this[e]=t[e];this.id=o.Object.__uid++},_parseShadow:function(t){var e=t.trim(),t=o.Shadow.reOffsetsAndBlur.exec(e)||[];return{color:(e.replace(o.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(),offsetX:parseFloat(t[1],10)||0,offsetY:parseFloat(t[2],10)||0,blur:parseFloat(t[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(t){var e=40,i=40,r=o.Object.NUM_FRACTION_DIGITS,n=o.util.rotateVector({x:this.offsetX,y:this.offsetY},o.util.degreesToRadians(-t.angle)),s=new o.Color(this.color);return t.width&&t.height&&(e=100*a((Math.abs(n.x)+this.blur)/t.width,r)+20,i=100*a((Math.abs(n.y)+this.blur)/t.height,r)+20),t.flipX&&(n.x*=-1),t.flipY&&(n.y*=-1),'\n\t\n\t\n\t\n\t\n\t\n\t\t\n\t\t\n\t\n\n'},toObject:function(){if(this.includeDefaultValues)return{color:this.color,blur:this.blur,offsetX:this.offsetX,offsetY:this.offsetY,affectStroke:this.affectStroke,nonScaling:this.nonScaling};var e={},i=o.Shadow.prototype;return["color","blur","offsetX","offsetY","affectStroke","nonScaling"].forEach(function(t){this[t]!==i[t]&&(e[t]=this[t])},this),e}}),o.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(\d+(?:\.\d*)?(?:px)?)?(?:\s?|$)(?:$|\s)/)}("undefined"!=typeof exports?exports:this),function(){"use strict";var n,t,h,a,s,o,i,r,e;fabric.StaticCanvas?fabric.warn("fabric.StaticCanvas is already defined."):(n=fabric.util.object.extend,t=fabric.util.getElementOffset,h=fabric.util.removeFromArray,a=fabric.util.toFixed,s=fabric.util.transformPoint,o=fabric.util.invertTransform,i=fabric.util.getNodeCanvas,r=fabric.util.createCanvasElement,e=new Error("Could not initialize `canvas` element"),fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(t,e){e=e||{},this.renderAndResetBound=this.renderAndReset.bind(this),this.requestRenderAllBound=this.requestRenderAll.bind(this),this._initStatic(t,e)},backgroundColor:"",backgroundImage:null,overlayColor:"",overlayImage:null,includeDefaultValues:!0,stateful:!1,renderOnAddRemove:!0,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,viewportTransform:fabric.iMatrix.concat(),backgroundVpt:!0,overlayVpt:!0,enableRetinaScaling:!0,vptCoords:{},skipOffscreen:!0,clipPath:void 0,_initStatic:function(t,e){var i=this.requestRenderAllBound;this._objects=[],this._createLowerCanvas(t),this._initOptions(e),this.interactive||this._initRetinaScaling(),e.overlayImage&&this.setOverlayImage(e.overlayImage,i),e.backgroundImage&&this.setBackgroundImage(e.backgroundImage,i),e.backgroundColor&&this.setBackgroundColor(e.backgroundColor,i),e.overlayColor&&this.setOverlayColor(e.overlayColor,i),this.calcOffset()},_isRetinaScaling:function(){return 1!==fabric.devicePixelRatio&&this.enableRetinaScaling},getRetinaScaling:function(){return this._isRetinaScaling()?fabric.devicePixelRatio:1},_initRetinaScaling:function(){var t;this._isRetinaScaling()&&(t=fabric.devicePixelRatio,this.__initRetinaScaling(t,this.lowerCanvasEl,this.contextContainer),this.upperCanvasEl&&this.__initRetinaScaling(t,this.upperCanvasEl,this.contextTop))},__initRetinaScaling:function(t,e,i){e.setAttribute("width",this.width*t),e.setAttribute("height",this.height*t),i.scale(t,t)},calcOffset:function(){return this._offset=t(this.lowerCanvasEl),this},setOverlayImage:function(t,e,i){return this.__setBgOverlayImage("overlayImage",t,e,i)},setBackgroundImage:function(t,e,i){return this.__setBgOverlayImage("backgroundImage",t,e,i)},setOverlayColor:function(t,e){return this.__setBgOverlayColor("overlayColor",t,e)},setBackgroundColor:function(t,e){return this.__setBgOverlayColor("backgroundColor",t,e)},__setBgOverlayImage:function(r,t,n,s){return"string"==typeof t?fabric.util.loadImage(t,function(t,e){var i;t&&(i=new fabric.Image(t,s),(this[r]=i).canvas=this),n&&n(t,e)},this,s&&s.crossOrigin):(s&&t.setOptions(s),(this[r]=t)&&(t.canvas=this),n&&n(t,!1)),this},__setBgOverlayColor:function(t,e,i){return this[t]=e,this._initGradient(e,t),this._initPattern(e,t,i),this},_createCanvasElement:function(){var t=r();if(!t)throw e;if(t.style||(t.style={}),void 0===t.getContext)throw e;return t},_initOptions:function(t){var e=this.lowerCanvasEl;this._setOptions(t),this.width=this.width||parseInt(e.width,10)||0,this.height=this.height||parseInt(e.height,10)||0,this.lowerCanvasEl.style&&(e.width=this.width,e.height=this.height,e.style.width=this.width+"px",e.style.height=this.height+"px",this.viewportTransform=this.viewportTransform.slice())},_createLowerCanvas:function(t){t&&t.getContext?this.lowerCanvasEl=t:this.lowerCanvasEl=fabric.util.getById(t)||this._createCanvasElement(),fabric.util.addClass(this.lowerCanvasEl,"lower-canvas"),this._originalCanvasStyle=this.lowerCanvasEl.style,this.interactive&&this._applyCanvasStyle(this.lowerCanvasEl),this.contextContainer=this.lowerCanvasEl.getContext("2d")},getWidth:function(){return this.width},getHeight:function(){return this.height},setWidth:function(t,e){return this.setDimensions({width:t},e)},setHeight:function(t,e){return this.setDimensions({height:t},e)},setDimensions:function(t,e){var i,r;for(r in e=e||{},t)i=t[r],e.cssOnly||(this._setBackstoreDimension(r,t[r]),i+="px",this.hasLostContext=!0),e.backstoreOnly||this._setCssDimension(r,i);return this._isCurrentlyDrawing&&this.freeDrawingBrush&&this.freeDrawingBrush._setBrushStyles(),this._initRetinaScaling(),this.calcOffset(),e.cssOnly||this.requestRenderAll(),this},_setBackstoreDimension:function(t,e){return this.lowerCanvasEl[t]=e,this.upperCanvasEl&&(this.upperCanvasEl[t]=e),this.cacheCanvasEl&&(this.cacheCanvasEl[t]=e),this[t]=e,this},_setCssDimension:function(t,e){return this.lowerCanvasEl.style[t]=e,this.upperCanvasEl&&(this.upperCanvasEl.style[t]=e),this.wrapperEl&&(this.wrapperEl.style[t]=e),this},getZoom:function(){return this.viewportTransform[0]},setViewportTransform:function(t){var e,i,r,n=this._activeObject,s=this.backgroundImage,o=this.overlayImage;for(this.viewportTransform=t,i=0,r=this._objects.length;i\n'),this._setSVGBgOverlayColor(i,"background"),this._setSVGBgOverlayImage(i,"backgroundImage",e),this._setSVGObjects(i,e),this.clipPath&&i.push("\n"),this._setSVGBgOverlayColor(i,"overlay"),this._setSVGBgOverlayImage(i,"overlayImage",e),i.push(""),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,r=e.width||this.width,n=e.height||this.height,s='viewBox="0 0 '+this.width+" "+this.height+'" ',o=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?s='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,s='viewBox="'+a(-i[4]/i[0],o)+" "+a(-i[5]/i[3],o)+" "+a(this.width/i[0],o)+" "+a(this.height/i[3],o)+'" '),t.push("\n',"Created with Fabric.js ",fabric.version,"\n","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),this.createSVGClipPathMarkup(e),"\n")},createSVGClipPathMarkup:function(t){var e=this.clipPath;return e?(e.clipPathId="CLIPPATH_"+fabric.Object.__uid++,'\n'+this.clipPath.toClipPathSVG(t.reviver)+"\n"):""},createSVGRefElementsMarkup:function(){var n=this;return["background","overlay"].map(function(t){var e=n[t+"Color"];if(e&&e.toLive){var i=n[t+"Vpt"],r=n.viewportTransform,t={width:n.width/(i?r[0]:1),height:n.height/(i?r[3]:1)};return e.toSVG(t,{additionalTransform:i?fabric.util.matrixToSVG(r):""})}}).join("")},createSVGFontFacesMarkup:function(){var t,e,i,r,n,s,o,a,c,h="",l={},u=fabric.fontPaths,f=[];for(this._objects.forEach(function t(e){f.push(e),e._objects&&e._objects.forEach(t)}),o=0,a=f.length;o',"\n",h,"","\n"].join("")},_setSVGObjects:function(t,e){for(var i,r=this._objects,n=0,s=r.length;n\n")):t.push('\n"))},sendToBack:function(t){if(!t)return this;var e,i,r,n=this._activeObject;if(t===n&&"activeSelection"===t.type)for(e=(r=n._objects).length;e--;)i=r[e],h(this._objects,i),this._objects.unshift(i);else h(this._objects,t),this._objects.unshift(t);return this.renderOnAddRemove&&this.requestRenderAll(),this},bringToFront:function(t){if(!t)return this;var e,i,r,n=this._activeObject;if(t===n&&"activeSelection"===t.type)for(r=n._objects,e=0;e"}}),n(fabric.StaticCanvas.prototype,fabric.Observable),n(fabric.StaticCanvas.prototype,fabric.Collection),n(fabric.StaticCanvas.prototype,fabric.DataURLExporter),n(fabric.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(t){var e=r();if(!e||!e.getContext)return null;e=e.getContext("2d");return!e||"setLineDash"!==t?null:void 0!==e.setLineDash}}),fabric.StaticCanvas.prototype.toJSON=fabric.StaticCanvas.prototype.toObject,fabric.isLikelyNode&&(fabric.StaticCanvas.prototype.createPNGStream=function(){var t=i(this.lowerCanvasEl);return t&&t.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(t){var e=i(this.lowerCanvasEl);return e&&e.createJPEGStream(t)}))}(),fabric.BaseBrush=fabric.util.createClass({color:"rgb(0, 0, 0)",width:1,shadow:null,strokeLineCap:"round",strokeLineJoin:"round",strokeMiterLimit:10,strokeDashArray:null,limitedToCanvasSize:!1,_setBrushStyles:function(){var t=this.canvas.contextTop;t.strokeStyle=this.color,t.lineWidth=this.width,t.lineCap=this.strokeLineCap,t.miterLimit=this.strokeMiterLimit,t.lineJoin=this.strokeLineJoin,t.setLineDash(this.strokeDashArray||[])},_saveAndTransform:function(t){var e=this.canvas.viewportTransform;t.save(),t.transform(e[0],e[1],e[2],e[3],e[4],e[5])},_setShadow:function(){var t,e,i,r;this.shadow&&(t=this.canvas,e=this.shadow,i=t.contextTop,r=t.getZoom(),t&&t._isRetinaScaling()&&(r*=fabric.devicePixelRatio),i.shadowColor=e.color,i.shadowBlur=e.blur*r,i.shadowOffsetX=e.offsetX*r,i.shadowOffsetY=e.offsetY*r)},needsFullRender:function(){return new fabric.Color(this.color).getAlpha()<1||!!this.shadow},_resetShadow:function(){var t=this.canvas.contextTop;t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0},_isOutSideCanvas:function(t){return t.x<0||t.x>this.canvas.getWidth()||t.y<0||t.y>this.canvas.getHeight()}}),fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{decimate:.4,initialize:function(t){this.canvas=t,this._points=[]},_drawSegment:function(t,e,i){i=e.midPointFrom(i);return t.quadraticCurveTo(e.x,e.y,i.x,i.y),i},onMouseDown:function(t,e){this.canvas._isMainEvent(e.e)&&(this._prepareForDrawing(t),this._captureDrawingPath(t),this._render())},onMouseMove:function(t,e){var i;this.canvas._isMainEvent(e.e)&&(!0===this.limitedToCanvasSize&&this._isOutSideCanvas(t)||this._captureDrawingPath(t)&&1"},getObjectScaling:function(){if(!this.group)return{scaleX:this.scaleX,scaleY:this.scaleY};var t=g.util.qrDecompose(this.calcTransformMatrix());return{scaleX:Math.abs(t.scaleX),scaleY:Math.abs(t.scaleY)}},getTotalObjectScaling:function(){var t,e=this.getObjectScaling(),i=e.scaleX,r=e.scaleY;return this.canvas&&(i*=(t=this.canvas.getZoom())*(e=this.canvas.getRetinaScaling()),r*=t*e),{scaleX:i,scaleY:r}},getObjectOpacity:function(){var t=this.opacity;return this.group&&(t*=this.group.getObjectOpacity()),t},_set:function(t,e){var i,r=this[t]!==e;return("scaleX"===t||"scaleY"===t)&&(e=this._constrainScale(e)),"scaleX"===t&&e<0?(this.flipX=!this.flipX,e*=-1):"scaleY"===t&&e<0?(this.flipY=!this.flipY,e*=-1):"shadow"!==t||!e||e instanceof g.Shadow?"dirty"===t&&this.group&&this.group.set("dirty",e):e=new g.Shadow(e),this[t]=e,r&&(i=this.group&&this.group.isOnACache(),-1=t.x&&r.left+r.width<=e.x&&r.top>=t.y&&r.top+r.height<=e.y},containsPoint:function(t,e,i,r){r=this._getCoords(i,r),e=e||this._getImageLines(r),e=this._findCrossPoints(t,e);return 0!==e&&e%2==1},isOnScreen:function(t){if(!this.canvas)return!1;var e=this.canvas.vptCoords.tl,i=this.canvas.vptCoords.br;return!!this.getCoords(!0,t).some(function(t){return t.x<=i.x&&t.x>=e.x&&t.y<=i.y&&t.y>=e.y})||(!!this.intersectsWithRect(e,i,!0,t)||this._containsCenterOfCanvas(e,i,t))},_containsCenterOfCanvas:function(t,e,i){e={x:(t.x+e.x)/2,y:(t.y+e.y)/2};return!!this.containsPoint(e,null,!0,i)},isPartiallyOnScreen:function(t){if(!this.canvas)return!1;var e=this.canvas.vptCoords.tl,i=this.canvas.vptCoords.br;return!!this.intersectsWithRect(e,i,!0,t)||this.getCoords(!0,t).every(function(t){return(t.x>=i.x||t.x<=e.x)&&(t.y>=i.y||t.y<=e.y)})&&this._containsCenterOfCanvas(e,i,t)},_getImageLines:function(t){return{topline:{o:t.tl,d:t.tr},rightline:{o:t.tr,d:t.br},bottomline:{o:t.br,d:t.bl},leftline:{o:t.bl,d:t.tl}}},_findCrossPoints:function(t,e){var i,r,n,s=0;for(n in e)if(!((r=e[n]).o.y=t.y&&r.d.y>=t.y||((r.o.x===r.d.x&&r.o.x>=t.x?r.o.x:(i=(r.d.y-r.o.y)/(r.d.x-r.o.x),-(t.y-0*t.x-(r.o.y-i*r.o.x))/(0-i)))>=t.x&&(s+=1),2!==s)))break;return s},getBoundingRect:function(t,e){e=this.getCoords(t,e);return s.makeBoundingBoxFromPoints(e)},getScaledWidth:function(){return this._getTransformedDimensions().x},getScaledHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(t){return Math.abs(t)\n'))},toSVG:function(t){return this._createBaseSVGMarkup(this._toSVG(t),{reviver:t})},toClipPathSVG:function(t){return"\t"+this._createBaseClipPathSVGMarkup(this._toSVG(t),{reviver:t})},_createBaseClipPathSVGMarkup:function(t,e){var i=(e=e||{}).reviver,r=e.additionalTransform||"",e=[this.getSvgTransform(!0,r),this.getSvgCommons()].join(""),r=t.indexOf("COMMON_PARTS");return t[r]=e,i?i(t.join("")):t.join("")},_createBaseSVGMarkup:function(t,e){var i,r=(e=e||{}).noStyle,n=e.reviver,s=r?"":'style="'+this.getSvgStyles()+'" ',o=e.withShadow?'style="'+this.getSvgFilter()+'" ':"",a=this.clipPath,c=this.strokeUniform?'vector-effect="non-scaling-stroke" ':"",h=a&&a.absolutePositioned,l=this.stroke,u=this.fill,f=this.shadow,d=[],g=t.indexOf("COMMON_PARTS"),e=e.additionalTransform;return a&&(a.clipPathId="CLIPPATH_"+fabric.Object.__uid++,i='\n'+a.toClipPathSVG(n)+"\n"),h&&d.push("\n"),d.push("\n"),e=[s,c,r?"":this.addPaintOrder()," ",e?'transform="'+e+'" ':""].join(""),t[g]=e,u&&u.toLive&&d.push(u.toSVG(this)),l&&l.toLive&&d.push(l.toSVG(this)),f&&d.push(f.toSVG(this)),a&&d.push(i),d.push(t.join("")),d.push("\n"),h&&d.push("\n"),n?n(d.join("")):d.join("")},addPaintOrder:function(){return"fill"!==this.paintFirst?' paint-order="'+this.paintFirst+'" ':""}})}(),function(){var n=fabric.util.object.extend,r="stateProperties";function s(e,t,i){var r={};i.forEach(function(t){r[t]=e[t]}),n(e[t],r,!0)}fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(t){var e="_"+(t=t||r);return Object.keys(this[e]).length\n']}}),n.Line.ATTRIBUTE_NAMES=n.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),n.Line.fromElement=function(t,e,i){i=i||{};var r=n.parseAttributes(t,n.Line.ATTRIBUTE_NAMES),t=[r.x1||0,r.y1||0,r.x2||0,r.y2||0];e(new n.Line(t,s(r,i)))},n.Line.fromObject=function(t,e){var i=r(t,!0);i.points=[t.x1,t.y1,t.x2,t.y2],n.Object._fromObject("Line",i,function(t){delete t.points,e&&e(t)},"points")})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var s=t.fabric||(t.fabric={}),o=Math.PI;s.Circle?s.warn("fabric.Circle is already defined."):(s.Circle=s.util.createClass(s.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*o,cacheProperties:s.Object.prototype.cacheProperties.concat("radius","startAngle","endAngle"),_set:function(t,e){return this.callSuper("_set",t,e),"radius"===t&&this.setRadius(e),this},toObject:function(t){return this.callSuper("toObject",["radius","startAngle","endAngle"].concat(t))},_toSVG:function(){var t,e,i,r,n=(this.endAngle-this.startAngle)%(2*o);return 0==n?["\n']:(t=s.util.cos(this.startAngle)*this.radius,e=s.util.sin(this.startAngle)*this.radius,i=s.util.cos(this.endAngle)*this.radius,r=s.util.sin(this.endAngle)*this.radius,['\n"])},_render:function(t){t.beginPath(),t.arc(0,0,this.radius,this.startAngle,this.endAngle,!1),this._renderPaintInOrder(t)},getRadiusX:function(){return this.get("radius")*this.get("scaleX")},getRadiusY:function(){return this.get("radius")*this.get("scaleY")},setRadius:function(t){return this.radius=t,this.set("width",2*t).set("height",2*t)}}),s.Circle.ATTRIBUTE_NAMES=s.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),s.Circle.fromElement=function(t,e){var i=s.parseAttributes(t,s.Circle.ATTRIBUTE_NAMES);if(!("radius"in(t=i)&&0<=t.radius))throw new Error("value of `r` attribute is required and can not be negative");i.left=(i.left||0)-i.radius,i.top=(i.top||0)-i.radius,e(new s.Circle(i))},s.Circle.fromObject=function(t,e){s.Object._fromObject("Circle",t,e)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var i=t.fabric||(t.fabric={});i.Triangle?i.warn("fabric.Triangle is already defined"):(i.Triangle=i.util.createClass(i.Object,{type:"triangle",width:100,height:100,_render:function(t){var e=this.width/2,i=this.height/2;t.beginPath(),t.moveTo(-e,i),t.lineTo(0,-i),t.lineTo(e,i),t.closePath(),this._renderPaintInOrder(t)},_toSVG:function(){var t=this.width/2,e=this.height/2;return["']}}),i.Triangle.fromObject=function(t,e){return i.Object._fromObject("Triangle",t,e)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var i=t.fabric||(t.fabric={}),e=2*Math.PI;i.Ellipse?i.warn("fabric.Ellipse is already defined."):(i.Ellipse=i.util.createClass(i.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:i.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this.set("rx",t&&t.rx||0),this.set("ry",t&&t.ry||0)},_set:function(t,e){switch(this.callSuper("_set",t,e),t){case"rx":this.rx=e,this.set("width",2*e);break;case"ry":this.ry=e,this.set("height",2*e)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(t){return this.callSuper("toObject",["rx","ry"].concat(t))},_toSVG:function(){return["\n']},_render:function(t){t.beginPath(),t.save(),t.transform(1,0,0,this.ry/this.rx,0,0),t.arc(0,0,this.rx,0,e,!1),t.restore(),this._renderPaintInOrder(t)}}),i.Ellipse.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("cx cy rx ry".split(" ")),i.Ellipse.fromElement=function(t,e){t=i.parseAttributes(t,i.Ellipse.ATTRIBUTE_NAMES);t.left=(t.left||0)-t.rx,t.top=(t.top||0)-t.ry,e(new i.Ellipse(t))},i.Ellipse.fromObject=function(t,e){i.Object._fromObject("Ellipse",t,e)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var r=t.fabric||(t.fabric={}),n=r.util.object.extend;r.Rect?r.warn("fabric.Rect is already defined"):(r.Rect=r.util.createClass(r.Object,{stateProperties:r.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:r.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(t){var e=this.rx?Math.min(this.rx,this.width/2):0,i=this.ry?Math.min(this.ry,this.height/2):0,r=this.width,n=this.height,s=-this.width/2,o=-this.height/2,a=0!==e||0!==i,c=.4477152502;t.beginPath(),t.moveTo(s+e,o),t.lineTo(s+r-e,o),a&&t.bezierCurveTo(s+r-c*e,o,s+r,o+c*i,s+r,o+i),t.lineTo(s+r,o+n-i),a&&t.bezierCurveTo(s+r,o+n-c*i,s+r-c*e,o+n,s+r-e,o+n),t.lineTo(s+e,o+n),a&&t.bezierCurveTo(s+c*e,o+n,s,o+n-c*i,s,o+n-i),t.lineTo(s,o+i),a&&t.bezierCurveTo(s,o+c*i,s+c*e,o,s+e,o),t.closePath(),this._renderPaintInOrder(t)},toObject:function(t){return this.callSuper("toObject",["rx","ry"].concat(t))},_toSVG:function(){return["\n']}}),r.Rect.ATTRIBUTE_NAMES=r.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),r.Rect.fromElement=function(t,e,i){if(!t)return e(null);i=i||{};t=r.parseAttributes(t,r.Rect.ATTRIBUTE_NAMES);t.left=t.left||0,t.top=t.top||0,t.height=t.height||0,t.width=t.width||0;t=new r.Rect(n(i?r.util.object.clone(i):{},t));t.visible=t.visible&&0\n']},commonRender:function(t){var e,i=this.points.length,r=this.pathOffset.x,n=this.pathOffset.y;if(!i||isNaN(this.points[i-1].y))return!1;t.beginPath(),t.moveTo(this.points[0].x-r,this.points[0].y-n);for(var s=0;s"},toObject:function(t){return r(this.callSuper("toObject",t),{path:this.path.map(function(t){return t.slice()})})},toDatalessObject:function(t){t=this.toObject(["sourcePath"].concat(t));return t.sourcePath&&delete t.path,t},_toSVG:function(){return["\n"]},_getOffsetTransform:function(){var t=f.Object.NUM_FRACTION_DIGITS;return" translate("+e(-this.pathOffset.x,t)+", "+e(-this.pathOffset.y,t)+")"},toClipPathSVG:function(t){var e=this._getOffsetTransform();return"\t"+this._createBaseClipPathSVGMarkup(this._toSVG(),{reviver:t,additionalTransform:e})},toSVG:function(t){var e=this._getOffsetTransform();return this._createBaseSVGMarkup(this._toSVG(),{reviver:t,additionalTransform:e})},complexity:function(){return this.path.length},_calcDimensions:function(){for(var t,e,i=[],r=[],n=0,s=0,o=0,a=0,c=0,h=this.path.length;c"},addWithUpdate:function(t){var e=!!this.group;return this._restoreObjectsState(),o.util.resetObjectTransform(this),t&&(e&&o.util.removeTransformFromObject(t,this.group.calcTransformMatrix()),this._objects.push(t),t.group=this,t._set("canvas",this.canvas)),this._calcBounds(),this._updateObjectsCoords(),this.dirty=!0,e?this.group.addWithUpdate():this.setCoords(),this},removeWithUpdate:function(t){return this._restoreObjectsState(),o.util.resetObjectTransform(this),this.remove(t),this._calcBounds(),this._updateObjectsCoords(),this.setCoords(),this.dirty=!0,this},_onObjectAdded:function(t){this.dirty=!0,t.group=this,t._set("canvas",this.canvas)},_onObjectRemoved:function(t){this.dirty=!0,delete t.group},_set:function(t,e){var i=this._objects.length;if(this.useSetOnGroup)for(;i--;)this._objects[i].setOnGroup(t,e);if("canvas"===t)for(;i--;)this._objects[i]._set(t,e);o.Object.prototype._set.call(this,t,e)},toObject:function(r){var n=this.includeDefaultValues,t=this._objects.filter(function(t){return!t.excludeFromExport}).map(function(t){var e=t.includeDefaultValues;t.includeDefaultValues=n;var i=t.toObject(r);return t.includeDefaultValues=e,i}),e=o.Object.prototype.toObject.call(this,r);return e.objects=t,e},toDatalessObject:function(r){var n,t,e=this.sourcePath;t=e||(n=this.includeDefaultValues,this._objects.map(function(t){var e=t.includeDefaultValues;t.includeDefaultValues=n;var i=t.toDatalessObject(r);return t.includeDefaultValues=e,i}));e=o.Object.prototype.toDatalessObject.call(this,r);return e.objects=t,e},render:function(t){this._transformDone=!0,this.callSuper("render",t),this._transformDone=!1},shouldCache:function(){var t=o.Object.prototype.shouldCache.call(this);if(t)for(var e=0,i=this._objects.length;e\n"],i=0,r=this._objects.length;i\n"),e},getSvgStyles:function(){var t=void 0!==this.opacity&&1!==this.opacity?"opacity: "+this.opacity+";":"",e=this.visible?"":" visibility: hidden;";return[t,this.getSvgFilter(),e].join("")},toClipPathSVG:function(t){for(var e=[],i=0,r=this._objects.length;i"},shouldCache:function(){return!1},isOnACache:function(){return!1},_renderControls:function(t,e,i){t.save(),t.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,this.callSuper("_renderControls",t,e),void 0===(i=i||{}).hasControls&&(i.hasControls=!1),i.forActiveSelection=!0;for(var r=0,n=this._objects.length;r\n','\t\n',"\n"),a=' clip-path="url(#imageCrop_'+e+')" '),this.imageSmoothing||(c='" image-rendering="optimizeSpeed'),r.push("\t\n"),(this.stroke||this.strokeDashArray)&&(a=this.fill,this.fill=null,t=["\t\n'],this.fill=a),i="fill"!==this.paintFirst?i.concat(t,r):i.concat(r,t)):[]},getSrc:function(t){t=t?this._element:this._originalElement;return t?t.toDataURL?t.toDataURL():this.srcFromAttribute?t.getAttribute("src"):t.src:this.src||""},setSrc:function(t,i,r){return fabric.util.loadImage(t,function(t,e){this.setElement(t,r),this._setWidthHeight(),i&&i(this,e)},this,r&&r.crossOrigin),this},toString:function(){return'#'},applyResizeFilters:function(){var t=this.resizeFilter,e=this.minimumScaleTrigger,i=this.getTotalObjectScaling(),r=i.scaleX,n=i.scaleY,s=this._filteredEl||this._originalElement;if(this.group&&this.set("dirty",!0),!t||e=t,o=["highp","mediump","lowp"],a=0;a<3;a++)if(r=void 0,r="precision "+(i=o[a])+" float;\nvoid main(){}",i=(e=s).createShader(e.FRAGMENT_SHADER),e.shaderSource(i,r),e.compileShader(i),!!e.getShaderParameter(i,e.COMPILE_STATUS)){fabric.webGlPrecision=o[a];break}}return this.isSupported=n},(fabric.WebglFilterBackend=t).prototype={tileSize:2048,resources:{},setupGLContext:function(t,e){this.dispose(),this.createWebGLCanvas(t,e),this.aPosition=new Float32Array([0,0,0,1,1,0,1,1]),this.chooseFastestCopyGLTo2DMethod(t,e)},chooseFastestCopyGLTo2DMethod:function(t,e){var i=void 0!==window.performance;try{new ImageData(1,1),s=!0}catch(t){s=!1}var r="undefined"!=typeof ArrayBuffer,n="undefined"!=typeof Uint8ClampedArray;if(i&&s&&r&&n){var s=fabric.util.createCanvasElement(),r=new ArrayBuffer(t*e*4);if(fabric.forceGLPutImageData)return this.imageBuffer=r,void(this.copyGLTo2D=copyGLTo2DPutImageData);n={imageBuffer:r,destinationWidth:t,destinationHeight:e,targetCanvas:s};s.width=t,s.height=e,s=window.performance.now(),copyGLTo2DDrawImage.call(n,this.gl,n),e=window.performance.now()-s,s=window.performance.now(),copyGLTo2DPutImageData.call(n,this.gl,n),window.performance.now()-s 0.0) {\n"+this.fragmentSource[t]+"}\n}"},retrieveShader:function(t){var e,i=this.type+"_"+this.mode;return t.programCache.hasOwnProperty(i)||(e=this.buildSource(this.mode),t.programCache[i]=this.createProgram(t.context,e)),t.programCache[i]},applyTo2d:function(t){for(var e,i,r,n=t.imageData.data,s=n.length,o=1-this.alpha,t=new u.Color(this.color).getSource(),a=t[0]*this.alpha,c=t[1]*this.alpha,h=t[2]*this.alpha,l=0;l'},_getCacheCanvasDimensions:function(){var t=this.callSuper("_getCacheCanvasDimensions"),e=this.fontSize;return t.width+=e*t.zoomX,t.height+=e*t.zoomY,t},_render:function(t){var e=this.path;e&&!e.isNotVisible()&&e._render(t),this._setTextStyles(t),this._renderTextLinesBackground(t),this._renderTextDecoration(t,"underline"),this._renderText(t),this._renderTextDecoration(t,"overline"),this._renderTextDecoration(t,"linethrough")},_renderText:function(t){"stroke"===this.paintFirst?(this._renderTextStroke(t),this._renderTextFill(t)):(this._renderTextFill(t),this._renderTextStroke(t))},_setTextStyles:function(t,e,i){t.textBaseline="alphabetic",t.font=this._getFontDeclaration(e,i)},calcTextWidth:function(){for(var t=this.getLineWidth(0),e=1,i=this._textLines.length;ethis.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=e):(this.selectionStart=e,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart===i&&this.selectionEnd===t||(this.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection())))},_setEditingProps:function(){this.hoverCursor="text",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},fromStringToGraphemeSelection:function(t,e,i){var r=i.slice(0,t),r=fabric.util.string.graphemeSplit(r).length;if(t===e)return{selectionStart:r,selectionEnd:r};e=i.slice(t,e);return{selectionStart:r,selectionEnd:r+fabric.util.string.graphemeSplit(e).length}},fromGraphemeToStringSelection:function(t,e,i){var r=i.slice(0,t).join("").length;return t===e?{selectionStart:r,selectionEnd:r}:{selectionStart:r,selectionEnd:r+i.slice(t,e).join("").length}},_updateTextarea:function(){var t;this.cursorOffsetCache={},this.hiddenTextarea&&(this.inCompositionMode||(t=this.fromGraphemeToStringSelection(this.selectionStart,this.selectionEnd,this._text),this.hiddenTextarea.selectionStart=t.selectionStart,this.hiddenTextarea.selectionEnd=t.selectionEnd),this.updateTextareaPosition())},updateFromTextArea:function(){var t;this.hiddenTextarea&&(this.cursorOffsetCache={},this.text=this.hiddenTextarea.value,this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),t=this.fromStringToGraphemeSelection(this.hiddenTextarea.selectionStart,this.hiddenTextarea.selectionEnd,this.hiddenTextarea.value),this.selectionEnd=this.selectionStart=t.selectionEnd,this.inCompositionMode||(this.selectionStart=t.selectionStart),this.updateTextareaPosition())},updateTextareaPosition:function(){var t;this.selectionStart===this.selectionEnd&&(t=this._calcTextareaPosition(),this.hiddenTextarea.style.left=t.left,this.hiddenTextarea.style.top=t.top)},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var t=this.inCompositionMode?this.compositionStart:this.selectionStart,e=this._getCursorBoundaries(t),i=this.get2DCursorLocation(t),r=i.lineIndex,n=i.charIndex,s=this.getValueOfPropertyAt(r,n,"fontSize")*this.lineHeight,o=e.leftOffset,a=this.calcTransformMatrix(),t={x:e.left+o,y:e.top+e.topOffset+s},i=this.canvas.getRetinaScaling(),r=this.canvas.upperCanvasEl,n=r.width/i,o=r.height/i,e=n-s,i=o-s,n=r.clientWidth/n,o=r.clientHeight/o,t=fabric.util.transformPoint(t,a);return(t=fabric.util.transformPoint(t,this.canvas.viewportTransform)).x*=n,t.y*=o,t.x<0&&(t.x=0),t.x>e&&(t.x=e),t.y<0&&(t.y=0),t.y>i&&(t.y=i),t.x+=this.canvas._offset.left,t.y+=this.canvas._offset.top,{left:t.x+"px",top:t.y+"px",fontSize:s+"px",charHeight:s}},_saveEditingProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,selectable:this.selectable,defaultCursor:this.canvas&&this.canvas.defaultCursor,moveCursor:this.canvas&&this.canvas.moveCursor}},_restoreEditingProps:function(){this._savedProps&&(this.hoverCursor=this._savedProps.hoverCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,this.selectable=this._savedProps.selectable,this.lockMovementX=this._savedProps.lockMovementX,this.lockMovementY=this._savedProps.lockMovementY,this.canvas&&(this.canvas.defaultCursor=this._savedProps.defaultCursor,this.canvas.moveCursor=this._savedProps.moveCursor))},exitEditing:function(){var t=this._textBeforeEdit!==this.text,e=this.hiddenTextarea;return this.selected=!1,this.isEditing=!1,this.selectionEnd=this.selectionStart,e&&(e.blur&&e.blur(),e.parentNode&&e.parentNode.removeChild(e)),this.hiddenTextarea=null,this.abortCursorAnimation(),this._restoreEditingProps(),this._currentCursorOpacity=0,this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this.fire("editing:exited"),t&&this.fire("modified"),this.canvas&&(this.canvas.off("mouse:move",this.mouseMoveHandler),this.canvas.fire("text:editing:exited",{target:this}),t&&this.canvas.fire("object:modified",{target:this})),this},_removeExtraneousStyles:function(){for(var t in this.styles)this._textLines[t]||delete this.styles[t]},removeStyleFromTo:function(t,e){var t=this.get2DCursorLocation(t,!0),e=this.get2DCursorLocation(e,!0),i=t.lineIndex,r=t.charIndex,n=e.lineIndex,s=e.charIndex;if(i!==n){if(this.styles[i])for(l=r;lt?this.selectionStart=t:this.selectionStart<0&&(this.selectionStart=0),this.selectionEnd>t?this.selectionEnd=t:this.selectionEnd<0&&(this.selectionEnd=0)}})}(),fabric.util.object.extend(fabric.IText.prototype,{initDoubleClickSimulation:function(){this.__lastClickTime=+new Date,this.__lastLastClickTime=+new Date,this.__lastPointer={},this.on("mousedown",this.onMouseDown)},onMouseDown:function(t){var e;this.canvas&&(this.__newClickTime=+new Date,e=t.pointer,this.isTripleClick(e)&&(this.fire("tripleclick",t),this._stopEvent(t.e)),this.__lastLastClickTime=this.__lastClickTime,this.__lastClickTime=this.__newClickTime,this.__lastPointer=e,this.__lastIsEditing=this.isEditing,this.__lastSelected=this.selected)},isTripleClick:function(t){return this.__newClickTime-this.__lastClickTime<500&&this.__lastClickTime-this.__lastLastClickTime<500&&this.__lastPointer.x===t.x&&this.__lastPointer.y===t.y},_stopEvent:function(t){t.preventDefault&&t.preventDefault(),t.stopPropagation&&t.stopPropagation()},initCursorSelectionHandlers:function(){this.initMousedownHandler(),this.initMouseupHandler(),this.initClicks()},doubleClickHandler:function(t){this.isEditing&&this.selectWord(this.getSelectionStartFromPointer(t.e))},tripleClickHandler:function(t){this.isEditing&&this.selectLine(this.getSelectionStartFromPointer(t.e))},initClicks:function(){this.on("mousedblclick",this.doubleClickHandler),this.on("tripleclick",this.tripleClickHandler)},_mouseDownHandler:function(t){!this.canvas||!this.editable||t.e.button&&1!==t.e.button||(this.__isMousedown=!0,this.selected&&(this.inCompositionMode=!1,this.setCursorByClick(t.e)),this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection()))},_mouseDownHandlerBefore:function(t){!this.canvas||!this.editable||t.e.button&&1!==t.e.button||(this.selected=this===this.canvas._activeObject)},initMousedownHandler:function(){this.on("mousedown",this._mouseDownHandler),this.on("mousedown:before",this._mouseDownHandlerBefore)},initMouseupHandler:function(){this.on("mouseup",this.mouseUpHandler)},mouseUpHandler:function(t){if(this.__isMousedown=!1,!(!this.editable||this.group||t.transform&&t.transform.actionPerformed||t.e.button&&1!==t.e.button)){if(this.canvas){var e=this.canvas._activeObject;if(e&&e!==this)return}this.__lastSelected&&!this.__corner?(this.selected=!1,this.__lastSelected=!1,this.enterEditing(t.e),this.selectionStart===this.selectionEnd?this.initDelayedCursor(!0):this.renderCursorOrSelection()):this.selected=!0}},setCursorByClick:function(t){var e=this.getSelectionStartFromPointer(t),i=this.selectionStart,r=this.selectionEnd;t.shiftKey?this.setSelectionStartEndWithShift(i,r,e):(this.selectionStart=e,this.selectionEnd=e),this.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(t){for(var e=this.getLocalPointer(t),i=0,r=0,n=0,s=0,o=0,a=0,c=this._textLines.length;athis._text.length?this._text.length:t}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.setAttribute("autocorrect","off"),this.hiddenTextarea.setAttribute("autocomplete","off"),this.hiddenTextarea.setAttribute("spellcheck","false"),this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea",""),this.hiddenTextarea.setAttribute("wrap","off");var t=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+t.top+"; left: "+t.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; paddingーtop: "+t.fontSize+";",(this.hiddenTextareaContainer||fabric.document.body).appendChild(this.hiddenTextarea),fabric.util.addListener(this.hiddenTextarea,"keydown",this.onKeyDown.bind(this)),fabric.util.addListener(this.hiddenTextarea,"keyup",this.onKeyUp.bind(this)),fabric.util.addListener(this.hiddenTextarea,"input",this.onInput.bind(this)),fabric.util.addListener(this.hiddenTextarea,"copy",this.copy.bind(this)),fabric.util.addListener(this.hiddenTextarea,"cut",this.copy.bind(this)),fabric.util.addListener(this.hiddenTextarea,"paste",this.paste.bind(this)),fabric.util.addListener(this.hiddenTextarea,"compositionstart",this.onCompositionStart.bind(this)),fabric.util.addListener(this.hiddenTextarea,"compositionupdate",this.onCompositionUpdate.bind(this)),fabric.util.addListener(this.hiddenTextarea,"compositionend",this.onCompositionEnd.bind(this)),!this._clickHandlerInitialized&&this.canvas&&(fabric.util.addListener(this.canvas.upperCanvasEl,"click",this.onClick.bind(this)),this._clickHandlerInitialized=!0)},keysMap:{9:"exitEditing",27:"exitEditing",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorRight",36:"moveCursorLeft",37:"moveCursorLeft",38:"moveCursorUp",39:"moveCursorRight",40:"moveCursorDown"},keysMapRtl:{9:"exitEditing",27:"exitEditing",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorLeft",36:"moveCursorRight",37:"moveCursorRight",38:"moveCursorUp",39:"moveCursorLeft",40:"moveCursorDown"},ctrlKeysMapUp:{67:"copy",88:"cut"},ctrlKeysMapDown:{65:"selectAll"},onClick:function(){this.hiddenTextarea&&this.hiddenTextarea.focus()},onKeyDown:function(t){if(this.isEditing){var e="rtl"===this.direction?this.keysMapRtl:this.keysMap;if(t.keyCode in e)this[e[t.keyCode]](t);else{if(!(t.keyCode in this.ctrlKeysMapDown&&(t.ctrlKey||t.metaKey)))return;this[this.ctrlKeysMapDown[t.keyCode]](t)}t.stopImmediatePropagation(),t.preventDefault(),33<=t.keyCode&&t.keyCode<=40?(this.inCompositionMode=!1,this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.requestRenderAll()}},onKeyUp:function(t){!this.isEditing||this._copyDone||this.inCompositionMode?this._copyDone=!1:t.keyCode in this.ctrlKeysMapUp&&(t.ctrlKey||t.metaKey)&&(this[this.ctrlKeysMapUp[t.keyCode]](t),t.stopImmediatePropagation(),t.preventDefault(),this.canvas&&this.canvas.requestRenderAll())},onInput:function(t){var e=this.fromPaste;if(this.fromPaste=!1,t&&t.stopPropagation(),this.isEditing){var i,r,n,s=this._splitTextIntoLines(this.hiddenTextarea.value).graphemeText,o=this._text.length,a=s.length,c=a-o,h=this.selectionStart,l=this.selectionEnd,u=h!==l;if(""===this.hiddenTextarea.value)return this.styles={},this.updateFromTextArea(),this.fire("changed"),void(this.canvas&&(this.canvas.fire("text:changed",{target:this}),this.canvas.requestRenderAll()));var f=this.fromStringToGraphemeSelection(this.hiddenTextarea.selectionStart,this.hiddenTextarea.selectionEnd,this.hiddenTextarea.value),t=h>f.selectionStart;u?(n=this._text.slice(h,l),c+=l-h):a=this._text.length&&this.selectionEnd>=this._text.length||this._moveCursorUpOrDown("Down",t)},moveCursorUp:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",t)},_moveCursorUpOrDown:function(t,e){t=this["get"+t+"CursorOffset"](e,"right"===this._selectionDirection);e.shiftKey?this.moveCursorWithShift(t):this.moveCursorWithoutShift(t),0!==t&&(this.setSelectionInBoundaries(),this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(t){var e="left"===this._selectionDirection?this.selectionStart+t:this.selectionEnd+t;return this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,e),0!==t},moveCursorWithoutShift:function(t){return t<0?(this.selectionStart+=t,this.selectionEnd=this.selectionStart):(this.selectionEnd+=t,this.selectionStart=this.selectionEnd),0!==t},moveCursorLeft:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorLeftOrRight("Left",t)},_move:function(t,e,i){var r;if(t.altKey)r=this["findWordBoundary"+i](this[e]);else{if(!t.metaKey&&35!==t.keyCode&&36!==t.keyCode)return this[e]+="Left"===i?-1:1,!0;r=this["findLineBoundary"+i](this[e])}if(this[e]!==r)return this[e]=r,!0},_moveLeft:function(t,e){return this._move(t,e,"Left")},_moveRight:function(t,e){return this._move(t,e,"Right")},moveCursorLeftWithoutShift:function(t){var e=!0;return this._selectionDirection="left",this.selectionEnd===this.selectionStart&&0!==this.selectionStart&&(e=this._moveLeft(t,"selectionStart")),this.selectionEnd=this.selectionStart,e},moveCursorLeftWithShift:function(t){return"right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveLeft(t,"selectionEnd"):0!==this.selectionStart?(this._selectionDirection="left",this._moveLeft(t,"selectionStart")):void 0},moveCursorRight:function(t){this.selectionStart>=this._text.length&&this.selectionEnd>=this._text.length||this._moveCursorLeftOrRight("Right",t)},_moveCursorLeftOrRight:function(t,e){t="moveCursor"+t+"With";this._currentCursorOpacity=1,e.shiftKey?t+="Shift":t+="outShift",this[t](e)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(t){return"left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveRight(t,"selectionStart"):this.selectionEnd!==this._text.length?(this._selectionDirection="right",this._moveRight(t,"selectionEnd")):void 0},moveCursorRightWithoutShift:function(t){var e=!0;return this._selectionDirection="right",this.selectionStart===this.selectionEnd?(e=this._moveRight(t,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd,e},removeChars:function(t,e){this.removeStyleFromTo(t,e=void 0===e?t+1:e),this._text.splice(t,e-t),this.text=this._text.join(""),this.set("dirty",!0),this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this._removeExtraneousStyles()},insertChars:function(t,e,i,r){i<(r=void 0===r?i:r)&&this.removeStyleFromTo(i,r);t=fabric.util.string.graphemeSplit(t);this.insertNewStyleBlock(t,i,e),this._text=[].concat(this._text.slice(0,i),t,this._text.slice(r)),this.text=this._text.join(""),this.set("dirty",!0),this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this._removeExtraneousStyles()}}),function(){var a=fabric.util.toFixed,c=/ +/g;fabric.util.object.extend(fabric.Text.prototype,{_toSVG:function(){var t=this._getSVGLeftTopOffsets(),t=this._getSVGTextAndBg(t.textTop,t.textLeft);return this._wrapSVGTextAndBg(t)},toSVG:function(t){return this._createBaseSVGMarkup(this._toSVG(),{reviver:t,noStyle:!0,withShadow:!0})},_getSVGLeftTopOffsets:function(){return{textLeft:-this.width/2,textTop:-this.height/2,lineTop:this.getHeightOfLine(0)}},_wrapSVGTextAndBg:function(t){var e=this.getSvgTextDecoration(this);return[t.textBgRects.join(""),'\t\t",t.textSpans.join(""),"\n"]},_getSVGTextAndBg:function(t,e){var i,r=[],n=[],s=t;this._setSVGBg(n);for(var o=0,a=this._textLines.length;o",fabric.util.string.escapeXml(t),""].join("")},_setSVGTextLineText:function(t,e,i,r){var n,s,o,a,c=this.getHeightOfLine(e),h=-1!==this.textAlign.indexOf("justify"),l="",u=0,f=this._textLines[e];r+=c*(1-this._fontSizeFraction)/this.lineHeight;for(var d=0,g=f.length-1;d<=g;d++)a=d===g||this.charSpacing,l+=f[d],o=this.__charBounds[e][d],0===u?(i+=o.kernedWidth-o.width,u+=o.width):u+=o.kernedWidth,(a=h&&!a&&this._reSpaceAndTab.test(f[d])?!0:a)||(n=n||this.getCompleteStyleDeclaration(e,d),s=this.getCompleteStyleDeclaration(e,d+1),a=this._hasStyleChangedForSvg(n,s)),a&&(a=this._getStyleDeclaration(e,d)||{},t.push(this._createTextCharSpan(l,a,i,r)),l="",n=s,i+=u,u=0)},_pushTextBgRect:function(t,e,i,r,n,s){var o=fabric.Object.NUM_FRACTION_DIGITS;t.push("\t\t\n')},_setSVGTextLineBg:function(t,e,i,r){for(var n,s,o=this._textLines[e],a=this.getHeightOfLine(e)/this.lineHeight,c=0,h=0,l=this.getValueOfPropertyAt(e,0,"textBackgroundColor"),u=0,f=o.length;uthis.width&&this._set("width",this.dynamicMinWidth),-1!==this.textAlign.indexOf("justify")&&this.enlargeSpaces(),this.height=this.calcTextHeight(),this.saveState({propertySet:"_dimensionAffectingProps"}))},_generateStyleMap:function(t){for(var e=0,i=0,r=0,n={},s=0;sthis.dynamicMinWidth&&(this.dynamicMinWidth=g-m+r),c},isEndOfWrapping:function(t){return!this._styleMap[t+1]||this._styleMap[t+1].line!==this._styleMap[t].line},missingNewlineOffset:function(t){return!this.splitByGrapheme||this.isEndOfWrapping(t)?1:0},_splitTextIntoLines:function(t){for(var t=b.Text.prototype._splitTextIntoLines.call(this,t),e=this._wrapText(t.lines,this.width),i=new Array(e.length),r=0;r_)for(var C=1,S=d.length;Ct[i-2].x?1:n.x===t[i-2].x?0:-1,c=n.y>t[i-2].y?1:n.y===t[i-2].y?0:-1),r.push(["L",n.x+a*e,n.y+c*e]),r},fabric.util.getPathSegmentsInfo=l,fabric.util.getBoundsOfCurve=function(t,e,i,r,n,s,o,a){var c;if(fabric.cachesBoundsOfCurve&&(c=j.call(arguments),fabric.boundsOfCurveCache[c]))return fabric.boundsOfCurveCache[c];var h,l,u,f,d,g,p,v,m=Math.sqrt,b=Math.min,y=Math.max,_=Math.abs,x=[],C=[[],[]];l=6*t-12*i+6*n,h=-3*t+9*i-9*n+3*o,u=3*i-3*t;for(var S=0;S<2;++S)if(0/g,">")},graphemeSplit:function(t){var e,i=0,r=[];for(i=0;it.x&&this.y>t.y},gte:function(t){return this.x>=t.x&&this.y>=t.y},lerp:function(t,e){return void 0===e&&(e=.5),e=Math.max(Math.min(1,e),0),new i(this.x+(t.x-this.x)*e,this.y+(t.y-this.y)*e)},distanceFrom:function(t){var e=this.x-t.x,i=this.y-t.y;return Math.sqrt(e*e+i*i)},midPointFrom:function(t){return this.lerp(t)},min:function(t){return new i(Math.min(this.x,t.x),Math.min(this.y,t.y))},max:function(t){return new i(Math.max(this.x,t.x),Math.max(this.y,t.y))},toString:function(){return this.x+","+this.y},setXY:function(t,e){return this.x=t,this.y=e,this},setX:function(t){return this.x=t,this},setY:function(t){return this.y=t,this},setFromPoint:function(t){return this.x=t.x,this.y=t.y,this},swap:function(t){var e=this.x,i=this.y;this.x=t.x,this.y=t.y,t.x=e,t.y=i},clone:function(){return new i(this.x,this.y)}}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var f=t.fabric||(t.fabric={});function d(t){this.status=t,this.points=[]}f.Intersection?f.warn("fabric.Intersection is already defined"):(f.Intersection=d,f.Intersection.prototype={constructor:d,appendPoint:function(t){return this.points.push(t),this},appendPoints:function(t){return this.points=this.points.concat(t),this}},f.Intersection.intersectLineLine=function(t,e,i,r){var n,s=(r.x-i.x)*(t.y-i.y)-(r.y-i.y)*(t.x-i.x),o=(e.x-t.x)*(t.y-i.y)-(e.y-t.y)*(t.x-i.x),a=(r.y-i.y)*(e.x-t.x)-(r.x-i.x)*(e.y-t.y);if(0!==a){var c=s/a,h=o/a;0<=c&&c<=1&&0<=h&&h<=1?(n=new d("Intersection")).appendPoint(new f.Point(t.x+c*(e.x-t.x),t.y+c*(e.y-t.y))):n=new d}else n=new d(0===s||0===o?"Coincident":"Parallel");return n},f.Intersection.intersectLinePolygon=function(t,e,i){var r,n,s,o,a=new d,c=i.length;for(o=0;o=c&&(h.x-=c),h.x<=-c&&(h.x+=c),h.y>=c&&(h.y-=c),h.y<=c&&(h.y+=c),h.x-=o.offsetX,h.y-=o.offsetY,h}function y(t){return t.flipX!==t.flipY}function _(t,e,i,r,n){if(0!==t[e]){var s=n/t._getTransformedDimensions()[r]*t[i];t.set(i,s)}}function x(t,e,i,r){var n,s=e.target,o=s._getTransformedDimensions(0,s.skewY),a=P(e,e.originX,e.originY,i,r),c=Math.abs(2*a.x)-o.x,h=s.skewX;c<2?n=0:(n=v(Math.atan2(c/s.scaleX,o.y/s.scaleY)),e.originX===f&&e.originY===p&&(n=-n),e.originX===g&&e.originY===d&&(n=-n),y(s)&&(n=-n));var l=h!==n;if(l){var u=s._getTransformedDimensions().y;s.set("skewX",n),_(s,"skewY","scaleY","y",u)}return l}function C(t,e,i,r){var n,s=e.target,o=s._getTransformedDimensions(s.skewX,0),a=P(e,e.originX,e.originY,i,r),c=Math.abs(2*a.y)-o.y,h=s.skewY;c<2?n=0:(n=v(Math.atan2(c/s.scaleY,o.x/s.scaleX)),e.originX===f&&e.originY===p&&(n=-n),e.originX===g&&e.originY===d&&(n=-n),y(s)&&(n=-n));var l=h!==n;if(l){var u=s._getTransformedDimensions().x;s.set("skewY",n),_(s,"skewX","scaleX","x",u)}return l}function E(t,e,i,r,n){n=n||{};var s,o,a,c,h,l,u=e.target,f=u.lockScalingX,d=u.lockScalingY,g=n.by,p=w(t,u),v=k(u,g,p),m=e.gestureScale;if(v)return!1;if(m)o=e.scaleX*m,a=e.scaleY*m;else{if(s=P(e,e.originX,e.originY,i,r),h="y"!==g?T(s.x):1,l="x"!==g?T(s.y):1,e.signX||(e.signX=h),e.signY||(e.signY=l),u.lockScalingFlip&&(e.signX!==h||e.signY!==l))return!1;if(c=u._getTransformedDimensions(),p&&!g){var b=Math.abs(s.x)+Math.abs(s.y),y=e.original,_=b/(Math.abs(c.x*y.scaleX/u.scaleX)+Math.abs(c.y*y.scaleY/u.scaleY));o=y.scaleX*_,a=y.scaleY*_}else o=Math.abs(s.x*u.scaleX/c.x),a=Math.abs(s.y*u.scaleY/c.y);O(e)&&(o*=2,a*=2),e.signX!==h&&"y"!==g&&(e.originX=S[e.originX],o*=-1,e.signX=h),e.signY!==l&&"x"!==g&&(e.originY=S[e.originY],a*=-1,e.signY=l)}var x=u.scaleX,C=u.scaleY;return g?("x"===g&&u.set("scaleX",o),"y"===g&&u.set("scaleY",a)):(!f&&u.set("scaleX",o),!d&&u.set("scaleY",a)),x!==u.scaleX||C!==u.scaleY}n.scaleCursorStyleHandler=function(t,e,i){var r=w(t,i),n="";if(0!==e.x&&0===e.y?n="x":0===e.x&&0!==e.y&&(n="y"),k(i,n,r))return"not-allowed";var s=a(i,e);return o[s]+"-resize"},n.skewCursorStyleHandler=function(t,e,i){var r="not-allowed";if(0!==e.x&&i.lockSkewingY)return r;if(0!==e.y&&i.lockSkewingX)return r;var n=a(i,e)%4;return s[n]+"-resize"},n.scaleSkewCursorStyleHandler=function(t,e,i){return t[i.canvas.altActionKey]?n.skewCursorStyleHandler(t,e,i):n.scaleCursorStyleHandler(t,e,i)},n.rotationWithSnapping=b("rotating",m(function(t,e,i,r){var n=e,s=n.target,o=s.translateToOriginPoint(s.getCenterPoint(),n.originX,n.originY);if(s.lockRotation)return!1;var a,c=Math.atan2(n.ey-o.y,n.ex-o.x),h=Math.atan2(r-o.y,i-o.x),l=v(h-c+n.theta);if(0o.r2,h=this.gradientTransform?this.gradientTransform.concat():fabric.iMatrix.concat(),l=-this.offsetX,u=-this.offsetY,f=!!e.additionalTransform,d="pixels"===this.gradientUnits?"userSpaceOnUse":"objectBoundingBox";if(a.sort(function(t,e){return t.offset-e.offset}),"objectBoundingBox"===d?(l/=t.width,u/=t.height):(l+=t.width/2,u+=t.height/2),"path"===t.type&&"percentage"!==this.gradientUnits&&(l-=t.pathOffset.x,u-=t.pathOffset.y),h[4]-=l,h[5]-=u,s='id="SVGID_'+this.id+'" gradientUnits="'+d+'"',s+=' gradientTransform="'+(f?e.additionalTransform+" ":"")+fabric.util.matrixToSVG(h)+'" ',"linear"===this.type?n=["\n']:"radial"===this.type&&(n=["\n']),"radial"===this.type){if(c)for((a=a.concat()).reverse(),i=0,r=a.length;i\n')}return n.push("linear"===this.type?"\n":"\n"),n.join("")},toLive:function(t){var e,i,r,n=fabric.util.object.clone(this.coords);if(this.type){for("linear"===this.type?e=t.createLinearGradient(n.x1,n.y1,n.x2,n.y2):"radial"===this.type&&(e=t.createRadialGradient(n.x1,n.y1,n.r1,n.x2,n.y2,n.r2)),i=0,r=this.colorStops.length;i\n\n\n'},setOptions:function(t){for(var e in t)this[e]=t[e]},toLive:function(t){var e=this.source;if(!e)return"";if(void 0!==e.src){if(!e.complete)return"";if(0===e.naturalWidth||0===e.naturalHeight)return""}return t.createPattern(e,this.repeat)}})}(),function(t){"use strict";var o=t.fabric||(t.fabric={}),a=o.util.toFixed;o.Shadow?o.warn("fabric.Shadow is already defined."):(o.Shadow=o.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,nonScaling:!1,initialize:function(t){for(var e in"string"==typeof t&&(t=this._parseShadow(t)),t)this[e]=t[e];this.id=o.Object.__uid++},_parseShadow:function(t){var e=t.trim(),i=o.Shadow.reOffsetsAndBlur.exec(e)||[];return{color:(e.replace(o.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(),offsetX:parseFloat(i[1],10)||0,offsetY:parseFloat(i[2],10)||0,blur:parseFloat(i[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(t){var e=40,i=40,r=o.Object.NUM_FRACTION_DIGITS,n=o.util.rotateVector({x:this.offsetX,y:this.offsetY},o.util.degreesToRadians(-t.angle)),s=new o.Color(this.color);return t.width&&t.height&&(e=100*a((Math.abs(n.x)+this.blur)/t.width,r)+20,i=100*a((Math.abs(n.y)+this.blur)/t.height,r)+20),t.flipX&&(n.x*=-1),t.flipY&&(n.y*=-1),'\n\t\n\t\n\t\n\t\n\t\n\t\t\n\t\t\n\t\n\n'},toObject:function(){if(this.includeDefaultValues)return{color:this.color,blur:this.blur,offsetX:this.offsetX,offsetY:this.offsetY,affectStroke:this.affectStroke,nonScaling:this.nonScaling};var e={},i=o.Shadow.prototype;return["color","blur","offsetX","offsetY","affectStroke","nonScaling"].forEach(function(t){this[t]!==i[t]&&(e[t]=this[t])},this),e}}),o.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(-?\d+(?:\.\d*)?(?:px)?(?:\s?|$))?(\d+(?:\.\d*)?(?:px)?)?(?:\s?|$)(?:$|\s)/)}("undefined"!=typeof exports?exports:this),function(){"use strict";if(fabric.StaticCanvas)fabric.warn("fabric.StaticCanvas is already defined.");else{var n=fabric.util.object.extend,t=fabric.util.getElementOffset,h=fabric.util.removeFromArray,a=fabric.util.toFixed,s=fabric.util.transformPoint,o=fabric.util.invertTransform,i=fabric.util.getNodeCanvas,r=fabric.util.createCanvasElement,e=new Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(t,e){e||(e={}),this.renderAndResetBound=this.renderAndReset.bind(this),this.requestRenderAllBound=this.requestRenderAll.bind(this),this._initStatic(t,e)},backgroundColor:"",backgroundImage:null,overlayColor:"",overlayImage:null,includeDefaultValues:!0,stateful:!1,renderOnAddRemove:!0,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,viewportTransform:fabric.iMatrix.concat(),backgroundVpt:!0,overlayVpt:!0,enableRetinaScaling:!0,vptCoords:{},skipOffscreen:!0,clipPath:void 0,_initStatic:function(t,e){var i=this.requestRenderAllBound;this._objects=[],this._createLowerCanvas(t),this._initOptions(e),this.interactive||this._initRetinaScaling(),e.overlayImage&&this.setOverlayImage(e.overlayImage,i),e.backgroundImage&&this.setBackgroundImage(e.backgroundImage,i),e.backgroundColor&&this.setBackgroundColor(e.backgroundColor,i),e.overlayColor&&this.setOverlayColor(e.overlayColor,i),this.calcOffset()},_isRetinaScaling:function(){return 1\n'),this._setSVGBgOverlayColor(i,"background"),this._setSVGBgOverlayImage(i,"backgroundImage",e),this._setSVGObjects(i,e),this.clipPath&&i.push("\n"),this._setSVGBgOverlayColor(i,"overlay"),this._setSVGBgOverlayImage(i,"overlayImage",e),i.push(""),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,r=e.width||this.width,n=e.height||this.height,s='viewBox="0 0 '+this.width+" "+this.height+'" ',o=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?s='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,s='viewBox="'+a(-i[4]/i[0],o)+" "+a(-i[5]/i[3],o)+" "+a(this.width/i[0],o)+" "+a(this.height/i[3],o)+'" '),t.push("\n',"Created with Fabric.js ",fabric.version,"\n","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),this.createSVGClipPathMarkup(e),"\n")},createSVGClipPathMarkup:function(t){var e=this.clipPath;return e?(e.clipPathId="CLIPPATH_"+fabric.Object.__uid++,'\n'+this.clipPath.toClipPathSVG(t.reviver)+"\n"):""},createSVGRefElementsMarkup:function(){var s=this;return["background","overlay"].map(function(t){var e=s[t+"Color"];if(e&&e.toLive){var i=s[t+"Vpt"],r=s.viewportTransform,n={width:s.width/(i?r[0]:1),height:s.height/(i?r[3]:1)};return e.toSVG(n,{additionalTransform:i?fabric.util.matrixToSVG(r):""})}}).join("")},createSVGFontFacesMarkup:function(){var t,e,i,r,n,s,o,a,c="",h={},l=fabric.fontPaths,u=[];for(this._objects.forEach(function t(e){u.push(e),e._objects&&e._objects.forEach(t)}),o=0,a=u.length;o',"\n",c,"","\n"].join("")),c},_setSVGObjects:function(t,e){var i,r,n,s=this._objects;for(r=0,n=s.length;r\n")}else t.push('\n")},sendToBack:function(t){if(!t)return this;var e,i,r,n=this._activeObject;if(t===n&&"activeSelection"===t.type)for(e=(r=n._objects).length;e--;)i=r[e],h(this._objects,i),this._objects.unshift(i);else h(this._objects,t),this._objects.unshift(t);return this.renderOnAddRemove&&this.requestRenderAll(),this},bringToFront:function(t){if(!t)return this;var e,i,r,n=this._activeObject;if(t===n&&"activeSelection"===t.type)for(r=n._objects,e=0;e"}}),n(fabric.StaticCanvas.prototype,fabric.Observable),n(fabric.StaticCanvas.prototype,fabric.Collection),n(fabric.StaticCanvas.prototype,fabric.DataURLExporter),n(fabric.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(t){var e=r();if(!e||!e.getContext)return null;var i=e.getContext("2d");if(!i)return null;switch(t){case"setLineDash":return void 0!==i.setLineDash;default:return null}}}),fabric.StaticCanvas.prototype.toJSON=fabric.StaticCanvas.prototype.toObject,fabric.isLikelyNode&&(fabric.StaticCanvas.prototype.createPNGStream=function(){var t=i(this.lowerCanvasEl);return t&&t.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(t){var e=i(this.lowerCanvasEl);return e&&e.createJPEGStream(t)})}}(),fabric.BaseBrush=fabric.util.createClass({color:"rgb(0, 0, 0)",width:1,shadow:null,strokeLineCap:"round",strokeLineJoin:"round",strokeMiterLimit:10,strokeDashArray:null,limitedToCanvasSize:!1,_setBrushStyles:function(t){t.strokeStyle=this.color,t.lineWidth=this.width,t.lineCap=this.strokeLineCap,t.miterLimit=this.strokeMiterLimit,t.lineJoin=this.strokeLineJoin,t.setLineDash(this.strokeDashArray||[])},_saveAndTransform:function(t){var e=this.canvas.viewportTransform;t.save(),t.transform(e[0],e[1],e[2],e[3],e[4],e[5])},_setShadow:function(){if(this.shadow){var t=this.canvas,e=this.shadow,i=t.contextTop,r=t.getZoom();t&&t._isRetinaScaling()&&(r*=fabric.devicePixelRatio),i.shadowColor=e.color,i.shadowBlur=e.blur*r,i.shadowOffsetX=e.offsetX*r,i.shadowOffsetY=e.offsetY*r}},needsFullRender:function(){return new fabric.Color(this.color).getAlpha()<1||!!this.shadow},_resetShadow:function(){var t=this.canvas.contextTop;t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0},_isOutSideCanvas:function(t){return t.x<0||t.x>this.canvas.getWidth()||t.y<0||t.y>this.canvas.getHeight()}}),fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{decimate:.4,drawStraightLine:!1,straightLineKey:"shiftKey",initialize:function(t){this.canvas=t,this._points=[]},needsFullRender:function(){return this.callSuper("needsFullRender")||this._hasStraightLine},_drawSegment:function(t,e,i){var r=e.midPointFrom(i);return t.quadraticCurveTo(e.x,e.y,r.x,r.y),r},onMouseDown:function(t,e){this.canvas._isMainEvent(e.e)&&(this.drawStraightLine=e.e[this.straightLineKey],this._prepareForDrawing(t),this._captureDrawingPath(t),this._render())},onMouseMove:function(t,e){if(this.canvas._isMainEvent(e.e)&&(this.drawStraightLine=e.e[this.straightLineKey],(!0!==this.limitedToCanvasSize||!this._isOutSideCanvas(t))&&this._captureDrawingPath(t)&&1"},getObjectScaling:function(){if(!this.group)return{scaleX:this.scaleX,scaleY:this.scaleY};var t=x.util.qrDecompose(this.calcTransformMatrix());return{scaleX:Math.abs(t.scaleX),scaleY:Math.abs(t.scaleY)}},getTotalObjectScaling:function(){var t=this.getObjectScaling(),e=t.scaleX,i=t.scaleY;if(this.canvas){var r=this.canvas.getZoom(),n=this.canvas.getRetinaScaling();e*=r*n,i*=r*n}return{scaleX:e,scaleY:i}},getObjectOpacity:function(){var t=this.opacity;return this.group&&(t*=this.group.getObjectOpacity()),t},_set:function(t,e){var i="scaleX"===t||"scaleY"===t,r=this[t]!==e,n=!1;return i&&(e=this._constrainScale(e)),"scaleX"===t&&e<0?(this.flipX=!this.flipX,e*=-1):"scaleY"===t&&e<0?(this.flipY=!this.flipY,e*=-1):"shadow"!==t||!e||e instanceof x.Shadow?"dirty"===t&&this.group&&this.group.set("dirty",e):e=new x.Shadow(e),this[t]=e,r&&(n=this.group&&this.group.isOnACache(),-1=t.x&&n.left+n.width<=e.x&&n.top>=t.y&&n.top+n.height<=e.y},containsPoint:function(t,e,i,r){var n=this._getCoords(i,r),s=(e=e||this._getImageLines(n),this._findCrossPoints(t,e));return 0!==s&&s%2==1},isOnScreen:function(t){if(!this.canvas)return!1;var e=this.canvas.vptCoords.tl,i=this.canvas.vptCoords.br;return!!this.getCoords(!0,t).some(function(t){return t.x<=i.x&&t.x>=e.x&&t.y<=i.y&&t.y>=e.y})||(!!this.intersectsWithRect(e,i,!0,t)||this._containsCenterOfCanvas(e,i,t))},_containsCenterOfCanvas:function(t,e,i){var r={x:(t.x+e.x)/2,y:(t.y+e.y)/2};return!!this.containsPoint(r,null,!0,i)},isPartiallyOnScreen:function(t){if(!this.canvas)return!1;var e=this.canvas.vptCoords.tl,i=this.canvas.vptCoords.br;return!!this.intersectsWithRect(e,i,!0,t)||this.getCoords(!0,t).every(function(t){return(t.x>=i.x||t.x<=e.x)&&(t.y>=i.y||t.y<=e.y)})&&this._containsCenterOfCanvas(e,i,t)},_getImageLines:function(t){return{topline:{o:t.tl,d:t.tr},rightline:{o:t.tr,d:t.br},bottomline:{o:t.br,d:t.bl},leftline:{o:t.bl,d:t.tl}}},_findCrossPoints:function(t,e){var i,r,n,s=0;for(var o in e)if(!((n=e[o]).o.y=t.y&&n.d.y>=t.y||(n.o.x===n.d.x&&n.o.x>=t.x?r=n.o.x:(0,i=(n.d.y-n.o.y)/(n.d.x-n.o.x),r=-(t.y-0*t.x-(n.o.y-i*n.o.x))/(0-i)),r>=t.x&&(s+=1),2!==s)))break;return s},getBoundingRect:function(t,e){var i=this.getCoords(t,e);return h.makeBoundingBoxFromPoints(i)},getScaledWidth:function(){return this._getTransformedDimensions().x},getScaledHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(t){return Math.abs(t)\n')}},toSVG:function(t){return this._createBaseSVGMarkup(this._toSVG(t),{reviver:t})},toClipPathSVG:function(t){return"\t"+this._createBaseClipPathSVGMarkup(this._toSVG(t),{reviver:t})},_createBaseClipPathSVGMarkup:function(t,e){var i=(e=e||{}).reviver,r=e.additionalTransform||"",n=[this.getSvgTransform(!0,r),this.getSvgCommons()].join(""),s=t.indexOf("COMMON_PARTS");return t[s]=n,i?i(t.join("")):t.join("")},_createBaseSVGMarkup:function(t,e){var i,r,n=(e=e||{}).noStyle,s=e.reviver,o=n?"":'style="'+this.getSvgStyles()+'" ',a=e.withShadow?'style="'+this.getSvgFilter()+'" ':"",c=this.clipPath,h=this.strokeUniform?'vector-effect="non-scaling-stroke" ':"",l=c&&c.absolutePositioned,u=this.stroke,f=this.fill,d=this.shadow,g=[],p=t.indexOf("COMMON_PARTS"),v=e.additionalTransform;return c&&(c.clipPathId="CLIPPATH_"+fabric.Object.__uid++,r='\n'+c.toClipPathSVG(s)+"\n"),l&&g.push("\n"),g.push("\n"),i=[o,h,n?"":this.addPaintOrder()," ",v?'transform="'+v+'" ':""].join(""),t[p]=i,f&&f.toLive&&g.push(f.toSVG(this)),u&&u.toLive&&g.push(u.toSVG(this)),d&&g.push(d.toSVG(this)),c&&g.push(r),g.push(t.join("")),g.push("\n"),l&&g.push("\n"),s?s(g.join("")):g.join("")},addPaintOrder:function(){return"fill"!==this.paintFirst?' paint-order="'+this.paintFirst+'" ':""}})}(),function(){var n=fabric.util.object.extend,r="stateProperties";function s(e,t,i){var r={};i.forEach(function(t){r[t]=e[t]}),n(e[t],r,!0)}fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(t){var e="_"+(t=t||r);return Object.keys(this[e]).length\n']}}),s.Line.ATTRIBUTE_NAMES=s.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),s.Line.fromElement=function(t,e,i){i=i||{};var r=s.parseAttributes(t,s.Line.ATTRIBUTE_NAMES),n=[r.x1||0,r.y1||0,r.x2||0,r.y2||0];e(new s.Line(n,o(r,i)))},s.Line.fromObject=function(t,e){var i=r(t,!0);i.points=[t.x1,t.y1,t.x2,t.y2],s.Object._fromObject("Line",i,function(t){delete t.points,e&&e(t)},"points")})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var s=t.fabric||(t.fabric={}),o=s.util.degreesToRadians;s.Circle?s.warn("fabric.Circle is already defined."):(s.Circle=s.util.createClass(s.Object,{type:"circle",radius:0,startAngle:0,endAngle:360,cacheProperties:s.Object.prototype.cacheProperties.concat("radius","startAngle","endAngle"),_set:function(t,e){return this.callSuper("_set",t,e),"radius"===t&&this.setRadius(e),this},toObject:function(t){return this.callSuper("toObject",["radius","startAngle","endAngle"].concat(t))},_toSVG:function(){var t,e=(this.endAngle-this.startAngle)%360;if(0===e)t=["\n'];else{var i=o(this.startAngle),r=o(this.endAngle),n=this.radius;t=['\n"]}return t},_render:function(t){t.beginPath(),t.arc(0,0,this.radius,o(this.startAngle),o(this.endAngle),!1),this._renderPaintInOrder(t)},getRadiusX:function(){return this.get("radius")*this.get("scaleX")},getRadiusY:function(){return this.get("radius")*this.get("scaleY")},setRadius:function(t){return this.radius=t,this.set("width",2*t).set("height",2*t)}}),s.Circle.ATTRIBUTE_NAMES=s.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),s.Circle.fromElement=function(t,e){var i,r=s.parseAttributes(t,s.Circle.ATTRIBUTE_NAMES);if(!("radius"in(i=r)&&0<=i.radius))throw new Error("value of `r` attribute is required and can not be negative");r.left=(r.left||0)-r.radius,r.top=(r.top||0)-r.radius,e(new s.Circle(r))},s.Circle.fromObject=function(t,e){s.Object._fromObject("Circle",t,e)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var i=t.fabric||(t.fabric={});i.Triangle?i.warn("fabric.Triangle is already defined"):(i.Triangle=i.util.createClass(i.Object,{type:"triangle",width:100,height:100,_render:function(t){var e=this.width/2,i=this.height/2;t.beginPath(),t.moveTo(-e,i),t.lineTo(0,-i),t.lineTo(e,i),t.closePath(),this._renderPaintInOrder(t)},_toSVG:function(){var t=this.width/2,e=this.height/2;return["']}}),i.Triangle.fromObject=function(t,e){return i.Object._fromObject("Triangle",t,e)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var r=t.fabric||(t.fabric={}),e=2*Math.PI;r.Ellipse?r.warn("fabric.Ellipse is already defined."):(r.Ellipse=r.util.createClass(r.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:r.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this.set("rx",t&&t.rx||0),this.set("ry",t&&t.ry||0)},_set:function(t,e){switch(this.callSuper("_set",t,e),t){case"rx":this.rx=e,this.set("width",2*e);break;case"ry":this.ry=e,this.set("height",2*e)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(t){return this.callSuper("toObject",["rx","ry"].concat(t))},_toSVG:function(){return["\n']},_render:function(t){t.beginPath(),t.save(),t.transform(1,0,0,this.ry/this.rx,0,0),t.arc(0,0,this.rx,0,e,!1),t.restore(),this._renderPaintInOrder(t)}}),r.Ellipse.ATTRIBUTE_NAMES=r.SHARED_ATTRIBUTES.concat("cx cy rx ry".split(" ")),r.Ellipse.fromElement=function(t,e){var i=r.parseAttributes(t,r.Ellipse.ATTRIBUTE_NAMES);i.left=(i.left||0)-i.rx,i.top=(i.top||0)-i.ry,e(new r.Ellipse(i))},r.Ellipse.fromObject=function(t,e){r.Object._fromObject("Ellipse",t,e)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var s=t.fabric||(t.fabric={}),o=s.util.object.extend;s.Rect?s.warn("fabric.Rect is already defined"):(s.Rect=s.util.createClass(s.Object,{stateProperties:s.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:s.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(t){var e=this.rx?Math.min(this.rx,this.width/2):0,i=this.ry?Math.min(this.ry,this.height/2):0,r=this.width,n=this.height,s=-this.width/2,o=-this.height/2,a=0!==e||0!==i,c=.4477152502;t.beginPath(),t.moveTo(s+e,o),t.lineTo(s+r-e,o),a&&t.bezierCurveTo(s+r-c*e,o,s+r,o+c*i,s+r,o+i),t.lineTo(s+r,o+n-i),a&&t.bezierCurveTo(s+r,o+n-c*i,s+r-c*e,o+n,s+r-e,o+n),t.lineTo(s+e,o+n),a&&t.bezierCurveTo(s+c*e,o+n,s,o+n-c*i,s,o+n-i),t.lineTo(s,o+i),a&&t.bezierCurveTo(s,o+c*i,s+c*e,o,s+e,o),t.closePath(),this._renderPaintInOrder(t)},toObject:function(t){return this.callSuper("toObject",["rx","ry"].concat(t))},_toSVG:function(){return["\n']}}),s.Rect.ATTRIBUTE_NAMES=s.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),s.Rect.fromElement=function(t,e,i){if(!t)return e(null);i=i||{};var r=s.parseAttributes(t,s.Rect.ATTRIBUTE_NAMES);r.left=r.left||0,r.top=r.top||0,r.height=r.height||0,r.width=r.width||0;var n=new s.Rect(o(i?s.util.object.clone(i):{},r));n.visible=n.visible&&0\n']},commonRender:function(t){var e,i=this.points.length,r=this.pathOffset.x,n=this.pathOffset.y;if(!i||isNaN(this.points[i-1].y))return!1;t.beginPath(),t.moveTo(this.points[0].x-r,this.points[0].y-n);for(var s=0;s"},toObject:function(t){return n(this.callSuper("toObject",t),{path:this.path.map(function(t){return t.slice()})})},toDatalessObject:function(t){var e=this.toObject(["sourcePath"].concat(t));return e.sourcePath&&delete e.path,e},_toSVG:function(){return["\n"]},_getOffsetTransform:function(){var t=f.Object.NUM_FRACTION_DIGITS;return" translate("+e(-this.pathOffset.x,t)+", "+e(-this.pathOffset.y,t)+")"},toClipPathSVG:function(t){var e=this._getOffsetTransform();return"\t"+this._createBaseClipPathSVGMarkup(this._toSVG(),{reviver:t,additionalTransform:e})},toSVG:function(t){var e=this._getOffsetTransform();return this._createBaseSVGMarkup(this._toSVG(),{reviver:t,additionalTransform:e})},complexity:function(){return this.path.length},_calcDimensions:function(){for(var t,e,i=[],r=[],n=0,s=0,o=0,a=0,c=0,h=this.path.length;c"},addWithUpdate:function(t){var e=!!this.group;return this._restoreObjectsState(),h.util.resetObjectTransform(this),t&&(e&&h.util.removeTransformFromObject(t,this.group.calcTransformMatrix()),this._objects.push(t),t.group=this,t._set("canvas",this.canvas)),this._calcBounds(),this._updateObjectsCoords(),this.dirty=!0,e?this.group.addWithUpdate():this.setCoords(),this},removeWithUpdate:function(t){return this._restoreObjectsState(),h.util.resetObjectTransform(this),this.remove(t),this._calcBounds(),this._updateObjectsCoords(),this.setCoords(),this.dirty=!0,this},_onObjectAdded:function(t){this.dirty=!0,t.group=this,t._set("canvas",this.canvas)},_onObjectRemoved:function(t){this.dirty=!0,delete t.group},_set:function(t,e){var i=this._objects.length;if(this.useSetOnGroup)for(;i--;)this._objects[i].setOnGroup(t,e);if("canvas"===t)for(;i--;)this._objects[i]._set(t,e);h.Object.prototype._set.call(this,t,e)},toObject:function(r){var n=this.includeDefaultValues,t=this._objects.filter(function(t){return!t.excludeFromExport}).map(function(t){var e=t.includeDefaultValues;t.includeDefaultValues=n;var i=t.toObject(r);return t.includeDefaultValues=e,i}),e=h.Object.prototype.toObject.call(this,r);return e.objects=t,e},toDatalessObject:function(r){var t,e=this.sourcePath;if(e)t=e;else{var n=this.includeDefaultValues;t=this._objects.map(function(t){var e=t.includeDefaultValues;t.includeDefaultValues=n;var i=t.toDatalessObject(r);return t.includeDefaultValues=e,i})}var i=h.Object.prototype.toDatalessObject.call(this,r);return i.objects=t,i},render:function(t){this._transformDone=!0,this.callSuper("render",t),this._transformDone=!1},shouldCache:function(){var t=h.Object.prototype.shouldCache.call(this);if(t)for(var e=0,i=this._objects.length;e\n"],i=0,r=this._objects.length;i\n"),e},getSvgStyles:function(){var t=void 0!==this.opacity&&1!==this.opacity?"opacity: "+this.opacity+";":"",e=this.visible?"":" visibility: hidden;";return[t,this.getSvgFilter(),e].join("")},toClipPathSVG:function(t){for(var e=[],i=0,r=this._objects.length;i"},shouldCache:function(){return!1},isOnACache:function(){return!1},_renderControls:function(t,e,i){t.save(),t.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,this.callSuper("_renderControls",t,e),void 0===(i=i||{}).hasControls&&(i.hasControls=!1),i.forActiveSelection=!0;for(var r=0,n=this._objects.length;r\n','\t\n',"\n"),o=' clip-path="url(#imageCrop_'+c+')" '}if(this.imageSmoothing||(a='" image-rendering="optimizeSpeed'),i.push("\t\n"),this.stroke||this.strokeDashArray){var h=this.fill;this.fill=null,t=["\t\n'],this.fill=h}return e="fill"!==this.paintFirst?e.concat(t,i):e.concat(i,t)},getSrc:function(t){var e=t?this._element:this._originalElement;return e?e.toDataURL?e.toDataURL():this.srcFromAttribute?e.getAttribute("src"):e.src:this.src||""},setSrc:function(t,i,r){return fabric.util.loadImage(t,function(t,e){this.setElement(t,r),this._setWidthHeight(),i&&i(this,e)},this,r&&r.crossOrigin),this},toString:function(){return'#'},applyResizeFilters:function(){var t=this.resizeFilter,e=this.minimumScaleTrigger,i=this.getTotalObjectScaling(),r=i.scaleX,n=i.scaleY,s=this._filteredEl||this._originalElement;if(this.group&&this.set("dirty",!0),!t||e=t;for(var a=["highp","mediump","lowp"],c=0;c<3;c++)if(void 0,i="precision "+a[c]+" float;\nvoid main(){}",r=(e=s).createShader(e.FRAGMENT_SHADER),e.shaderSource(r,i),e.compileShader(r),e.getShaderParameter(r,e.COMPILE_STATUS)){fabric.webGlPrecision=a[c];break}}return this.isSupported=o},(fabric.WebglFilterBackend=t).prototype={tileSize:2048,resources:{},setupGLContext:function(t,e){this.dispose(),this.createWebGLCanvas(t,e),this.aPosition=new Float32Array([0,0,0,1,1,0,1,1]),this.chooseFastestCopyGLTo2DMethod(t,e)},chooseFastestCopyGLTo2DMethod:function(t,e){var i,r=void 0!==window.performance;try{new ImageData(1,1),i=!0}catch(t){i=!1}var n="undefined"!=typeof ArrayBuffer,s="undefined"!=typeof Uint8ClampedArray;if(r&&i&&n&&s){var o=fabric.util.createCanvasElement(),a=new ArrayBuffer(t*e*4);if(fabric.forceGLPutImageData)return this.imageBuffer=a,void(this.copyGLTo2D=copyGLTo2DPutImageData);var c,h,l={imageBuffer:a,destinationWidth:t,destinationHeight:e,targetCanvas:o};o.width=t,o.height=e,c=window.performance.now(),copyGLTo2DDrawImage.call(l,this.gl,l),h=window.performance.now()-c,c=window.performance.now(),copyGLTo2DPutImageData.call(l,this.gl,l),window.performance.now()-c 0.0) {\n"+this.fragmentSource[t]+"}\n}"},retrieveShader:function(t){var e,i=this.type+"_"+this.mode;return t.programCache.hasOwnProperty(i)||(e=this.buildSource(this.mode),t.programCache[i]=this.createProgram(t.context,e)),t.programCache[i]},applyTo2d:function(t){var e,i,r,n,s,o,a,c=t.imageData.data,h=c.length,l=1-this.alpha;e=(a=new f.Color(this.color).getSource())[0]*this.alpha,i=a[1]*this.alpha,r=a[2]*this.alpha;for(var u=0;u'},_getCacheCanvasDimensions:function(){var t=this.callSuper("_getCacheCanvasDimensions"),e=this.fontSize;return t.width+=e*t.zoomX,t.height+=e*t.zoomY,t},_render:function(t){var e=this.path;e&&!e.isNotVisible()&&e._render(t),this._setTextStyles(t),this._renderTextLinesBackground(t),this._renderTextDecoration(t,"underline"),this._renderText(t),this._renderTextDecoration(t,"overline"),this._renderTextDecoration(t,"linethrough")},_renderText:function(t){"stroke"===this.paintFirst?(this._renderTextStroke(t),this._renderTextFill(t)):(this._renderTextFill(t),this._renderTextStroke(t))},_setTextStyles:function(t,e,i){if(t.textBaseline="alphabetical",this.path)switch(this.pathAlign){case"center":t.textBaseline="middle";break;case"ascender":t.textBaseline="top";break;case"descender":t.textBaseline="bottom"}t.font=this._getFontDeclaration(e,i)},calcTextWidth:function(){for(var t=this.getLineWidth(0),e=1,i=this._textLines.length;ethis.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=e):(this.selectionStart=e,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart===i&&this.selectionEnd===r||(this.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()))}},_setEditingProps:function(){this.hoverCursor="text",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},fromStringToGraphemeSelection:function(t,e,i){var r=i.slice(0,t),n=fabric.util.string.graphemeSplit(r).length;if(t===e)return{selectionStart:n,selectionEnd:n};var s=i.slice(t,e);return{selectionStart:n,selectionEnd:n+fabric.util.string.graphemeSplit(s).length}},fromGraphemeToStringSelection:function(t,e,i){var r=i.slice(0,t).join("").length;return t===e?{selectionStart:r,selectionEnd:r}:{selectionStart:r,selectionEnd:r+i.slice(t,e).join("").length}},_updateTextarea:function(){if(this.cursorOffsetCache={},this.hiddenTextarea){if(!this.inCompositionMode){var t=this.fromGraphemeToStringSelection(this.selectionStart,this.selectionEnd,this._text);this.hiddenTextarea.selectionStart=t.selectionStart,this.hiddenTextarea.selectionEnd=t.selectionEnd}this.updateTextareaPosition()}},updateFromTextArea:function(){if(this.hiddenTextarea){this.cursorOffsetCache={},this.text=this.hiddenTextarea.value,this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords());var t=this.fromStringToGraphemeSelection(this.hiddenTextarea.selectionStart,this.hiddenTextarea.selectionEnd,this.hiddenTextarea.value);this.selectionEnd=this.selectionStart=t.selectionEnd,this.inCompositionMode||(this.selectionStart=t.selectionStart),this.updateTextareaPosition()}},updateTextareaPosition:function(){if(this.selectionStart===this.selectionEnd){var t=this._calcTextareaPosition();this.hiddenTextarea.style.left=t.left,this.hiddenTextarea.style.top=t.top}},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var t=this.inCompositionMode?this.compositionStart:this.selectionStart,e=this._getCursorBoundaries(t),i=this.get2DCursorLocation(t),r=i.lineIndex,n=i.charIndex,s=this.getValueOfPropertyAt(r,n,"fontSize")*this.lineHeight,o=e.leftOffset,a=this.calcTransformMatrix(),c={x:e.left+o,y:e.top+e.topOffset+s},h=this.canvas.getRetinaScaling(),l=this.canvas.upperCanvasEl,u=l.width/h,f=l.height/h,d=u-s,g=f-s,p=l.clientWidth/u,v=l.clientHeight/f;return c=fabric.util.transformPoint(c,a),(c=fabric.util.transformPoint(c,this.canvas.viewportTransform)).x*=p,c.y*=v,c.x<0&&(c.x=0),c.x>d&&(c.x=d),c.y<0&&(c.y=0),c.y>g&&(c.y=g),c.x+=this.canvas._offset.left,c.y+=this.canvas._offset.top,{left:c.x+"px",top:c.y+"px",fontSize:s+"px",charHeight:s}},_saveEditingProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,selectable:this.selectable,defaultCursor:this.canvas&&this.canvas.defaultCursor,moveCursor:this.canvas&&this.canvas.moveCursor}},_restoreEditingProps:function(){this._savedProps&&(this.hoverCursor=this._savedProps.hoverCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,this.selectable=this._savedProps.selectable,this.lockMovementX=this._savedProps.lockMovementX,this.lockMovementY=this._savedProps.lockMovementY,this.canvas&&(this.canvas.defaultCursor=this._savedProps.defaultCursor,this.canvas.moveCursor=this._savedProps.moveCursor))},exitEditing:function(){var t=this._textBeforeEdit!==this.text,e=this.hiddenTextarea;return this.selected=!1,this.isEditing=!1,this.selectionEnd=this.selectionStart,e&&(e.blur&&e.blur(),e.parentNode&&e.parentNode.removeChild(e)),this.hiddenTextarea=null,this.abortCursorAnimation(),this._restoreEditingProps(),this._currentCursorOpacity=0,this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this.fire("editing:exited"),t&&this.fire("modified"),this.canvas&&(this.canvas.off("mouse:move",this.mouseMoveHandler),this.canvas.fire("text:editing:exited",{target:this}),t&&this.canvas.fire("object:modified",{target:this})),this},_removeExtraneousStyles:function(){for(var t in this.styles)this._textLines[t]||delete this.styles[t]},removeStyleFromTo:function(t,e){var i,r,n=this.get2DCursorLocation(t,!0),s=this.get2DCursorLocation(e,!0),o=n.lineIndex,a=n.charIndex,c=s.lineIndex,h=s.charIndex;if(o!==c){if(this.styles[o])for(i=a;it?this.selectionStart=t:this.selectionStart<0&&(this.selectionStart=0),this.selectionEnd>t?this.selectionEnd=t:this.selectionEnd<0&&(this.selectionEnd=0)}})}(),fabric.util.object.extend(fabric.IText.prototype,{initDoubleClickSimulation:function(){this.__lastClickTime=+new Date,this.__lastLastClickTime=+new Date,this.__lastPointer={},this.on("mousedown",this.onMouseDown)},onMouseDown:function(t){if(this.canvas){this.__newClickTime=+new Date;var e=t.pointer;this.isTripleClick(e)&&(this.fire("tripleclick",t),this._stopEvent(t.e)),this.__lastLastClickTime=this.__lastClickTime,this.__lastClickTime=this.__newClickTime,this.__lastPointer=e,this.__lastIsEditing=this.isEditing,this.__lastSelected=this.selected}},isTripleClick:function(t){return this.__newClickTime-this.__lastClickTime<500&&this.__lastClickTime-this.__lastLastClickTime<500&&this.__lastPointer.x===t.x&&this.__lastPointer.y===t.y},_stopEvent:function(t){t.preventDefault&&t.preventDefault(),t.stopPropagation&&t.stopPropagation()},initCursorSelectionHandlers:function(){this.initMousedownHandler(),this.initMouseupHandler(),this.initClicks()},doubleClickHandler:function(t){this.isEditing&&this.selectWord(this.getSelectionStartFromPointer(t.e))},tripleClickHandler:function(t){this.isEditing&&this.selectLine(this.getSelectionStartFromPointer(t.e))},initClicks:function(){this.on("mousedblclick",this.doubleClickHandler),this.on("tripleclick",this.tripleClickHandler)},_mouseDownHandler:function(t){!this.canvas||!this.editable||t.e.button&&1!==t.e.button||(this.__isMousedown=!0,this.selected&&(this.inCompositionMode=!1,this.setCursorByClick(t.e)),this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection()))},_mouseDownHandlerBefore:function(t){!this.canvas||!this.editable||t.e.button&&1!==t.e.button||(this.selected=this===this.canvas._activeObject)},initMousedownHandler:function(){this.on("mousedown",this._mouseDownHandler),this.on("mousedown:before",this._mouseDownHandlerBefore)},initMouseupHandler:function(){this.on("mouseup",this.mouseUpHandler)},mouseUpHandler:function(t){if(this.__isMousedown=!1,!(!this.editable||this.group||t.transform&&t.transform.actionPerformed||t.e.button&&1!==t.e.button)){if(this.canvas){var e=this.canvas._activeObject;if(e&&e!==this)return}this.__lastSelected&&!this.__corner?(this.selected=!1,this.__lastSelected=!1,this.enterEditing(t.e),this.selectionStart===this.selectionEnd?this.initDelayedCursor(!0):this.renderCursorOrSelection()):this.selected=!0}},setCursorByClick:function(t){var e=this.getSelectionStartFromPointer(t),i=this.selectionStart,r=this.selectionEnd;t.shiftKey?this.setSelectionStartEndWithShift(i,r,e):(this.selectionStart=e,this.selectionEnd=e),this.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(t){for(var e,i=this.getLocalPointer(t),r=0,n=0,s=0,o=0,a=0,c=0,h=this._textLines.length;cthis._text.length&&(a=this._text.length),a}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.setAttribute("autocorrect","off"),this.hiddenTextarea.setAttribute("autocomplete","off"),this.hiddenTextarea.setAttribute("spellcheck","false"),this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea",""),this.hiddenTextarea.setAttribute("wrap","off");var t=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+t.top+"; left: "+t.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; paddingーtop: "+t.fontSize+";",this.hiddenTextareaContainer?this.hiddenTextareaContainer.appendChild(this.hiddenTextarea):fabric.document.body.appendChild(this.hiddenTextarea),fabric.util.addListener(this.hiddenTextarea,"keydown",this.onKeyDown.bind(this)),fabric.util.addListener(this.hiddenTextarea,"keyup",this.onKeyUp.bind(this)),fabric.util.addListener(this.hiddenTextarea,"input",this.onInput.bind(this)),fabric.util.addListener(this.hiddenTextarea,"copy",this.copy.bind(this)),fabric.util.addListener(this.hiddenTextarea,"cut",this.copy.bind(this)),fabric.util.addListener(this.hiddenTextarea,"paste",this.paste.bind(this)),fabric.util.addListener(this.hiddenTextarea,"compositionstart",this.onCompositionStart.bind(this)),fabric.util.addListener(this.hiddenTextarea,"compositionupdate",this.onCompositionUpdate.bind(this)),fabric.util.addListener(this.hiddenTextarea,"compositionend",this.onCompositionEnd.bind(this)),!this._clickHandlerInitialized&&this.canvas&&(fabric.util.addListener(this.canvas.upperCanvasEl,"click",this.onClick.bind(this)),this._clickHandlerInitialized=!0)},keysMap:{9:"exitEditing",27:"exitEditing",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorRight",36:"moveCursorLeft",37:"moveCursorLeft",38:"moveCursorUp",39:"moveCursorRight",40:"moveCursorDown"},keysMapRtl:{9:"exitEditing",27:"exitEditing",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorLeft",36:"moveCursorRight",37:"moveCursorRight",38:"moveCursorUp",39:"moveCursorLeft",40:"moveCursorDown"},ctrlKeysMapUp:{67:"copy",88:"cut"},ctrlKeysMapDown:{65:"selectAll"},onClick:function(){this.hiddenTextarea&&this.hiddenTextarea.focus()},onKeyDown:function(t){if(this.isEditing){var e="rtl"===this.direction?this.keysMapRtl:this.keysMap;if(t.keyCode in e)this[e[t.keyCode]](t);else{if(!(t.keyCode in this.ctrlKeysMapDown&&(t.ctrlKey||t.metaKey)))return;this[this.ctrlKeysMapDown[t.keyCode]](t)}t.stopImmediatePropagation(),t.preventDefault(),33<=t.keyCode&&t.keyCode<=40?(this.inCompositionMode=!1,this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.requestRenderAll()}},onKeyUp:function(t){!this.isEditing||this._copyDone||this.inCompositionMode?this._copyDone=!1:t.keyCode in this.ctrlKeysMapUp&&(t.ctrlKey||t.metaKey)&&(this[this.ctrlKeysMapUp[t.keyCode]](t),t.stopImmediatePropagation(),t.preventDefault(),this.canvas&&this.canvas.requestRenderAll())},onInput:function(t){var e=this.fromPaste;if(this.fromPaste=!1,t&&t.stopPropagation(),this.isEditing){var i,r,n,s,o,a=this._splitTextIntoLines(this.hiddenTextarea.value).graphemeText,c=this._text.length,h=a.length,l=h-c,u=this.selectionStart,f=this.selectionEnd,d=u!==f;if(""===this.hiddenTextarea.value)return this.styles={},this.updateFromTextArea(),this.fire("changed"),void(this.canvas&&(this.canvas.fire("text:changed",{target:this}),this.canvas.requestRenderAll()));var g=this.fromStringToGraphemeSelection(this.hiddenTextarea.selectionStart,this.hiddenTextarea.selectionEnd,this.hiddenTextarea.value),p=u>g.selectionStart;d?(i=this._text.slice(u,f),l+=f-u):h=this._text.length&&this.selectionEnd>=this._text.length||this._moveCursorUpOrDown("Down",t)},moveCursorUp:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",t)},_moveCursorUpOrDown:function(t,e){var i=this["get"+t+"CursorOffset"](e,"right"===this._selectionDirection);e.shiftKey?this.moveCursorWithShift(i):this.moveCursorWithoutShift(i),0!==i&&(this.setSelectionInBoundaries(),this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(t){var e="left"===this._selectionDirection?this.selectionStart+t:this.selectionEnd+t;return this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,e),0!==t},moveCursorWithoutShift:function(t){return t<0?(this.selectionStart+=t,this.selectionEnd=this.selectionStart):(this.selectionEnd+=t,this.selectionStart=this.selectionEnd),0!==t},moveCursorLeft:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorLeftOrRight("Left",t)},_move:function(t,e,i){var r;if(t.altKey)r=this["findWordBoundary"+i](this[e]);else{if(!t.metaKey&&35!==t.keyCode&&36!==t.keyCode)return this[e]+="Left"===i?-1:1,!0;r=this["findLineBoundary"+i](this[e])}if(void 0!==typeof r&&this[e]!==r)return this[e]=r,!0},_moveLeft:function(t,e){return this._move(t,e,"Left")},_moveRight:function(t,e){return this._move(t,e,"Right")},moveCursorLeftWithoutShift:function(t){var e=!0;return this._selectionDirection="left",this.selectionEnd===this.selectionStart&&0!==this.selectionStart&&(e=this._moveLeft(t,"selectionStart")),this.selectionEnd=this.selectionStart,e},moveCursorLeftWithShift:function(t){return"right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveLeft(t,"selectionEnd"):0!==this.selectionStart?(this._selectionDirection="left",this._moveLeft(t,"selectionStart")):void 0},moveCursorRight:function(t){this.selectionStart>=this._text.length&&this.selectionEnd>=this._text.length||this._moveCursorLeftOrRight("Right",t)},_moveCursorLeftOrRight:function(t,e){var i="moveCursor"+t+"With";this._currentCursorOpacity=1,e.shiftKey?i+="Shift":i+="outShift",this[i](e)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(t){return"left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveRight(t,"selectionStart"):this.selectionEnd!==this._text.length?(this._selectionDirection="right",this._moveRight(t,"selectionEnd")):void 0},moveCursorRightWithoutShift:function(t){var e=!0;return this._selectionDirection="right",this.selectionStart===this.selectionEnd?(e=this._moveRight(t,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd,e},removeChars:function(t,e){void 0===e&&(e=t+1),this.removeStyleFromTo(t,e),this._text.splice(t,e-t),this.text=this._text.join(""),this.set("dirty",!0),this._shouldClearDimensionCache()&&(this.initDimensions(),this.setCoords()),this._removeExtraneousStyles()},insertChars:function(t,e,i,r){void 0===r&&(r=i),i",t.textSpans.join(""),"\n"]},_getSVGTextAndBg:function(t,e){var i,r=[],n=[],s=t;this._setSVGBg(n);for(var o=0,a=this._textLines.length;o",fabric.util.string.escapeXml(t),""].join("")},_setSVGTextLineText:function(t,e,i,r){var n,s,o,a,c,h=this.getHeightOfLine(e),l=-1!==this.textAlign.indexOf("justify"),u="",f=0,d=this._textLines[e];r+=h*(1-this._fontSizeFraction)/this.lineHeight;for(var g=0,p=d.length-1;g<=p;g++)c=g===p||this.charSpacing,u+=d[g],o=this.__charBounds[e][g],0===f?(i+=o.kernedWidth-o.width,f+=o.width):f+=o.kernedWidth,l&&!c&&this._reSpaceAndTab.test(d[g])&&(c=!0),c||(n=n||this.getCompleteStyleDeclaration(e,g),s=this.getCompleteStyleDeclaration(e,g+1),c=this._hasStyleChangedForSvg(n,s)),c&&(a=this._getStyleDeclaration(e,g)||{},t.push(this._createTextCharSpan(u,a,i,r)),u="",n=s,i+=f,f=0)},_pushTextBgRect:function(t,e,i,r,n,s){var o=fabric.Object.NUM_FRACTION_DIGITS;t.push("\t\t\n')},_setSVGTextLineBg:function(t,e,i,r){for(var n,s,o=this._textLines[e],a=this.getHeightOfLine(e)/this.lineHeight,c=0,h=0,l=this.getValueOfPropertyAt(e,0,"textBackgroundColor"),u=0,f=o.length;uthis.width&&this._set("width",this.dynamicMinWidth),-1!==this.textAlign.indexOf("justify")&&this.enlargeSpaces(),this.height=this.calcTextHeight(),this.saveState({propertySet:"_dimensionAffectingProps"}))},_generateStyleMap:function(t){for(var e=0,i=0,r=0,n={},s=0;sthis.dynamicMinWidth&&(this.dynamicMinWidth=g-v+r),o},isEndOfWrapping:function(t){return!this._styleMap[t+1]||this._styleMap[t+1].line!==this._styleMap[t].line},missingNewlineOffset:function(t){return this.splitByGrapheme?this.isEndOfWrapping(t)?1:0:1},_splitTextIntoLines:function(t){for(var e=b.Text.prototype._splitTextIntoLines.call(this,t),i=this._wrapText(e.lines,this.width),r=new Array(i.length),n=0;n", "contributors": [ {