diff --git a/CHANGELOG.md b/CHANGELOG.md index fa66dde0..64172d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,26 @@ +**Version 1.6.5** + +- Fix: charspacing, do not get subzero with charwidth. +- Improvement: add callback support to all object cloning. [#3212](https://github.com/kangax/fabric.js/pull/3212) +- Improvement: add backgroundColor to all classe [#3248](https://github.com/kangax/fabric.js/pull/3248) +- Fix: add custom properties to backgroundImage and overlayImage [#3250](https://github.com/kangax/fabric.js/pull/3250) +- Fix: Object intersection is calculated on boundingBox and boundingRect, intersection is fired if objects are overlapping [#3252](https://github.com/kangax/fabric.js/pull/3252) +- Change: Restored previous selection behaviour, added key to selection active object under overlaid target [#3254](https://github.com/kangax/fabric.js/pull/3254) +- Improvement: hasStateChanged let you find state changes of complex properties. [#3262](https://github.com/kangax/fabric.js/pull/3262) +- Fix: IText/Textbox shift click selection backward. [#3270](https://github.com/kangax/fabric.js/pull/3270) +- Revert: font family quoting was a bad idea. node-canvas stills use it. [#3276](https://github.com/kangax/fabric.js/pull/3276) +- Fix: fire mouse:over event for activeObject and activeGroup when using findTarget shourtcuts [#3285](https://github.com/kangax/fabric.js/pull/3285) +- Fix: clear method clear all properties of canvas [#3305](https://github.com/kangax/fabric.js/pull/3305) +- Fix: text area position method takes in account canvas offset [#3306](https://github.com/kangax/fabric.js/pull/3306) +- Improvement: Added event on right click and possibility to hide the context menu with a flag [3308](https://github.com/kangax/fabric.js/pull/3308) +- Fix: remove canvas reference from object when object gets removed from canvas [#3307](https://github.com/kangax/fabric.js/pull/3307) +- Improvement: use native stroke dash if available [#3309](https://github.com/kangax/fabric.js/pull/3309) +- Fix: Export correct src when exporting to svg [#3310](https://github.com/kangax/fabric.js/pull/3310) +- Fix: Stop text to go on zero dimensions [#3312](https://github.com/kangax/fabric.js/pull/3312) +- Fix: Error in dataURL with multiplier was outputting very big canvas with retina [#3314](https://github.com/kangax/fabric.js/pull/3314) +- Fix: Error in style map was not respecting style if textbox started with space [#3315](https://github.com/kangax/fabric.js/pull/3315) + + **Version 1.6.4** - Improvement: Ignore svg: namespace during svg import. [#3081](https://github.com/kangax/fabric.js/pull/3081) diff --git a/HEADER.js b/HEADER.js index c7b957a4..577cb842 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: "1.6.4" }; +var fabric = fabric || { version: "1.6.5" }; if (typeof exports !== 'undefined') { exports.fabric = fabric; } diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md index 69683198..2784f9d1 100644 --- a/ISSUE_TEMPLATE.md +++ b/ISSUE_TEMPLATE.md @@ -24,7 +24,7 @@ Remove the template from below and provide thoughtful commentary *and code sampl ## Version -1.6.2 +1.6.5 ## Test Case http://jsfiddle.net/fabricjs/Da7SP/ diff --git a/dist/fabric.js b/dist/fabric.js index 0efd6404..27bdd479 100644 --- a/dist/fabric.js +++ b/dist/fabric.js @@ -1,7 +1,7 @@ /* build: `node build.js modules=ALL exclude=json,gestures minifier=uglifyjs` */ /*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */ -var fabric = fabric || { version: "1.6.4" }; +var fabric = fabric || { version: "1.6.5" }; if (typeof exports !== 'undefined') { exports.fabric = fabric; } @@ -118,7 +118,7 @@ fabric.devicePixelRatio = fabric.window.devicePixelRatio || } else { if (!this.__eventListeners[eventName]) { - this.__eventListeners[eventName] = [ ]; + this.__eventListeners[eventName] = []; } this.__eventListeners[eventName].push(handler); } @@ -213,7 +213,9 @@ fabric.Collection = { _objects: [], /** - * Adds objects to collection, then renders canvas (if `renderOnAddRemove` is not `false`) + * Adds objects to collection, Canvas or Group, then renders canvas + * (if `renderOnAddRemove` is not `false`). + * in case of Group no changes to bounding box are made. * Objects should be instances of (or inherit from) fabric.Object * @param {...fabric.Object} object Zero or more fabric instances * @return {Self} thisArg @@ -602,10 +604,10 @@ fabric.Collection = { } var parts = namespace.split('.'), - len = parts.length, + len = parts.length, i, obj = global || fabric.window; - for (var i = 0; i < len; ++i) { + for (i = 0; i < len; ++i) { obj = obj[parts[i]]; } @@ -663,7 +665,7 @@ fabric.Collection = { * called after each fabric object created. */ enlivenObjects: function(objects, callback, namespace, reviver) { - objects = objects || [ ]; + objects = objects || []; function onLoaded() { if (++numLoadedObjects === numTotalObjects) { @@ -671,7 +673,7 @@ fabric.Collection = { } } - var enlivenedObjects = [ ], + var enlivenedObjects = [], numLoadedObjects = 0, numTotalObjects = objects.length; @@ -792,11 +794,11 @@ fabric.Collection = { */ createCanvasElement: function(canvasEl) { canvasEl || (canvasEl = fabric.document.createElement('canvas')); - //jscs:disable requireCamelCaseOrUpperCaseIdentifiers + /* eslint-disable camelcase */ if (!canvasEl.getContext && typeof G_vmlCanvasManager !== 'undefined') { G_vmlCanvasManager.initElement(canvasEl); } - //jscs:enable requireCamelCaseOrUpperCaseIdentifiers + /* eslint-enable camelcase */ return canvasEl; }, @@ -819,14 +821,15 @@ fabric.Collection = { * @param {Object} klass "Class" to create accessors for */ createAccessors: function(klass) { - var proto = klass.prototype; + var proto = klass.prototype, i, propName, + capitalizedPropName, setterName, getterName; - for (var i = proto.stateProperties.length; i--; ) { + for (i = proto.stateProperties.length; i--; ) { - var propName = proto.stateProperties[i], - capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1), - setterName = 'set' + capitalizedPropName, - getterName = 'get' + capitalizedPropName; + propName = proto.stateProperties[i]; + capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1); + setterName = 'set' + capitalizedPropName; + getterName = 'get' + capitalizedPropName; // using `new Function` for better introspection if (!proto[getterName]) { @@ -952,12 +955,13 @@ fabric.Collection = { } } - var _isTransparent = true, - imageData = ctx.getImageData(x, y, (tolerance * 2) || 1, (tolerance * 2) || 1); + var _isTransparent = true, i, temp, + imageData = ctx.getImageData(x, y, (tolerance * 2) || 1, (tolerance * 2) || 1), + l = imageData.data.length; // Split image data - for tolerance > 1, pixelDataSize = 4; - for (var i = 3, l = imageData.data.length; i < l; i += 4) { - var temp = imageData.data[i]; + for (i = 3; i < l; i += 4) { + temp = imageData.data[i]; _isTransparent = temp <= 0; if (_isTransparent === false) { break; // Stop if colour found @@ -1048,13 +1052,13 @@ fabric.Collection = { root = 0; if (pl < 0) { - var s = Math.sqrt(1 - pl/(rx2 * ry2)); + var s = Math.sqrt(1 - pl / (rx2 * ry2)); rx *= s; ry *= s; } else { root = (large === sweep ? -1.0 : 1.0) * - Math.sqrt( pl /(rx2 * py2 + ry2 * px2)); + Math.sqrt( pl / (rx2 * py2 + ry2 * px2)); } var cx = root * rx * py / ry, @@ -1100,8 +1104,8 @@ fabric.Collection = { sinth3 = Math.sin(th3), toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1, toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1, - cp1X = fromX + mT * ( - cosTh * rx * sinth2 - sinTh * ry * costh2), - cp1Y = fromY + mT * ( - sinTh * rx * sinth2 + cosTh * ry * costh2), + cp1X = fromX + mT * ( -cosTh * rx * sinth2 - sinTh * ry * costh2), + cp1Y = fromY + mT * ( -sinTh * rx * sinth2 + cosTh * ry * costh2), cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3), cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3); @@ -1142,7 +1146,7 @@ fabric.Collection = { sweep = coords[4], tx = coords[5], ty = coords[6], - segs = [[ ], [ ], [ ], [ ]], + segs = [[], [], [], []], segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot); for (var i = 0, len = segsNorm.length; i < len; i++) { @@ -1170,9 +1174,9 @@ fabric.Collection = { */ fabric.util.getBoundsOfArc = function(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), - boundCopy = [[ ], [ ]]; + var fromX = 0, fromY = 0, bound = [], bounds = [], + segs = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot), + boundCopy = [[], []]; for (var i = 0, len = segs.length; i < len; i++) { bound = getBoundsOfCurve(fromX, fromY, segs[i][0], segs[i][1], segs[i][2], segs[i][3], segs[i][4], segs[i][5]); @@ -1208,8 +1212,8 @@ fabric.Collection = { var sqrt = Math.sqrt, min = Math.min, max = Math.max, - abs = Math.abs, tvalues = [ ], - bounds = [[ ], [ ]], + abs = Math.abs, tvalues = [], + bounds = [[], []], a, b, c, t, t1, t2, b2ac, sqrtb2ac; b = 6 * x0 - 12 * x1 + 6 * x2; @@ -1349,7 +1353,7 @@ fabric.Collection = { * @return {Array} */ Array.prototype.map = function(fn, context) { - var result = [ ]; + var result = []; for (var i = 0, len = this.length >>> 0; i < len; i++) { if (i in this) { result[i] = fn.call(context, this[i], i, this); @@ -1401,7 +1405,7 @@ fabric.Collection = { * @return {Array} */ Array.prototype.filter = function(fn, context) { - var result = [ ], val; + var result = [], val; for (var i = 0, len = this.length >>> 0; i < len; i++) { if (i in this) { val = this[i]; // in case fn mutates this @@ -1460,7 +1464,7 @@ fabric.Collection = { * @return {Array} */ function invoke(array, method) { - var args = slice.call(arguments, 2), result = [ ]; + var args = slice.call(arguments, 2), result = []; for (var i = 0, len = array.length; i < len; i++) { result[i] = args.length ? array[i][method].apply(array[i], args) : array[i][method].call(array[i]); } @@ -1553,10 +1557,30 @@ fabric.Collection = { * @param {Object} source Where to copy from * @return {Object} */ - function extend(destination, source) { + function extend(destination, source, deep) { // JScript DontEnum bug is not taken care of - for (var property in source) { - destination[property] = source[property]; + // the deep clone is for internal use, is not meant to avoid + // javascript traps or cloning html element or self referenced objects. + if (deep) { + if (source instanceof Array) { + destination = source.map(function(v) { + return clone(v, deep) + }) + } + else if (source instanceof Object) { + for (var property in source) { + destination[property] = clone(source[property], deep) + } + } + else { + // this sounds odd for an extend but is ok for recursive use + destination = source; + } + } + else { + for (var property in source) { + destination[property] = source[property]; + } } return destination; } @@ -1567,8 +1591,8 @@ fabric.Collection = { * @param {Object} object Object to clone * @return {Object} */ - function clone(object) { - return extend({ }, object); + function clone(object, deep) { + return extend({ }, object, deep); } /** @namespace fabric.util.object */ @@ -1645,7 +1669,7 @@ fabric.Collection = { capitalize: capitalize, escapeXml: escapeXml }; -}()); +})(); /* _ES5_COMPAT_START_ */ @@ -1765,7 +1789,7 @@ fabric.Collection = { } klass.superclass = parent; - klass.subclasses = [ ]; + klass.subclasses = []; if (parent) { Subclass.prototype = parent.prototype; @@ -1887,7 +1911,7 @@ fabric.Collection = { listeners[uid] = { }; } if (!listeners[uid][eventName]) { - listeners[uid][eventName] = [ ]; + listeners[uid][eventName] = []; } var listener = createListener(uid, handler); @@ -1916,7 +1940,7 @@ fabric.Collection = { handlers[uid] = { }; } if (!handlers[uid][eventName]) { - handlers[uid][eventName] = [ ]; + handlers[uid][eventName] = []; var existingHandler = element['on' + eventName]; if (existingHandler) { handlers[uid][eventName].push(existingHandler); @@ -1982,12 +2006,12 @@ fabric.Collection = { // looks like in IE (<9) clientX at certain point (apparently when mouseup fires on VML element) // is represented as COM object, with all the consequences, like "unknown" type and error on [[Get]] // need to investigate later - return (typeof event.clientX !== unknown ? event.clientX : 0); - }, + return (typeof event.clientX !== unknown ? event.clientX : 0); + }, - pointerY = function(event) { - return (typeof event.clientY !== unknown ? event.clientY : 0); - }; + pointerY = function(event) { + return (typeof event.clientY !== unknown ? event.clientY : 0); + }; function _getPointer(event, pageProp, clientProp) { var touchProp = event.type === 'touchend' ? 'changedTouches' : 'touches'; @@ -2475,7 +2499,7 @@ fabric.log = function() { }; */ fabric.warn = function() { }; -/* jshint ignore:start */ +/* eslint-disable */ if (typeof console !== 'undefined') { ['log', 'warn'].forEach(function(methodName) { @@ -2489,7 +2513,7 @@ if (typeof console !== 'undefined') { } }); } -/* jshint ignore:end */ +/* eslint-enable */ (function() { @@ -2605,7 +2629,7 @@ if (typeof console !== 'undefined') { * @memberOf fabric.util.ease */ function easeInOutCubic(t, b, c, d) { - t /= d/2; + t /= d / 2; if (t < 1) { return c / 2 * t * t * t + b; } @@ -2871,10 +2895,10 @@ if (typeof console !== 'undefined') { if ((t /= d) < (1 / 2.75)) { return c * (7.5625 * t * t) + b; } - else if (t < (2/2.75)) { + else if (t < (2 / 2.75)) { return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b; } - else if (t < (2.5/2.75)) { + else if (t < (2.5 / 2.75)) { return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b; } else { @@ -2964,7 +2988,7 @@ if (typeof console !== 'undefined') { easeInOutBounce: easeInOutBounce }; -}()); +})(); (function(global) { @@ -3100,7 +3124,7 @@ if (typeof console !== 'undefined') { * @private */ function _getMultipleNodes(doc, nodeNames) { - var nodeName, nodeArray = [ ], nodeList; + var nodeName, nodeArray = [], nodeList; for (var i = 0; i < nodeNames.length; i++) { nodeName = nodeNames[i]; nodeList = doc.getElementsByTagName(nodeName); @@ -3215,7 +3239,7 @@ if (typeof console !== 'undefined') { // start with identity matrix var matrix = iMatrix.concat(), - matrices = [ ]; + matrices = []; // return if no argument was given or // an argument does not match transform attribute regexp @@ -3226,7 +3250,8 @@ if (typeof console !== 'undefined') { attributeValue.replace(reTransform, function(match) { var m = new RegExp(transform).exec(match).filter(function (match) { - return (match !== '' && match != null); + // match !== '' && match != null + return (!!match); }), operation = m[1], args = m.slice(2).map(parseFloat); @@ -3406,7 +3431,8 @@ if (typeof console !== 'undefined') { attr = attrs.item(j); el3.setAttribute(attr.nodeName, attr.nodeValue); } - while (el2.firstChild != null) { + // el2.firstChild != null + while (el2.firstChild) { el3.appendChild(el2.firstChild); } el2 = el3; @@ -3485,9 +3511,9 @@ if (typeof console !== 'undefined') { return parsedDim; } - minX = -parseFloat(viewBoxAttr[1]), - minY = -parseFloat(viewBoxAttr[2]), - viewBoxWidth = parseFloat(viewBoxAttr[3]), + minX = -parseFloat(viewBoxAttr[1]); + minY = -parseFloat(viewBoxAttr[2]); + viewBoxWidth = parseFloat(viewBoxAttr[3]); viewBoxHeight = parseFloat(viewBoxAttr[4]); if (!missingDimAttr) { @@ -3525,7 +3551,8 @@ if (typeof console !== 'undefined') { if (element.nodeName === 'svg') { el = element.ownerDocument.createElement('g'); - while (element.firstChild != null) { + // element.firstChild != null + while (element.firstChild) { el.appendChild(element.firstChild); } element.appendChild(el); @@ -3545,7 +3572,8 @@ if (typeof console !== 'undefined') { * @function * @memberOf fabric * @param {SVGDocument} doc SVG document to parse - * @param {Function} callback Callback to call when parsing is finished; It's being passed an array of elements (parsed from a document). + * @param {Function} callback Callback to call when parsing is finished; + * It's being passed an array of elements (parsed from a document). * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created. */ fabric.parseSVGDocument = (function() { @@ -3578,7 +3606,7 @@ if (typeof console !== 'undefined') { // we're likely in node, where "o3-xml" library fails to gEBTN("*") // https://github.com/ajaxorg/node-o3-xml/issues/21 descendants = doc.selectNodes('//*[name(.)!="svg"]'); - var arr = [ ]; + var arr = []; for (var i = 0, len = descendants.length; i < len; i++) { arr[i] = descendants[i]; } @@ -3857,11 +3885,11 @@ if (typeof console !== 'undefined') { points = points.replace(/,/g, ' ').trim(); points = points.split(/\s+/); - var parsedPoints = [ ], i, len; + var parsedPoints = [], i, len; i = 0; len = points.length; - for (; i < len; i+=2) { + for (; i < len; i += 2) { parsedPoints.push({ x: parseFloat(points[i]), y: parseFloat(points[i + 1]) @@ -3903,8 +3931,8 @@ if (typeof console !== 'undefined') { rules.forEach(function(rule) { var match = rule.match(/([\s\S]*?)\s*\{([^}]*)\}/), - ruleObj = { }, declaration = match[2].trim(), - propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/); + ruleObj = { }, declaration = match[2].trim(), + propertyValuePairs = declaration.replace(/;$/, '').split(/\s*;\s*/); for (var i = 0, len = propertyValuePairs.length; i < len; i++) { var pair = propertyValuePairs[i].split(/\s*:\s*/), @@ -3931,7 +3959,8 @@ if (typeof console !== 'undefined') { }, /** - * Takes url corresponding to an SVG document, and parses it into a set of fabric objects. Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy) + * Takes url corresponding to an SVG document, and parses it into a set of fabric objects. + * Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy) * @memberOf fabric * @param {String} url * @param {Function} callback @@ -4043,24 +4072,20 @@ if (typeof console !== 'undefined') { for (var j in fontList) { markup += [ - //jscs:disable validateIndentation '\t\t@font-face {\n', - '\t\t\tfont-family: \'', j, '\';\n', - '\t\t\tsrc: url(\'', fontPaths[j], '\');\n', + '\t\t\tfont-family: \'', j, '\';\n', + '\t\t\tsrc: url(\'', fontPaths[j], '\');\n', '\t\t}\n' - //jscs:enable validateIndentation ].join(''); } if (markup) { markup = [ - //jscs:disable validateIndentation '\t\n' - //jscs:enable validateIndentation ].join(''); } @@ -4073,7 +4098,7 @@ if (typeof console !== 'undefined') { * @return {String} */ createSVGRefElementsMarkup: function(canvas) { - var markup = [ ]; + var markup = []; _createSVGPattern(markup, canvas, 'backgroundColor'); _createSVGPattern(markup, canvas, 'overlayColor'); @@ -4103,9 +4128,9 @@ fabric.ElementsParser.prototype.parse = function() { fabric.ElementsParser.prototype.createObjects = function() { for (var i = 0, len = this.elements.length; i < len; i++) { this.elements[i].setAttribute('svgUid', this.svgUid); - (function(_this, i) { + (function(_obj, i) { setTimeout(function() { - _this.createObject(_this.elements[i], i); + _obj.createObject(_obj.elements[i], i); }, 0); })(this, i); } @@ -4167,6 +4192,7 @@ fabric.ElementsParser.prototype.resolveGradient = function(obj, property) { fabric.ElementsParser.prototype.checkIfDone = function() { if (--this.numElements === 0) { this.instances = this.instances.filter(function(el) { + // eslint-disable-next-line no-eq-null, eqeqeq return el != null; }); this.callback(this.instances); @@ -4618,8 +4644,8 @@ fabric.ElementsParser.prototype.checkIfDone = function() { b1, b2, inter; for (var i = 0; i < length; i++) { - b1 = points[i], - b2 = points[(i + 1) % length], + b1 = points[i]; + b2 = points[(i + 1) % length]; inter = Intersection.intersectLineLine(a1, a2, b1, b2); result.appendPoints(inter.points); @@ -4763,7 +4789,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() { * @return {Array} Hsl color */ _rgbToHsl: function(r, g, b) { - r /= 255, g /= 255, b /= 255; + r /= 255; g /= 255; b /= 255; var h, s, l, max = fabric.util.array.max([r, g, b]), @@ -4954,6 +4980,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() { * @field * @memberOf fabric.Color */ + // eslint-disable-next-line max-len fabric.Color.reRGBa = /^rgba?\(\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*,\s*(\d{1,3}(?:\.\d+)?\%?)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/; /** @@ -5014,14 +5041,14 @@ fabric.ElementsParser.prototype.checkIfDone = function() { if (t > 1) { t -= 1; } - if (t < 1/6) { + if (t < 1 / 6) { return p + (q - p) * 6 * t; } - if (t < 1/2) { + if (t < 1 / 2) { return q; } - if (t < 2/3) { - return p + (q - p) * (2/3 - t) * 6; + if (t < 2 / 3) { + return p + (q - p) * (2 / 3 - t) * 6; } return p; } @@ -5104,9 +5131,9 @@ fabric.ElementsParser.prototype.checkIfDone = function() { var q = l <= 0.5 ? l * (s + 1) : l + s - l * s, p = l * 2 - q; - r = hue2rgb(p, q, h + 1/3); + r = hue2rgb(p, q, h + 1 / 3); g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1/3); + b = hue2rgb(p, q, h - 1 / 3); } return [ @@ -5373,41 +5400,35 @@ fabric.ElementsParser.prototype.checkIfDone = function() { } if (this.type === 'linear') { markup = [ - //jscs:disable validateIndentation '\n' - //jscs:enable validateIndentation ]; } else if (this.type === 'radial') { markup = [ - //jscs:disable validateIndentation '\n' - //jscs:enable validateIndentation ]; } for (var i = 0; i < this.colorStops.length; i++) { markup.push( - //jscs:disable validateIndentation '\n' - //jscs:enable validateIndentation ); } @@ -5603,7 +5624,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() { gradientUnits === 'objectBoundingBox' && object.rx !== object.ry) { - var scaleFactor = object.ry/object.rx; + var scaleFactor = object.ry / object.rx; ellipseMatrix = ' scale(1, ' + scaleFactor + ')'; if (options.y1) { options.y1 /= scaleFactor; @@ -5872,7 +5893,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ */ _parseShadow: function(shadow) { var shadowStr = shadow.trim(), - offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [ ], + offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [], color = shadowStr.replace(fabric.Shadow.reOffsetsAndBlur, '') || 'rgb(0,0,0)'; return { @@ -5966,6 +5987,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ * @field * @memberOf fabric.Shadow */ + // eslint-disable-next-line max-len fabric.Shadow.reOffsetsAndBlur = /(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/; })(typeof exports !== 'undefined' ? exports : this); @@ -6152,7 +6174,6 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ this._createLowerCanvas(el); this._initOptions(options); this._setImageSmoothing(); - // only initialize retina scaling once if (!this.interactive) { this._initRetinaScaling(); @@ -6195,7 +6216,6 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ if (!this._isRetinaScaling()) { return; } - this.lowerCanvasEl.setAttribute('width', this.width * fabric.devicePixelRatio); this.lowerCanvasEl.setAttribute('height', this.height * fabric.devicePixelRatio); @@ -6432,28 +6452,18 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ /** * @private */ - _createCanvasElement: function() { - var element = fabric.document.createElement('canvas'); + _createCanvasElement: function(canvasEl) { + var element = fabric.util.createCanvasElement(canvasEl) if (!element.style) { element.style = { }; } if (!element) { throw CANVAS_INIT_ERROR; } - this._initCanvasElement(element); - return element; - }, - - /** - * @private - * @param {HTMLElement} element - */ - _initCanvasElement: function(element) { - fabric.util.createCanvasElement(element); - if (typeof element.getContext === 'undefined') { throw CANVAS_INIT_ERROR; } + return element; }, /** @@ -6487,8 +6497,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ * @param {HTMLElement} [canvasEl] */ _createLowerCanvas: function (canvasEl) { - this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement(); - this._initCanvasElement(this.lowerCanvasEl); + this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement(canvasEl); fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas'); @@ -6641,10 +6650,11 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ * @chainable true */ setViewportTransform: function (vpt) { - var activeGroup = this.getActiveGroup(); + var activeGroup = this._activeGroup, object; this.viewportTransform = vpt; for (var i = 0, len = this._objects.length; i < len; i++) { - this._objects[i].setCoords(); + object = this._objects[i]; + object.group || object.setCoords(); } if (activeGroup) { activeGroup.setCoords(); @@ -6717,22 +6727,6 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ return this.lowerCanvasEl; }, - /** - * Returns currently selected object, if any - * @return {fabric.Object} - */ - getActiveObject: function() { - return null; - }, - - /** - * Returns currently selected group of object, if any - * @return {fabric.Group} - */ - getActiveGroup: function() { - return null; - }, - /** * @private * @param {fabric.Object} obj Object that was added @@ -6752,6 +6746,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ _onObjectRemoved: function(obj) { this.fire('object:removed', { target: obj }); obj.fire('removed'); + delete obj.canvas; }, /** @@ -6780,6 +6775,10 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ */ clear: function () { this._objects.length = 0; + this.backgroundImage = null; + this.overlayImage = null; + this.backgroundColor = ''; + this.overlayColor = '' this.clearContext(this.contextContainer); this.fire('canvas:cleared'); this.renderAll(); @@ -6830,14 +6829,6 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ this.fire('after:render'); }, - /** - * dummy function for organization purpouse. - * @private - */ - drawControls: function() { - // NOOP - }, - /** * @private * @param {CanvasRenderingContext2D} ctx Context to render on @@ -7039,7 +7030,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ objects: this._toObjects(methodName, propertiesToInclude) }; - extend(data, this.__serializeBgOverlay()); + extend(data, this.__serializeBgOverlay(propertiesToInclude)); fabric.util.populateWithProperties(this, data, propertiesToInclude); @@ -7051,10 +7042,10 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ */ _toObjects: function(methodName, propertiesToInclude) { return this.getObjects().filter(function(object) { - return !object.excludeFromExport; - }).map(function(instance) { - return this._toObject(instance, methodName, propertiesToInclude); - }, this); + return !object.excludeFromExport; + }).map(function(instance) { + return this._toObject(instance, methodName, propertiesToInclude); + }, this); }, /** @@ -7068,76 +7059,33 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ instance.includeDefaultValues = false; } - //If the object is part of the current selection group, it should - //be transformed appropriately - //i.e. it should be serialised as it would appear if the selection group - //were to be destroyed. - var originalProperties = this._realizeGroupTransformOnObject(instance), - object = instance[methodName](propertiesToInclude); + var object = instance[methodName](propertiesToInclude); if (!this.includeDefaultValues) { instance.includeDefaultValues = originalValue; } - - //Undo the damage we did by changing all of its properties - this._unwindGroupTransformOnObject(instance, originalProperties); - return object; }, - /** - * Realises an object's group transformation on it - * @private - * @param {fabric.Object} [instance] the object to transform (gets mutated) - * @returns the original values of instance which were changed - */ - _realizeGroupTransformOnObject: function(instance) { - var layoutProps = ['angle', 'flipX', 'flipY', 'height', 'left', 'scaleX', 'scaleY', 'top', 'width']; - if (instance.group && instance.group === this.getActiveGroup()) { - //Copy all the positionally relevant properties across now - var originalValues = {}; - layoutProps.forEach(function(prop) { - originalValues[prop] = instance[prop]; - }); - this.getActiveGroup().realizeTransform(instance); - return originalValues; - } - else { - return null; - } - }, - - /** - * Restores the changed properties of instance - * @private - * @param {fabric.Object} [instance] the object to un-transform (gets mutated) - * @param {Object} [originalValues] the original values of instance, as returned by _realizeGroupTransformOnObject - */ - _unwindGroupTransformOnObject: function(instance, originalValues) { - if (originalValues) { - instance.set(originalValues); - } - }, - /** * @private */ - __serializeBgOverlay: function() { + __serializeBgOverlay: function(propertiesToInclude) { var data = { background: (this.backgroundColor && this.backgroundColor.toObject) - ? this.backgroundColor.toObject() + ? this.backgroundColor.toObject(propertiesToInclude) : this.backgroundColor }; if (this.overlayColor) { data.overlay = this.overlayColor.toObject - ? this.overlayColor.toObject() + ? this.overlayColor.toObject(propertiesToInclude) : this.overlayColor; } if (this.backgroundImage) { - data.backgroundImage = this.backgroundImage.toObject(); + data.backgroundImage = this.backgroundImage.toObject(propertiesToInclude); } if (this.overlayImage) { - data.overlayImage = this.overlayImage.toObject(); + data.overlayImage = this.overlayImage.toObject(propertiesToInclude); } return data; @@ -7275,20 +7223,24 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ * @private */ _setSVGObjects: function(markup, reviver) { - var instance, originalProperties; + var instance; for (var i = 0, objects = this.getObjects(), len = objects.length; i < len; i++) { instance = objects[i]; if (instance.excludeFromExport) { continue; } - //If the object is in a selection group, simulate what would happen to that - //object when the group is deselected - originalProperties = this._realizeGroupTransformOnObject(instance); - markup.push(instance.toSVG(reviver)); - this._unwindGroupTransformOnObject(instance, originalProperties); + this._setSVGObject(markup, instance, reviver); } }, + /** + * push single object svg representation in the markup + * @private + */ + _setSVGObject: function(markup, instance, reviver) { + markup.push(instance.toSVG(reviver)); + }, + /** * @private */ @@ -7340,7 +7292,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, + var activeGroup = this._activeGroup, i, obj, objs; if (object === activeGroup) { objs = activeGroup._objects; @@ -7368,7 +7320,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, + var activeGroup = this._activeGroup, i, obj, objs; if (object === activeGroup) { objs = activeGroup._objects; @@ -7396,7 +7348,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, + var activeGroup = this._activeGroup, i, obj, idx, newIdx, objs; if (object === activeGroup) { @@ -7464,7 +7416,7 @@ fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, + var activeGroup = this._activeGroup, i, obj, idx, newIdx, objs; if (object === activeGroup) { @@ -7645,14 +7597,14 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype * @type String * @default */ - color: 'rgb(0, 0, 0)', + color: 'rgb(0, 0, 0)', /** * Width of a brush * @type Number * @default */ - width: 1, + width: 1, /** * Shadow object representing shadow of this shape. @@ -7661,28 +7613,28 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype * @type fabric.Shadow * @default */ - shadow: null, + shadow: null, /** * Line endings style of a brush (one of "butt", "round", "square") * @type String * @default */ - strokeLineCap: 'round', + strokeLineCap: 'round', /** * Corner style of a brush (one of "bevil", "round", "miter") * @type String * @default */ - strokeLineJoin: 'round', + strokeLineJoin: 'round', /** * Stroke Dash Array. * @type Array * @default */ - strokeDashArray: null, + strokeDashArray: null, /** * Sets shadow of an object @@ -7757,7 +7709,7 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ initialize: function(canvas) { this.canvas = canvas; - this._points = [ ]; + this._points = []; }, /** @@ -7907,15 +7859,15 @@ fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ createPath: function(pathData) { var path = new fabric.Path(pathData, { - fill: null, - stroke: this.color, - strokeWidth: this.width, - strokeLineCap: this.strokeLineCap, - strokeLineJoin: this.strokeLineJoin, - strokeDashArray: this.strokeDashArray, - originX: 'center', - originY: 'center' - }); + fill: null, + stroke: this.color, + strokeWidth: this.width, + strokeLineCap: this.strokeLineCap, + strokeLineJoin: this.strokeLineJoin, + strokeDashArray: this.strokeDashArray, + originX: 'center', + originY: 'center' + }); if (this.shadow) { this.shadow.affectStroke = true; @@ -7980,7 +7932,7 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric */ initialize: function(canvas) { this.canvas = canvas; - this.points = [ ]; + this.points = []; }, /** @@ -8028,7 +7980,7 @@ fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric var originalRenderOnAddRemove = this.canvas.renderOnAddRemove; this.canvas.renderOnAddRemove = false; - var circles = [ ]; + var circles = []; for (var i = 0, len = this.points.length; i < len; i++) { var point = this.points[i], @@ -8136,7 +8088,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric */ initialize: function(canvas) { this.canvas = canvas; - this.sprayChunks = [ ]; + this.sprayChunks = []; }, /** @@ -8168,7 +8120,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric var originalRenderOnAddRemove = this.canvas.renderOnAddRemove; this.canvas.renderOnAddRemove = false; - var rects = [ ]; + var rects = []; for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) { var sprayChunk = this.sprayChunks[i]; @@ -8221,7 +8173,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric uniqueRects[key] = rects[i]; } } - var uniqueRectsArray = [ ]; + var uniqueRectsArray = []; for (key in uniqueRects) { uniqueRectsArray.push(uniqueRects[key]); } @@ -8254,7 +8206,7 @@ fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric * @param {Object} pointer */ addSprayChunk: function(pointer) { - this.sprayChunkPoints = [ ]; + this.sprayChunkPoints = []; var x, y, width, radius = this.width / 2; @@ -8356,6 +8308,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab radiansToDegrees = fabric.util.radiansToDegrees, atan2 = Math.atan2, abs = Math.abs, + supportLineDash = fabric.StaticCanvas.supports('setLineDash'), STROKE_OFFSET = 0.5; @@ -8469,13 +8422,23 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab /** * Indicates which key enable multiple click selection - * values: altKey, shiftKey, ctrlKey + * values: altKey, shiftKey, ctrlKey, cmdKey * @since 1.6.2 * @type String * @default */ selectionKey: 'shiftKey', + /** + * Indicates which key enable alternative selection + * in case of target overlapping with active object + * values: altKey, shiftKey, ctrlKey, cmdKey + * @since 1.6.5 + * @type null|String + * @default + */ + altSelectionKey: null, + /** * Color of selection * @type String @@ -8488,7 +8451,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab * If not empty the selection border is dashed * @type Array */ - selectionDashArray: [ ], + selectionDashArray: [], /** * Color of the border of selection (usually slightly darker than color of selection itself) @@ -8578,12 +8541,29 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab isDrawingMode: false, /** - * Indicates whether objects should remain in current stack position when selected. When false objects are brought to top and rendered as part of the selection group + * Indicates whether objects should remain in current stack position when selected. + * When false objects are brought to top and rendered as part of the selection group * @type Boolean * @default */ preserveObjectStacking: false, + /** + * Indicates if the right click on canvas can output the context menu or not + * @type Boolean + * @since 1.6.5 + * @default + */ + stopContextMenu: false, + + /** + * Indicates if the canvas can fire right click events + * @type Boolean + * @since 1.6.5 + * @default + */ + fireRightClick: false, + /** * @private */ @@ -8609,7 +8589,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab _chooseObjectsToRender: function() { var activeGroup = this.getActiveGroup(), activeObject = this.getActiveObject(), - object, objsToRender = [ ], activeGroupObjects = [ ]; + object, objsToRender = [], activeGroupObjects = []; if ((activeGroup || activeObject) && !this.preserveObjectStacking) { for (var i = 0, length = this._objects.length; i < length; i++) { @@ -8748,7 +8728,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab vptPointer = this.restorePointerVpt(pointer), p = fabric.util.transformPoint(vptPointer, invertedM); return fabric.util.transformPoint(p, vpt); - //return { x: p.x * vpt[0], y: p.y * vpt[3] }; }, /** @@ -9018,8 +8997,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab actualMouseByOrigin, constraintPosition, dim = target._getTransformedDimensions(); this._changeSkewTransformOrigin(actualMouseByCenter - lastMouseByCenter, t, by); - actualMouseByOrigin = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY)[by], - + actualMouseByOrigin = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY)[by]; constraintPosition = target.translateToOriginPoint(center, t.originX, t.originY); // Actually skew the object skewed = this._setObjectSkew(actualMouseByOrigin, t, by, dim); @@ -9306,23 +9284,28 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab aleft = abs(left), atop = abs(top); - ctx.fillStyle = this.selectionColor; + if (this.selectionColor) { + ctx.fillStyle = this.selectionColor; - ctx.fillRect( - groupSelector.ex - ((left > 0) ? 0 : -left), - groupSelector.ey - ((top > 0) ? 0 : -top), - aleft, - atop - ); + ctx.fillRect( + groupSelector.ex - ((left > 0) ? 0 : -left), + groupSelector.ey - ((top > 0) ? 0 : -top), + aleft, + atop + ); + } + if (!this.selectionLineWidth || !this.selectionBorderColor) { + return; + } ctx.lineWidth = this.selectionLineWidth; ctx.strokeStyle = this.selectionBorderColor; // selection border - if (this.selectionDashArray.length > 1) { + if (this.selectionDashArray.length > 1 && !supportLineDash) { - var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0: aleft), - py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0: atop); + var px = groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft), + py = groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop); ctx.beginPath(); @@ -9335,6 +9318,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab ctx.stroke(); } else { + fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray); ctx.strokeRect( groupSelector.ex + STROKE_OFFSET - ((left > 0) ? 0 : aleft), groupSelector.ey + STROKE_OFFSET - ((top > 0) ? 0 : atop), @@ -9357,22 +9341,37 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab var ignoreZoom = true, pointer = this.getPointer(e, ignoreZoom), activeGroup = this.getActiveGroup(), - activeObject = this.getActiveObject(); + activeObject = this.getActiveObject(), + activeTarget; // first check current group (if one exists) // active group does not check sub targets like normal groups. // if active group just exits. if (activeGroup && !skipGroup && this._checkTarget(pointer, activeGroup)) { + this._fireOverOutEvents(activeGroup, e); return activeGroup; } - - if (activeObject && this._checkTarget(pointer, activeObject)) { + // if we hit the corner of an activeObject, let's return that. + if (activeObject && activeObject._findTargetCorner(pointer)) { + this._fireOverOutEvents(activeObject, e); return activeObject; } + if (activeObject && this._checkTarget(pointer, activeObject)) { + if (!this.preserveObjectStacking) { + this._fireOverOutEvents(activeObject, e); + return activeObject; + } + else { + activeTarget = activeObject; + } + } - this.targets = [ ]; + this.targets = []; var target = this._searchPossibleTargets(this._objects, pointer); + if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) { + target = activeTarget; + } this._fireOverOutEvents(target, e); return target; }, @@ -9820,6 +9819,66 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab } }, + /** + * @private + */ + _toObject: function(instance, methodName, propertiesToInclude) { + //If the object is part of the current selection group, it should + //be transformed appropriately + //i.e. it should be serialised as it would appear if the selection group + //were to be destroyed. + var originalProperties = this._realizeGroupTransformOnObject(instance), + object = this.callSuper('_toObject', instance, methodName, propertiesToInclude); + //Undo the damage we did by changing all of its properties + this._unwindGroupTransformOnObject(instance, originalProperties); + return object; + }, + + /** + * Realises an object's group transformation on it + * @private + * @param {fabric.Object} [instance] the object to transform (gets mutated) + * @returns the original values of instance which were changed + */ + _realizeGroupTransformOnObject: function(instance) { + var layoutProps = ['angle', 'flipX', 'flipY', 'height', 'left', 'scaleX', 'scaleY', 'top', 'width']; + if (instance.group && instance.group === this.getActiveGroup()) { + //Copy all the positionally relevant properties across now + var originalValues = {}; + layoutProps.forEach(function(prop) { + originalValues[prop] = instance[prop]; + }); + this.getActiveGroup().realizeTransform(instance); + return originalValues; + } + else { + return null; + } + }, + + /** + * Restores the changed properties of instance + * @private + * @param {fabric.Object} [instance] the object to un-transform (gets mutated) + * @param {Object} [originalValues] the original values of instance, as returned by _realizeGroupTransformOnObject + */ + _unwindGroupTransformOnObject: function(instance, originalValues) { + if (originalValues) { + instance.set(originalValues); + } + }, + + /** + * @private + */ + _setSVGObject: function(markup, instance, reviver) { + var originalProperties; + //If the object is in a selection group, simulate what would happen to that + //object when the group is deselected + originalProperties = this._realizeGroupTransformOnObject(instance); + this.callSuper('_setSVGObject', markup, instance, reviver); + this._unwindGroupTransformOnObject(instance, originalProperties); + }, }); // copying static properties manually to work around Opera's bug, @@ -9849,17 +9908,17 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab (function() { var cursorOffset = { - mt: 0, // n - tr: 1, // ne - mr: 2, // e - br: 3, // se - mb: 4, // s - bl: 5, // sw - ml: 6, // w - tl: 7 // nw - }, - addListener = fabric.util.addListener, - removeListener = fabric.util.removeListener; + mt: 0, // n + tr: 1, // ne + mr: 2, // e + br: 3, // se + mb: 4, // s + bl: 5, // sw + ml: 6, // w + tl: 7 // nw + }, + addListener = fabric.util.addListener, + removeListener = fabric.util.removeListener; fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ { @@ -9893,6 +9952,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove); addListener(this.upperCanvasEl, 'mouseout', this._onMouseOut); addListener(this.upperCanvasEl, 'wheel', this._onMouseWheel); + addListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu); // touch events addListener(this.upperCanvasEl, 'touchstart', this._onMouseDown); @@ -9922,6 +9982,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab this._onOrientationChange = this._onOrientationChange.bind(this); this._onMouseWheel = this._onMouseWheel.bind(this); this._onMouseOut = this._onMouseOut.bind(this); + this._onContextMenu = this._onContextMenu.bind(this); }, /** @@ -9934,6 +9995,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove); removeListener(this.upperCanvasEl, 'mouseout', this._onMouseOut); removeListener(this.upperCanvasEl, 'wheel', this._onMouseWheel); + removeListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu); removeListener(this.upperCanvasEl, 'touchstart', this._onMouseDown); removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove); @@ -10011,6 +10073,18 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab this.__onLongPress && this.__onLongPress(e, self); }, + /** + * @private + * @param {Event} e Event object fired on mousedown + */ + _onContextMenu: function (e) { + if (this.stopContextMenu) { + e.stopPropagation() + e.preventDefault(); + } + return false; + }, + /** * @private * @param {Event} e Event object fired on mousedown @@ -10166,7 +10240,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab */ _handleEvent: function(e, eventType, targetObj) { var target = typeof targetObj === undefined ? this.findTarget(e) : targetObj, - targets = this.targets || [ ], + targets = this.targets || [], options = { e: e, target: target, subTargets: targets }; this.fire('mouse:' + eventType, options); @@ -10271,9 +10345,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab */ __onMouseDown: function (e) { - // accept only left clicks - var isLeftClick = 'which' in e ? e.which === 1 : e.button === 0; - if (!isLeftClick && !fabric.isTouchSupported) { + // if right click just fire events + var isRightClick = 'which' in e ? e.which === 3 : e.button === 2; + if (isRightClick) { + if (this.fireRightClick) { + this._handleEvent(e, 'down', target ? target : null); + } return; } @@ -10316,7 +10393,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab } } this._handleEvent(e, 'down', target ? target : null); - // we must renderAll so that active image is placed on the top canvas + // we must renderAll so that we update the visuals shouldRender && this.renderAll(); }, @@ -10452,7 +10529,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab var pointer = this.getPointer(e), transform = this._currentTransform; - transform.reset = false, + transform.reset = false; transform.target.isMoving = true; this._beforeScaleTransform(e, transform); @@ -10726,8 +10803,8 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab var objects = this.getObjects(), isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target), groupObjects = isActiveLower - ? [ this._activeObject, target ] - : [ target, this._activeObject ]; + ? [this._activeObject, target] + : [target, this._activeObject]; this._activeObject.isEditing && this._activeObject.exitEditing(); return new fabric.Group(groupObjects, { canvas: this @@ -10762,7 +10839,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab * @private */ _collectObjects: function() { - var group = [ ], + var group = [], currentObject, x1 = this._groupSelector.ex, y1 = this._groupSelector.ey, @@ -10821,223 +10898,130 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab })(); -fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { +(function () { - /** - * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately - * @param {Object} [options] Options object - * @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png" - * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg. - * @param {Number} [options.multiplier=1] Multiplier to scale by - * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14 - * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14 - * @param {Number} [options.width] Cropping width. Introduced in v1.2.14 - * @param {Number} [options.height] Cropping height. Introduced in v1.2.14 - * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format - * @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo} - * @example Generate jpeg dataURL with lower quality - * var dataURL = canvas.toDataURL({ - * format: 'jpeg', - * quality: 0.8 - * }); - * @example Generate cropped png dataURL (clipping of canvas) - * var dataURL = canvas.toDataURL({ - * format: 'png', - * left: 100, - * top: 100, - * width: 200, - * height: 200 - * }); - * @example Generate double scaled png dataURL - * var dataURL = canvas.toDataURL({ - * format: 'png', - * multiplier: 2 - * }); - */ - toDataURL: function (options) { - options || (options = { }); + var supportQuality = fabric.StaticCanvas.supports('toDataURLWithQuality'); - var format = options.format || 'png', - quality = options.quality || 1, - multiplier = options.multiplier || 1, - cropping = { - left: options.left, - top: options.top, - width: options.width, - height: options.height - }; + fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { - if (this._isRetinaScaling()) { - multiplier *= fabric.devicePixelRatio; - } + /** + * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately + * @param {Object} [options] Options object + * @param {String} [options.format=png] The format of the output image. Either "jpeg" or "png" + * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg. + * @param {Number} [options.multiplier=1] Multiplier to scale by + * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14 + * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14 + * @param {Number} [options.width] Cropping width. Introduced in v1.2.14 + * @param {Number} [options.height] Cropping height. Introduced in v1.2.14 + * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format + * @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo} + * @example Generate jpeg dataURL with lower quality + * var dataURL = canvas.toDataURL({ + * format: 'jpeg', + * quality: 0.8 + * }); + * @example Generate cropped png dataURL (clipping of canvas) + * var dataURL = canvas.toDataURL({ + * format: 'png', + * left: 100, + * top: 100, + * width: 200, + * height: 200 + * }); + * @example Generate double scaled png dataURL + * var dataURL = canvas.toDataURL({ + * format: 'png', + * multiplier: 2 + * }); + */ + toDataURL: function (options) { + options || (options = { }); - if (multiplier !== 1) { + var format = options.format || 'png', + quality = options.quality || 1, + multiplier = options.multiplier || 1, + cropping = { + left: options.left || 0, + top: options.top || 0, + width: options.width || 0, + height: options.height || 0, + }; return this.__toDataURLWithMultiplier(format, quality, cropping, multiplier); - } - else { - return this.__toDataURL(format, quality, cropping); - } - }, + }, - /** - * @private - */ - __toDataURL: function(format, quality, cropping) { + /** + * @private + */ + __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) { - this.renderAll(); + var origWidth = this.getWidth(), + origHeight = this.getHeight(), + scaledWidth = (cropping.width || this.getWidth()) * multiplier, + scaledHeight = (cropping.width || this.getHeight()) * multiplier, + zoom = this.getZoom(), + newZoom = zoom * multiplier, + vp = this.viewportTransform, + translateX = (vp[4] - cropping.left) * multiplier, + translateY = (vp[5] - cropping.top) * multiplier, + newVp = [newZoom, 0, 0, newZoom, translateX, translateY], + originalInteractive = this.interactive; - var canvasEl = this.contextContainer.canvas, - croppedCanvasEl = this.__getCroppedCanvas(canvasEl, cropping); + this.viewportTransform = newVp; + // setting interactive to false avoid exporting controls + this.interactive && (this.interactive = false); + if (origWidth !== scaledWidth || origHeight !== scaledHeight) { + // this.setDimensions is going to renderAll also; + this.setDimensions({ width: scaledWidth, height: scaledHeight }); + } + else { + this.renderAll(); + } + var data = this.__toDataURL(format, quality, cropping); + originalInteractive && (this.interactive = originalInteractive); + this.viewportTransform = vp; + //setDimensions with no option object is taking care of: + //this.width, this.height, this.renderAll() + this.setDimensions({ width: origWidth, height: origHeight }); + return data; + }, - // to avoid common confusion https://github.com/kangax/fabric.js/issues/806 - if (format === 'jpg') { - format = 'jpeg'; - } + /** + * @private + */ + __toDataURL: function(format, quality) { - var data = (fabric.StaticCanvas.supports('toDataURLWithQuality')) - ? (croppedCanvasEl || canvasEl).toDataURL('image/' + format, quality) - : (croppedCanvasEl || canvasEl).toDataURL('image/' + format); + var canvasEl = this.contextContainer.canvas; + // to avoid common confusion https://github.com/kangax/fabric.js/issues/806 + if (format === 'jpg') { + format = 'jpeg'; + } - if (croppedCanvasEl) { - croppedCanvasEl = null; - } + var data = supportQuality + ? canvasEl.toDataURL('image/' + format, quality) + : canvasEl.toDataURL('image/' + format); - return data; - }, + return data; + }, - /** - * @private - */ - __getCroppedCanvas: function(canvasEl, cropping) { + /** + * Exports canvas element to a dataurl image (allowing to change image size via multiplier). + * @deprecated since 1.0.13 + * @param {String} format (png|jpeg) + * @param {Number} multiplier + * @param {Number} quality (0..1) + * @return {String} + */ + toDataURLWithMultiplier: function (format, multiplier, quality) { + return this.toDataURL({ + format: format, + multiplier: multiplier, + quality: quality + }); + }, + }); - var croppedCanvasEl, - croppedCtx, - shouldCrop = 'left' in cropping || - 'top' in cropping || - 'width' in cropping || - 'height' in cropping; - - if (shouldCrop) { - - croppedCanvasEl = fabric.util.createCanvasElement(); - croppedCtx = croppedCanvasEl.getContext('2d'); - - croppedCanvasEl.width = cropping.width || this.width; - croppedCanvasEl.height = cropping.height || this.height; - - croppedCtx.drawImage(canvasEl, -cropping.left || 0, -cropping.top || 0); - } - - return croppedCanvasEl; - }, - - /** - * @private - */ - __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) { - - var origWidth = this.getWidth(), - origHeight = this.getHeight(), - scaledWidth = origWidth * multiplier, - scaledHeight = origHeight * multiplier, - activeObject = this.getActiveObject(), - activeGroup = this.getActiveGroup(), - zoom = this.getZoom(), - newZoom = zoom * multiplier / fabric.devicePixelRatio; - - if (multiplier > 1) { - this.setDimensions({ width: scaledWidth, height: scaledHeight }); - } - - this.setZoom(newZoom); - - if (cropping.left) { - cropping.left *= multiplier; - } - if (cropping.top) { - cropping.top *= multiplier; - } - if (cropping.width) { - cropping.width *= multiplier; - } - else if (multiplier < 1) { - cropping.width = scaledWidth; - } - if (cropping.height) { - cropping.height *= multiplier; - } - else if (multiplier < 1) { - cropping.height = scaledHeight; - } - - if (activeGroup) { - // not removing group due to complications with restoring it with correct state afterwords - this._tempRemoveBordersControlsFromGroup(activeGroup); - } - else if (activeObject && this.deactivateAll) { - this.deactivateAll(); - } - - var data = this.__toDataURL(format, quality, cropping); - if (activeGroup) { - this._restoreBordersControlsOnGroup(activeGroup); - } - else if (activeObject && this.setActiveObject) { - this.setActiveObject(activeObject); - } - this.setZoom(zoom); - //setDimensions with no option object is taking care of: - //this.width, this.height, this.renderAll() - this.setDimensions({ width: origWidth, height: origHeight }); - - return data; - }, - - /** - * Exports canvas element to a dataurl image (allowing to change image size via multiplier). - * @deprecated since 1.0.13 - * @param {String} format (png|jpeg) - * @param {Number} multiplier - * @param {Number} quality (0..1) - * @return {String} - */ - toDataURLWithMultiplier: function (format, multiplier, quality) { - return this.toDataURL({ - format: format, - multiplier: multiplier, - quality: quality - }); - }, - - /** - * @private - */ - _tempRemoveBordersControlsFromGroup: function(group) { - group.origHasControls = group.hasControls; - group.origBorderColor = group.borderColor; - - group.hasControls = true; - group.borderColor = 'rgba(0,0,0,0)'; - - group.forEachObject(function(o) { - o.origBorderColor = o.borderColor; - o.borderColor = 'rgba(0,0,0,0)'; - }); - }, - - /** - * @private - */ - _restoreBordersControlsOnGroup: function(group) { - group.hideControls = group.origHideControls; - group.borderColor = group.origBorderColor; - - group.forEachObject(function(o) { - o.borderColor = o.origBorderColor; - delete o.origBorderColor; - }); - } -}); +})(); fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { @@ -12040,7 +12024,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati 'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' + 'stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit ' + 'angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor ' + - 'alignX alignY meetOrSlice skewX skewY' + 'skewX skewY' ).split(' '), /** @@ -12299,7 +12283,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati this[key] = value; if (key === 'width' || key === 'height') { - this.minScaleLimit = Math.min(0.1, 1/Math.max(this.width, this.height)); + this.minScaleLimit = Math.min(0.1, 1 / Math.max(this.width, this.height)); } return this; @@ -12372,13 +12356,14 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati if (!noTransform) { this.transform(ctx); } + this._setOpacity(ctx); + this._setShadow(ctx); + this._renderBackground(ctx); this._setStrokeStyles(ctx); this._setFillStyles(ctx); if (this.transformMatrix) { ctx.transform.apply(ctx, this.transformMatrix); } - this._setOpacity(ctx); - this._setShadow(ctx); this.clipTo && fabric.util.clipContext(this, ctx); this._render(ctx, noTransform); this.clipTo && ctx.restore(); @@ -12386,6 +12371,29 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati ctx.restore(); }, + /** + * Draws a background for the object big as its width and height; + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderBackground: function(ctx) { + if (!this.backgroundColor) { + return; + } + + ctx.fillStyle = this.backgroundColor; + + ctx.fillRect( + -this.width / 2, + -this.height / 2, + this.width, + this.height + ); + // if there is background color no other shadows + // should be casted + this._removeShadow(ctx); + }, + /** * @private * @param {CanvasRenderingContext2D} ctx Context to render on @@ -12567,7 +12575,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati }, /** - * Clones an instance + * Clones an instance, some objects are async, so using callback method will work for every object. + * Using the direct return does not work for images and groups. * @param {Function} callback Callback is invoked with a clone as a first argument * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output * @return {fabric.Object} clone of an instance @@ -12617,10 +12626,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati el.width = boundingRect.width; el.height = boundingRect.height; - fabric.util.wrapElement(el, 'div'); var canvas = new fabric.StaticCanvas(el, { enableRetinaScaling: options.enableRetinaScaling }); - // to avoid common confusion https://github.com/kangax/fabric.js/issues/806 if (options.format === 'jpg') { options.format = 'jpeg'; @@ -13289,7 +13296,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati getCoords(other.oCoords) ); - return intersection.status === 'Intersection'; + return intersection.status === 'Intersection' + || other.isContainedWithinObject(this) + || this.isContainedWithinObject(other); }, /** @@ -13298,11 +13307,14 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * @return {Boolean} true if object is fully contained within area of another object */ isContainedWithinObject: function(other) { - var boundingRect = other.getBoundingRect(), - point1 = new fabric.Point(boundingRect.left, boundingRect.top), - point2 = new fabric.Point(boundingRect.left + boundingRect.width, boundingRect.top + boundingRect.height); - - return this.isContainedWithinRect(point1, point2); + var points = getCoords(this.oCoords), + i = 0; + for (; i < 4; i++) { + if (!other.containsPoint(points[i])) { + return false; + } + } + return true; }, /** @@ -13371,8 +13383,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati * @param {fabric.Point} point Point to check * @param {Object} oCoords Coordinates of the object being evaluated */ + // remove yi, not used but left code here just in case. _findCrossPoints: function(point, oCoords) { - var b1, b2, a1, a2, xi, yi, + var b1, b2, a1, a2, xi, // yi, xcount = 0, iLine; @@ -13389,7 +13402,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati // optimisation 3: vertical line case if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= point.x)) { xi = iLine.o.x; - yi = point.y; + // yi = point.y; } // calculate the intersection point else { @@ -13398,8 +13411,8 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati a1 = point.y - b1 * point.x; a2 = iLine.o.y - b2 * iLine.o.x; - xi = - (a1 - a2) / (b1 - b2); - yi = a1 + b1 * xi; + xi = -(a1 - a2) / (b1 - b2); + // yi = a1 + b1 * xi; } // dont count xi < point.x cases if (xi >= point.x) { @@ -13555,10 +13568,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati tr = new fabric.Point(tl.x + (currentWidth * cosTh), tl.y + (currentWidth * sinTh)), bl = new fabric.Point(tl.x - (currentHeight * sinTh), tl.y + (currentHeight * cosTh)), br = new fabric.Point(coords.x + offsetX, coords.y + offsetY), - ml = new fabric.Point((tl.x + bl.x)/2, (tl.y + bl.y)/2), - mt = new fabric.Point((tr.x + tl.x)/2, (tr.y + tl.y)/2), - mr = new fabric.Point((br.x + tr.x)/2, (br.y + tr.y)/2), - mb = new fabric.Point((br.x + bl.x)/2, (br.y + bl.y)/2), + ml = new fabric.Point((tl.x + bl.x) / 2, (tl.y + bl.y) / 2), + mt = new fabric.Point((tr.x + tl.x) / 2, (tr.y + tl.y) / 2), + mr = new fabric.Point((br.x + tr.x) / 2, (br.y + tr.y) / 2), + mb = new fabric.Point((br.x + bl.x) / 2, (br.y + bl.y) / 2), mtr = new fabric.Point(mt.x + sinTh * this.rotatingPointOffset, mt.y - cosTh * this.rotatingPointOffset); // debugging @@ -13590,6 +13603,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati return this; }, + /* + * calculate rotation matrix of an object + * @return {Array} rotation matrix for the object + */ _calcRotateMatrix: function() { if (this.angle) { var theta = degreesToRadians(this.angle), cos = Math.cos(theta), sin = Math.sin(theta); @@ -13846,7 +13863,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @private */ _createBaseSVGMarkup: function() { - var markup = [ ]; + var markup = []; if (this.fill && this.fill.toLive) { markup.push(this.fill.toSVG(this, false)); @@ -13864,60 +13881,89 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot /* _TO_SVG_END_ */ -/* - Depends on `stateProperties` -*/ -fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { +(function() { - /** - * Returns true if object state (one of its state properties) was changed - * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called - */ - hasStateChanged: function() { - return this.stateProperties.some(function(prop) { - return this.get(prop) !== this.originalState[prop]; - }, this); - }, + var extend = fabric.util.object.extend; - /** - * Saves state of an object - * @param {Object} [options] Object with additional `stateProperties` array to include when saving state - * @return {fabric.Object} thisArg - */ - saveState: function(options) { - this.stateProperties.forEach(function(prop) { - this.originalState[prop] = this.get(prop); - }, this); - - if (options && options.stateProperties) { - options.stateProperties.forEach(function(prop) { - this.originalState[prop] = this.get(prop); - }, this); - } - - return this; - }, - - /** - * Setups state of an object - * @return {fabric.Object} thisArg - */ - setupState: function() { - this.originalState = { }; - this.saveState(); - - return this; + /* + Depends on `stateProperties` + */ + function saveProps(origin, destination, props) { + var tmpObj = { }, deep = true; + props.forEach(function(prop) { + tmpObj[prop] = origin[prop]; + }); + extend(origin[destination], tmpObj, deep); } -}); + + function _isEqual(origValue, currentValue) { + if (origValue instanceof Array) { + if (origValue.length !== currentValue.length) { + return false + } + var _currentValue = currentValue.concat().sort(), + _origValue = origValue.concat().sort(); + return !_origValue.some(function(v, i) { + return !_isEqual(_currentValue[i], v); + }); + } + else if (origValue instanceof Object) { + for (var key in origValue) { + if (!_isEqual(origValue[key], currentValue[key])) { + return false; + } + } + return true; + } + else { + return origValue === currentValue; + } + } + + + fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + + /** + * Returns true if object state (one of its state properties) was changed + * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called + */ + hasStateChanged: function() { + return !_isEqual(this.originalState, this); + }, + + /** + * Saves state of an object + * @param {Object} [options] Object with additional `stateProperties` array to include when saving state + * @return {fabric.Object} thisArg + */ + saveState: function(options) { + saveProps(this, 'originalState', this.stateProperties); + if (options && options.stateProperties) { + saveProps(this, 'originalState', options.stateProperties); + } + return this; + }, + + /** + * Setups state of an object + * @param {Object} [options] Object with additional `stateProperties` array to include when saving state + * @return {fabric.Object} thisArg + */ + setupState: function(options) { + this.originalState = { }; + this.saveState(options); + return this; + } + }); +})(); (function() { var degreesToRadians = fabric.util.degreesToRadians, - //jscs:disable requireCamelCaseOrUpperCaseIdentifiers + /* eslint-disable camelcase */ isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; }; - //jscs:enable requireCamelCaseOrUpperCaseIdentifiers - + /* eslint-enable camelcase */ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { /** @@ -14059,24 +14105,24 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot skewY = this.skewY; } var dimensions = this._getNonTransformedDimensions(), - dimX = dimensions.x /2, dimY = dimensions.y / 2, + dimX = dimensions.x / 2, dimY = dimensions.y / 2, points = [ - { - x: -dimX, - y: -dimY - }, - { - x: dimX, - y: -dimY - }, - { - x: -dimX, - y: dimY - }, - { - x: dimX, - y: dimY - }], + { + x: -dimX, + y: -dimY + }, + { + x: dimX, + y: -dimY + }, + { + x: -dimX, + y: dimY + }, + { + x: dimX, + y: dimY + }], i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY, false), bbox; for (i = 0; i < points.length; i++) { @@ -14107,8 +14153,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @chainable */ drawSelectionBackground: function(ctx) { - if (!this.selectionBackgroundColor || this.group - || this !== this.canvas.getActiveObject()) { + if (!this.selectionBackgroundColor || this.group || !this.active) { return this; } ctx.save(); @@ -14118,7 +14163,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot ctx.scale(1 / vpt[0], 1 / vpt[3]); ctx.rotate(degreesToRadians(this.angle)); ctx.fillStyle = this.selectionBackgroundColor; - ctx.fillRect(-wh.x/2, -wh.y/2, wh.x, wh.y); + ctx.fillRect(-wh.x / 2, -wh.y / 2, wh.x, wh.y); ctx.restore(); return this; }, @@ -14255,23 +14300,23 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot // middle-top this._drawControl('mt', ctx, methodName, - left + width/2, + left + width / 2, top); // middle-bottom this._drawControl('mb', ctx, methodName, - left + width/2, + left + width / 2, top + height); // middle-right this._drawControl('mr', ctx, methodName, left + width, - top + height/2); + top + height / 2); // middle-left this._drawControl('ml', ctx, methodName, left, - top + height/2); + top + height / 2); } // middle-top-rotate @@ -14297,7 +14342,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot switch (this.cornerStyle) { case 'circle': ctx.beginPath(); - ctx.arc(left + size/2, top + size/2, size/2, 0, 2 * Math.PI, false); + ctx.arc(left + size / 2, top + size / 2, size / 2, 0, 2 * Math.PI, false); ctx[methodName](); if (stroke) { ctx.stroke(); @@ -14522,7 +14567,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ animate: function() { if (arguments[0] && typeof arguments[0] === 'object') { - var propsToAnimate = [ ], prop, skipCallbacks; + var propsToAnimate = [], prop, skipCallbacks; for (prop in arguments[0]) { propsToAnimate.push(prop); } @@ -14910,11 +14955,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @static * @memberOf fabric.Line * @param {Object} object Object to create an instance from + * @param {function} [callback] invoked with new instance as first argument * @return {fabric.Line} instance of fabric.Line */ - fabric.Line.fromObject = function(object) { - var points = [object.x1, object.y1, object.x2, object.y2]; - return new fabric.Line(points, object); + fabric.Line.fromObject = function(object, callback) { + var points = [object.x1, object.y1, object.x2, object.y2], + line = new fabric.Line(points, object); + callback && callback(line); + return line; }; /** @@ -14931,12 +14979,12 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot return function() { switch (this.get(origin)) { - case nearest: - return Math.min(this.get(axis1), this.get(axis2)); - case center: - return Math.min(this.get(axis1), this.get(axis2)) + (0.5 * this.get(dimension)); - case farthest: - return Math.max(this.get(axis1), this.get(axis2)); + case nearest: + return Math.min(this.get(axis1), this.get(axis2)); + case center: + return Math.min(this.get(axis1), this.get(axis2)) + (0.5 * this.get(dimension)); + case farthest: + return Math.max(this.get(axis1), this.get(axis2)); } }; @@ -15046,7 +15094,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ toSVG: function(reviver) { var markup = this._createBaseSVGMarkup(), x = 0, y = 0, - angle = (this.endAngle - this.startAngle) % ( 2 * pi); + angle = (this.endAngle - this.startAngle) % ( 2 * pi); if (angle === 0) { if (this.group && this.group.type === 'path-group') { @@ -15073,7 +15121,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot markup.push( '\n' - //jscs:enable validateIndentation ); return reviver ? reviver(markup.join('')) : markup.join(''); @@ -16737,8 +16799,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @private */ _parsePath: function() { - var result = [ ], - coords = [ ], + var result = [], + coords = [], currentPath, parsed, re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig, @@ -16755,7 +16817,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot coords.push(match[0]); } - coordsParsed = [ currentPath.charAt(0) ]; + coordsParsed = [currentPath.charAt(0)]; for (var j = 0, jlen = coords.length; j < jlen; j++) { parsed = parseFloat(coords[j]); @@ -16770,7 +16832,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot if (coordsParsed.length - 1 > commandLength) { for (var k = 1, klen = coordsParsed.length; k < klen; k += commandLength) { - result.push([ command ].concat(coordsParsed.slice(k, k + commandLength))); + result.push([command].concat(coordsParsed.slice(k, k + commandLength))); command = repeatedCommand; } } @@ -16810,33 +16872,33 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot case 'l': // lineto, relative x += current[1]; y += current[2]; - bounds = [ ]; + bounds = []; break; case 'L': // lineto, absolute x = current[1]; y = current[2]; - bounds = [ ]; + bounds = []; break; case 'h': // horizontal lineto, relative x += current[1]; - bounds = [ ]; + bounds = []; break; case 'H': // horizontal lineto, absolute x = current[1]; - bounds = [ ]; + bounds = []; break; case 'v': // vertical lineto, relative y += current[1]; - bounds = [ ]; + bounds = []; break; case 'V': // verical lineto, absolute y = current[1]; - bounds = [ ]; + bounds = []; break; case 'm': // moveTo, relative @@ -16844,7 +16906,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot y += current[2]; subpathStartX = x; subpathStartY = y; - bounds = [ ]; + bounds = []; break; case 'M': // moveTo, absolute @@ -16852,7 +16914,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot y = current[2]; subpathStartX = x; subpathStartY = y; - bounds = [ ]; + bounds = []; break; case 'c': // bezierCurveTo, relative @@ -17112,24 +17174,27 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @static * @memberOf fabric.Path * @param {Object} object - * @param {Function} callback Callback to invoke when an fabric.Path instance is created + * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created */ fabric.Path.fromObject = function(object, callback) { + // remove this pattern rom 2.0, accept just object. + var path; if (typeof object.path === 'string') { fabric.loadSVGFromURL(object.path, function (elements) { - var path = elements[0], - pathUrl = object.path; - + var pathUrl = object.path; + path = elements[0]; delete object.path; fabric.util.object.extend(path, object); path.setSourcePath(pathUrl); - callback(path); + callback && callback(path); }); } else { - callback(new fabric.Path(object.path, object)); + path = new fabric.Path(object.path, object); + callback && callback(path); + return path; } }; @@ -17214,7 +17279,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot initialize: function(paths, options) { options = options || { }; - this.paths = paths || [ ]; + this.paths = paths || []; for (var i = this.paths.length; i--;) { this.paths[i].group = this; @@ -17236,7 +17301,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * Calculate width and height based on paths contained */ parseDimensionsFromPaths: function(options) { - var points, p, xC = [ ], yC = [ ], path, height, width, + var points, p, xC = [], yC = [], path, height, width, m; for (var j = this.paths.length; j--;) { path = this.paths[j]; @@ -17281,7 +17346,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot this._setShadow(ctx); this.clipTo && fabric.util.clipContext(this, ctx); - ctx.translate(-this.width/2, -this.height/2); + ctx.translate(-this.width / 2, -this.height / 2); for (var i = 0, l = this.paths.length; i < l; ++i) { this.paths[i].render(ctx, true); } @@ -17411,9 +17476,10 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @static * @memberOf fabric.PathGroup * @param {Object} object Object to create an instance from - * @param {Function} callback Callback to invoke when an fabric.PathGroup instance is created + * @param {Function} [callback] Callback to invoke when an fabric.PathGroup instance is created */ fabric.PathGroup.fromObject = function(object, callback) { + // remove this pattern from 2.0 accepts only object if (typeof object.paths === 'string') { fabric.loadSVGFromURL(object.paths, function (elements) { @@ -17971,7 +18037,6 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @memberOf fabric.Group * @param {Object} object Object to create a group from * @param {Function} [callback] Callback to invoke when an group instance is created - * @return {fabric.Group} An instance of fabric.Group */ fabric.Group.fromObject = function(object, callback) { fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) { @@ -18007,6 +18072,13 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot return; } + var stateProperties = fabric.Object.prototype.stateProperties.concat(); + stateProperties.push( + 'alignX', + 'alignY', + 'meetOrSlice' + ); + /** * Image class * @class fabric.Image @@ -18091,6 +18163,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ minimumScaleTrigger: 0.5, + /** + * List of properties to consider when checking if + * state of an object is changed ({@link fabric.Object#hasStateChanged}) + * as well as for history (undo/redo) purposes + * @type Array + */ + stateProperties: stateProperties, + /** * Constructor * @param {HTMLImageElement | String} element Image element @@ -18100,8 +18180,8 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ initialize: function(element, options, callback) { options || (options = { }); - this.filters = [ ]; - this.resizeFilters = [ ]; + this.filters = []; + this.resizeFilters = []; this.callSuper('initialize', options); this._initElement(element, options, callback); }, @@ -18222,7 +18302,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * @return {Object} Object representation of an instance */ toObject: function(propertiesToInclude) { - var filters = [ ], resizeFilters = [ ], + var filters = [], resizeFilters = [], scaleX = 1, scaleY = 1; this.filters.forEach(function(filterObj) { @@ -18267,7 +18347,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot */ toSVG: function(reviver) { var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2, - preserveAspectRatio = 'none'; + preserveAspectRatio = 'none', filtered = true; if (this.group && this.group.type === 'path-group') { x = this.left; y = this.top; @@ -18277,7 +18357,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot } markup.push( '\n', - ''; }, - /** - * Returns a clone of an instance - * @param {Function} callback Callback is invoked with a clone as a first argument - * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output - */ - clone: function(callback, propertiesToInclude) { - this.constructor.fromObject(this.toObject(propertiesToInclude), callback); - }, - /** * Applies filters assigned to this image (from "filters" array) * @method applyFilters @@ -18608,14 +18680,14 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot * Creates an instance of fabric.Image from its object representation * @static * @param {Object} object Object to create an instance from - * @param {Function} [callback] Callback to invoke when an image instance is created + * @param {Function} callback Callback to invoke when an image instance is created */ fabric.Image.fromObject = function(object, callback) { fabric.util.loadImage(object.src, function(img) { fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) { - object.filters = filters || [ ]; + object.filters = filters || []; fabric.Image.prototype._initFilters.call(object, object.resizeFilters, function(resizeFilters) { - object.resizeFilters = resizeFilters || [ ]; + object.resizeFilters = resizeFilters || []; return new fabric.Image(img, object, callback); }); }); @@ -18841,7 +18913,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Brightness filter class @@ -18857,7 +18931,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Brightness = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ { + filters.Brightness = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ { /** * Filter type @@ -18925,7 +18999,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Adapted from html5rocks article @@ -18968,7 +19044,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Convolute = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ { + filters.Convolute = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ { /** * Filter type @@ -19006,7 +19082,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag pixels = context.getImageData(0, 0, canvasEl.width, canvasEl.height), side = Math.round(Math.sqrt(weights.length)), - halfSide = Math.floor(side/2), + halfSide = Math.floor(side / 2), src = pixels.data, sw = pixels.width, sh = pixels.height, @@ -19029,7 +19105,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag scy = y + cy - halfSide; scx = x + cx - halfSide; - /* jshint maxdepth:5 */ + // eslint-disable-next-line max-depth if (scy < 0 || scy > sh || scx < 0 || scx > sw) { continue; } @@ -19083,7 +19159,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * GradientTransparency filter class @@ -19099,7 +19177,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.GradientTransparency = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.GradientTransparency.prototype */ { + // eslint-disable-next-line max-len + filters.GradientTransparency = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.GradientTransparency.prototype */ { /** * Filter type @@ -19165,7 +19244,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; - var fabric = global.fabric || (global.fabric = { }); + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Grayscale image filter class @@ -19178,7 +19259,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Grayscale = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ { + filters.Grayscale = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ { /** * Filter type @@ -19228,7 +19309,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; - var fabric = global.fabric || (global.fabric = { }); + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Invert filter class @@ -19241,7 +19324,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Invert = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ { + filters.Invert = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ { /** * Filter type @@ -19261,7 +19344,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag data = imageData.data, iLen = data.length, i; - for (i = 0; i < iLen; i+=4) { + for (i = 0; i < iLen; i += 4) { data[i] = 255 - data[i]; data[i + 1] = 255 - data[i + 1]; data[i + 2] = 255 - data[i + 2]; @@ -19288,7 +19371,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Mask filter class @@ -19298,7 +19383,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * @extends fabric.Image.filters.BaseFilter * @see {@link fabric.Image.filters.Mask#initialize} for constructor definition */ - fabric.Image.filters.Mask = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Mask.prototype */ { + filters.Mask = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Mask.prototype */ { /** * Filter type @@ -19318,7 +19403,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag options = options || { }; this.mask = options.mask; - this.channel = [ 0, 1, 2, 3 ].indexOf(options.channel) > -1 ? options.channel : 0; + this.channel = [0, 1, 2, 3].indexOf(options.channel) > -1 ? options.channel : 0; }, /** @@ -19395,7 +19480,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Noise filter class @@ -19411,7 +19498,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Noise = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ { + filters.Noise = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ { /** * Filter type @@ -19482,7 +19569,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Pixelate filter class @@ -19498,7 +19587,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Pixelate = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ { + filters.Pixelate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ { /** * Filter type @@ -19594,7 +19683,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Remove white filter class @@ -19611,7 +19702,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.RemoveWhite = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.RemoveWhite.prototype */ { + filters.RemoveWhite = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.RemoveWhite.prototype */ { /** * Filter type @@ -19695,7 +19786,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; - var fabric = global.fabric || (global.fabric = { }); + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Sepia filter class @@ -19708,7 +19801,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Sepia = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Sepia.prototype */ { + filters.Sepia = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia.prototype */ { /** * Filter type @@ -19728,7 +19821,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag data = imageData.data, iLen = data.length, i, avg; - for (i = 0; i < iLen; i+=4) { + for (i = 0; i < iLen; i += 4) { avg = 0.3 * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2]; data[i] = avg + 100; data[i + 1] = avg + 50; @@ -19755,7 +19848,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; - var fabric = global.fabric || (global.fabric = { }); + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Sepia2 filter class @@ -19768,7 +19863,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Sepia2 = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Sepia2.prototype */ { + filters.Sepia2 = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia2.prototype */ { /** * Filter type @@ -19788,7 +19883,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag data = imageData.data, iLen = data.length, i, r, g, b; - for (i = 0; i < iLen; i+=4) { + for (i = 0; i < iLen; i += 4) { r = data[i]; g = data[i + 1]; b = data[i + 2]; @@ -19819,7 +19914,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Tint filter class @@ -19843,7 +19940,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Tint = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ { + filters.Tint = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ { /** * Filter type @@ -19889,7 +19986,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag alpha1 = 1 - this.opacity; - for (i = 0; i < iLen; i+=4) { + for (i = 0; i < iLen; i += 4) { r = data[i]; g = data[i + 1]; b = data[i + 2]; @@ -19933,7 +20030,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Multiply filter class @@ -19954,7 +20053,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Multiply = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Multiply.prototype */ { + filters.Multiply = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Multiply.prototype */ { /** * Filter type @@ -19988,7 +20087,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag source = new fabric.Color(this.color).getSource(); - for (i = 0; i < iLen; i+=4) { + for (i = 0; i < iLen; i += 4) { data[i] *= source[0] / 255; data[i + 1] *= source[1] / 255; data[i + 2] *= source[2] / 255; @@ -20024,7 +20123,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag (function(global) { 'use strict'; - var fabric = global.fabric; + var fabric = global.fabric, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Color Blend filter class @@ -20046,7 +20147,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Blend = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Blend.prototype */{ + + filters.Blend = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blend.prototype */ { type: 'Blend', initialize: function(options) { @@ -20174,7 +20276,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag var fabric = global.fabric || (global.fabric = { }), pow = Math.pow, floor = Math.floor, sqrt = Math.sqrt, abs = Math.abs, max = Math.max, round = Math.round, sin = Math.sin, - ceil = Math.ceil; + ceil = Math.ceil, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Resize image filter class @@ -20187,7 +20291,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.Resize = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.Resize.prototype */ { + filters.Resize = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Resize.prototype */ { /** * Filter type @@ -20351,7 +20455,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag for (v = 0; v < dH; v++) { center.y = (v + 0.5) * ratioY; icenter.y = floor(center.y); - a = 0, red = 0, green = 0, blue = 0, alpha = 0; + a = 0; red = 0; green = 0; blue = 0; alpha = 0; for (i = icenter.x - range2X; i <= icenter.x + range2X; i++) { if (i < 0 || i >= oW) { continue; @@ -20472,7 +20576,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag for (var xx = floor(i * ratioW); xx < (i + 1) * ratioW; xx++) { var dx = abs(centerX - (xx + 0.5)) / ratioWHalf, w = sqrt(w0 + dx * dx); - /*jshint maxdepth:5 */ + /* eslint-disable max-depth */ if (w > 1 && w < -1) { continue; } @@ -20484,17 +20588,15 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag gxA += weight * data[dx + 3]; weightsAlpha += weight; //colors - /*jshint maxdepth:6 */ if (data[dx + 3] < 255) { weight = weight * data[dx + 3] / 250; } - /*jshint maxdepth:5 */ gxR += weight * data[dx]; gxG += weight * data[dx + 1]; gxB += weight * data[dx + 2]; weights += weight; } - /*jshint maxdepth:4 */ + /* eslint-enable max-depth */ } } data2[x2] = gxR / weights; @@ -20538,7 +20640,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag 'use strict'; var fabric = global.fabric || (global.fabric = { }), - extend = fabric.util.object.extend; + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; /** * Color Matrix filter class @@ -20561,7 +20665,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * object.filters.push(filter); * object.applyFilters(canvas.renderAll.bind(canvas)); */ - fabric.Image.filters.ColorMatrix = fabric.util.createClass(fabric.Image.filters.BaseFilter, /** @lends fabric.Image.filters.ColorMatrix.prototype */ { + filters.ColorMatrix = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.ColorMatrix.prototype */ { /** * Filter type @@ -20579,11 +20683,11 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag initialize: function( options ) { options || ( options = {} ); this.matrix = options.matrix || [ - 1, 0, 0, 0, 0, - 0, 1, 0, 0, 0, - 0, 0, 1, 0, 0, - 0, 0, 0, 1, 0 - ]; + 1, 0, 0, 0, 0, + 0, 1, 0, 0, 0, + 0, 0, 1, 0, 0, + 0, 0, 0, 1, 0 + ]; }, /** @@ -20592,15 +20696,15 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag */ applyTo: function( canvasEl ) { var context = canvasEl.getContext( '2d' ), - imageData = context.getImageData( 0, 0, canvasEl.width, canvasEl.height ), - data = imageData.data, - iLen = data.length, - i, - r, - g, - b, - a, - m = this.matrix; + imageData = context.getImageData( 0, 0, canvasEl.width, canvasEl.height ), + data = imageData.data, + iLen = data.length, + i, + r, + g, + b, + a, + m = this.matrix; for ( i = 0; i < iLen; i += 4 ) { r = data[ i ]; @@ -20650,7 +20754,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag extend = fabric.util.object.extend, clone = fabric.util.object.clone, toFixed = fabric.util.toFixed, - NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS; + NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, + MIN_TEXT_WIDTH = 2; if (fabric.Text) { fabric.warn('fabric.Text is already defined'); @@ -20694,7 +20799,6 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag text: true, charSpacing: true, textAlign: true, - stroke: false, strokeWidth: false, }, @@ -21004,7 +21108,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag } this._textLines = this._splitTextIntoLines(); this._clearCache(); - this.width = this._getTextWidth(ctx); + this.width = this._getTextWidth(ctx) || this.cursorWidth || MIN_TEXT_WIDTH; this.height = this._getTextHeight(ctx); }, @@ -21279,32 +21383,10 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * @param {CanvasRenderingContext2D} ctx Context to render on */ _renderTextBackground: function(ctx) { - this._renderTextBoxBackground(ctx); + this._renderBackground(ctx); this._renderTextLinesBackground(ctx); }, - /** - * @private - * @param {CanvasRenderingContext2D} ctx Context to render on - */ - _renderTextBoxBackground: function(ctx) { - if (!this.backgroundColor) { - return; - } - - ctx.fillStyle = this.backgroundColor; - - ctx.fillRect( - this._getLeftOffset(), - this._getTopOffset(), - this.width, - this.height - ); - // if there is background color no other shadows - // should be casted - this._removeShadow(ctx); - }, - /** * @private * @param {CanvasRenderingContext2D} ctx Context to render on @@ -21355,8 +21437,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * @private */ _clearCache: function() { - this.__lineWidths = [ ]; - this.__lineHeights = [ ]; + this.__lineWidths = []; + this.__lineHeights = []; }, /** @@ -21450,8 +21532,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag for (i = 0, len = _this._textLines.length; i < len; i++) { - lineWidth = _this._getLineWidth(ctx, i), - lineLeftOffset = _this._getLineLeftOffset(lineWidth), + lineWidth = _this._getLineWidth(ctx, i); + lineLeftOffset = _this._getLineLeftOffset(lineWidth); heightOfLine = _this._getHeightOfLine(ctx, i); for (j = 0, oLen = offsets.length; j < oLen; j++) { @@ -21489,7 +21571,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag (fabric.isLikelyNode ? this.fontWeight : this.fontStyle), (fabric.isLikelyNode ? this.fontStyle : this.fontWeight), this.fontSize + 'px', - '"' + this.fontFamily + '"' + (fabric.isLikelyNode ? ('"' + this.fontFamily + '"') : this.fontFamily) ].join(' '); }, @@ -21601,11 +21683,11 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag style, '>\n', textAndBg.textBgRects.join(''), '\t\t\n', textAndBg.textSpans.join(''), '\t\t\n', @@ -21620,8 +21702,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * @return {Object} */ _getSVGTextAndBg: function(textTopOffset, textLeftOffset) { - var textSpans = [ ], - textBgRects = [ ], + var textSpans = [], + textBgRects = [], height = 0; // bounding-box background this._setSVGBg(textBgRects); @@ -21869,10 +21951,13 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * @static * @memberOf fabric.Text * @param {Object} object Object to create an instance from + * @param {Function} [callback] Callback to invoke when an fabric.Text instance is created * @return {fabric.Text} Instance of fabric.Text */ - fabric.Text.fromObject = function(object) { - return new fabric.Text(object.text, clone(object)); + fabric.Text.fromObject = function(object, callback) { + var text = new fabric.Text(object.text, clone(object)); + callback && callback(text); + return text; }; fabric.util.createAccessors(fabric.Text); @@ -22047,7 +22132,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag /** * @private */ - __widthOfSpace: [ ], + __widthOfSpace: [], /** * Constructor @@ -22066,7 +22151,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag */ _clearCache: function() { this.callSuper('_clearCache'); - this.__widthOfSpace = [ ]; + this.__widthOfSpace = []; }, /** @@ -22080,7 +22165,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag for (var p1 in obj) { for (var p2 in obj[p1]) { - /*jshint unused:false */ + // eslint-disable-next-line no-unused-vars for (var p3 in obj[p1][p2]) { return false; } @@ -22138,7 +22223,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag getSelectionStyles: function(startIndex, endIndex) { if (arguments.length === 2) { - var styles = [ ]; + var styles = []; for (var i = startIndex; i < endIndex; i++) { styles.push(this.getSelectionStyles(i)); } @@ -22400,7 +22485,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag ctx.globalAlpha = this.__isMousedown ? 1 : this._currentCursorOpacity; ctx.fillRect( - boundaries.left + leftOffset - cursorWidth/2, + boundaries.left + leftOffset - cursorWidth / 2, boundaries.top + boundaries.topOffset, cursorWidth, charHeight); @@ -22770,6 +22855,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag styleDeclaration.scaleX = this.scaleX; styleDeclaration.scaleY = this.scaleY; styleDeclaration.canvas = this.canvas; + styleDeclaration.getObjectScaling = this.getObjectScaling; this._setShadow.call(styleDeclaration, ctx); } @@ -23021,10 +23107,13 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag * @static * @memberOf fabric.IText * @param {Object} object Object to create an instance from + * @param {function} [callback] invoked with new instance as argument * @return {fabric.IText} instance of fabric.IText */ - fabric.IText.fromObject = function(object) { - return new fabric.IText(object.text, clone(object)); + fabric.IText.fromObject = function(object, callback) { + var iText = new fabric.IText(object.text, clone(object)); + callback && callback(iText); + return iText; }; })(); @@ -23527,6 +23616,10 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag p.y = maxHeight; } + // add canvas offset on document + p.x += this.canvas._offset.left; + p.y += this.canvas._offset.top; + return { left: p.x + 'px', top: p.y + 'px', fontSize: charHeight }; }, @@ -23855,6 +23948,58 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Imag */ insertNewline: function() { this.insertChars('\n'); + }, + + /** + * Set the selectionStart and selectionEnd according to the ne postion of cursor + * mimic the key - mouse navigation when shift is pressed. + */ + setSelectionStartEndWithShift: function(start, end, newSelection) { + if (newSelection <= start) { + if (end === start) { + this._selectionDirection = 'left'; + } + else if (this._selectionDirection === 'right') { + this._selectionDirection = 'left'; + this.selectionEnd = start; + } + this.selectionStart = newSelection; + } + else if (newSelection > start && newSelection < end) { + if (this._selectionDirection === 'right') { + this.selectionEnd = newSelection; + } + else { + this.selectionStart = newSelection; + } + } + else { + // newSelection is > selection start and end + if (end === start) { + this._selectionDirection = 'right'; + } + else if (this._selectionDirection === 'left') { + this._selectionDirection = 'right'; + this.selectionStart = end; + } + this.selectionEnd = newSelection; + } + }, + + setSelectionInBoundaries: function() { + var length = this.text.length; + if (this.selectionStart > length) { + this.selectionStart = length; + } + else if (this.selectionStart < 0) { + this.selectionStart = 0; + } + if (this.selectionEnd > length) { + this.selectionEnd = length; + } + else if (this.selectionEnd < 0) { + this.selectionEnd = 0; + } } }); })(); @@ -24007,20 +24152,14 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot * @param {Event} e Event object */ setCursorByClick: function(e) { - var newSelectionStart = this.getSelectionStartFromPointer(e); - + var newSelection = this.getSelectionStartFromPointer(e), + start = this.selectionStart, end = this.selectionEnd; if (e.shiftKey) { - if (newSelectionStart < this.selectionStart) { - this.selectionEnd = this.selectionStart; - this.selectionStart = newSelectionStart; - } - else { - this.selectionEnd = newSelectionStart; - } + this.setSelectionStartEndWithShift(start, end, newSelection); } else { - this.selectionStart = newSelectionStart; - this.selectionEnd = newSelectionStart; + this.selectionStart = newSelection; + this.selectionEnd = newSelection; } this._fireSelectionChanged(); this._updateTextarea(); @@ -24359,6 +24498,25 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot return (e && e.clipboardData) || fabric.window.clipboardData; }, + /** + * Finds the width in pixels before the cursor on the same line + * @private + * @param {Number} lineIndex + * @param {Number} charIndex + * @return {Number} widthBeforeCursor width before cursor + */ + _getWidthBeforeCursor: function(lineIndex, charIndex) { + var textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex), + widthOfLine = this._getLineWidth(this.ctx, lineIndex), + widthBeforeCursor = this._getLineLeftOffset(widthOfLine), _char; + + for (var i = 0, len = textBeforeCursor.length; i < len; i++) { + _char = textBeforeCursor[i]; + widthBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); + } + return widthBeforeCursor; + }, + /** * Gets start offset of a selection * @param {Event} e Event object @@ -24366,64 +24524,89 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot * @return {Number} */ getDownCursorOffset: function(e, isRight) { - var selectionProp = isRight ? this.selectionEnd : this.selectionStart, + var selectionProp = this._getSelectionForOffset(e, isRight), cursorLocation = this.get2DCursorLocation(selectionProp), - _char, lineLeftOffset, lineIndex = cursorLocation.lineIndex, - textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex), - textOnSameLineAfterCursor = this._textLines[lineIndex].slice(cursorLocation.charIndex), - textOnNextLine = this._textLines[lineIndex + 1] || ''; - + lineIndex = cursorLocation.lineIndex; // if on last line, down cursor goes to end of line if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) { - // move to the end of a text return this.text.length - selectionProp; } + var charIndex = cursorLocation.charIndex, + widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex), + indexOnOtherLine = this._getIndexOnLine(lineIndex + 1, widthBeforeCursor), + textAfterCursor = this._textLines[lineIndex].slice(charIndex); - var widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, lineIndex); - lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); - - var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; - - for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { - _char = textOnSameLineBeforeCursor[i]; - widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); - } - - var indexOnNextLine = this._getIndexOnNextLine( - cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor); - - return textOnSameLineAfterCursor.length + 1 + indexOnNextLine; + return textAfterCursor.length + indexOnOtherLine + 2; }, /** + * private + * Helps finding if the offset should be counted from Start or End + * @param {Event} e Event object + * @param {Boolean} isRight + * @return {Number} + */ + _getSelectionForOffset: function(e, isRight) { + if (e.shiftKey && this.selectionStart !== this.selectionEnd && isRight) { + return this.selectionEnd; + } + else { + return this.selectionStart; + } + }, + + /** + * @param {Event} e Event object + * @param {Boolean} isRight + * @return {Number} + */ + getUpCursorOffset: function(e, isRight) { + var selectionProp = this._getSelectionForOffset(e, isRight), + cursorLocation = this.get2DCursorLocation(selectionProp), + lineIndex = cursorLocation.lineIndex; + if (lineIndex === 0 || e.metaKey || e.keyCode === 33) { + // if on first line, up cursor goes to start of line + return -selectionProp; + } + var charIndex = cursorLocation.charIndex, + widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex), + indexOnOtherLine = this._getIndexOnLine(lineIndex - 1, widthBeforeCursor), + textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex); + // return a negative offset + return -this._textLines[lineIndex - 1].length + indexOnOtherLine - textBeforeCursor.length; + }, + + /** + * find for a given width it founds the matching character. * @private */ - _getIndexOnNextLine: function(cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor) { - var lineIndex = cursorLocation.lineIndex + 1, - widthOfNextLine = this._getLineWidth(this.ctx, lineIndex), - lineLeftOffset = this._getLineLeftOffset(widthOfNextLine), - widthOfCharsOnNextLine = lineLeftOffset, - indexOnNextLine = 0, + _getIndexOnLine: function(lineIndex, width) { + + var widthOfLine = this._getLineWidth(this.ctx, lineIndex), + textOnLine = this._textLines[lineIndex], + lineLeftOffset = this._getLineLeftOffset(widthOfLine), + widthOfCharsOnLine = lineLeftOffset, + indexOnLine = 0, foundMatch; - for (var j = 0, jlen = textOnNextLine.length; j < jlen; j++) { + for (var j = 0, jlen = textOnLine.length; j < jlen; j++) { - var _char = textOnNextLine[j], + var _char = textOnLine[j], widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); - widthOfCharsOnNextLine += widthOfChar; + widthOfCharsOnLine += widthOfChar; - if (widthOfCharsOnNextLine > widthOfCharsOnSameLineBeforeCursor) { + if (widthOfCharsOnLine > width) { foundMatch = true; - var leftEdge = widthOfCharsOnNextLine - widthOfChar, - rightEdge = widthOfCharsOnNextLine, - offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor), - offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); + var leftEdge = widthOfCharsOnLine - widthOfChar, + rightEdge = widthOfCharsOnLine, + offsetFromLeftEdge = Math.abs(leftEdge - width), + offsetFromRightEdge = Math.abs(rightEdge - width); - indexOnNextLine = offsetFromRightEdge < offsetFromLeftEdge ? j + 1 : j; + indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1); break; } @@ -24431,12 +24614,13 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot // reached end if (!foundMatch) { - indexOnNextLine = textOnNextLine.length; + indexOnLine = textOnLine.length - 1; } - return indexOnNextLine; + return indexOnLine; }, + /** * Moves cursor down * @param {Event} e Event object @@ -24448,124 +24632,6 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot this._moveCursorUpOrDown('Down', e); }, - /** - * Moves cursor down without keeping selection - * @param {Number} offset - */ - moveCursorDownWithoutShift: function(offset) { - this._selectionDirection = 'right'; - this.selectionEnd = this.selectionEnd + offset; - this.selectionStart = this.selectionEnd; - return offset !== 0; - }, - - /** - * private - */ - swapSelectionPoints: function() { - var swapSel = this.selectionEnd; - this.selectionEnd = this.selectionStart; - this.selectionStart = swapSel; - }, - - /** - * Moves cursor down while keeping selection - * @param {Number} offset - */ - moveCursorDownWithShift: function(offset) { - if (this.selectionEnd === this.selectionStart) { - this._selectionDirection = 'right'; - } - if (this._selectionDirection === 'right') { - this.selectionEnd += offset; - } - else { - this.selectionStart += offset; - } - if (this.selectionEnd < this.selectionStart && this._selectionDirection === 'left') { - this.swapSelectionPoints(); - this._selectionDirection = 'right'; - } - if (this.selectionEnd > this.text.length) { - this.selectionEnd = this.text.length; - } - return offset !== 0; - }, - - /** - * @param {Event} e Event object - * @param {Boolean} isRight - * @return {Number} - */ - getUpCursorOffset: function(e, isRight) { - var selectionProp = isRight ? this.selectionEnd : this.selectionStart, - cursorLocation = this.get2DCursorLocation(selectionProp), - lineIndex = cursorLocation.lineIndex; - // if on first line, up cursor goes to start of line - if (lineIndex === 0 || e.metaKey || e.keyCode === 33) { - return selectionProp; - } - - var textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex), - textOnPreviousLine = this._textLines[lineIndex - 1] || '', - _char, - widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex), - lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor), - widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; - - for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { - _char = textOnSameLineBeforeCursor[i]; - widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); - } - - var indexOnPrevLine = this._getIndexOnPrevLine( - cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor); - - return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length; - }, - - /** - * @private - */ - _getIndexOnPrevLine: function(cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor) { - - var lineIndex = cursorLocation.lineIndex - 1, - widthOfPreviousLine = this._getLineWidth(this.ctx, lineIndex), - lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine), - widthOfCharsOnPreviousLine = lineLeftOffset, - indexOnPrevLine = 0, - foundMatch; - - for (var j = 0, jlen = textOnPreviousLine.length; j < jlen; j++) { - - var _char = textOnPreviousLine[j], - widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); - - widthOfCharsOnPreviousLine += widthOfChar; - - if (widthOfCharsOnPreviousLine > widthOfCharsOnSameLineBeforeCursor) { - - foundMatch = true; - - var leftEdge = widthOfCharsOnPreviousLine - widthOfChar, - rightEdge = widthOfCharsOnPreviousLine, - offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor), - offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); - - indexOnPrevLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1); - - break; - } - } - - // reached end - if (!foundMatch) { - indexOnPrevLine = textOnPreviousLine.length - 1; - } - - return indexOnPrevLine; - }, - /** * Moves cursor up * @param {Event} e Event object @@ -24583,16 +24649,18 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot * @param {Event} e Event object */ _moveCursorUpOrDown: function(direction, e) { + // getUpCursorOffset + // getDownCursorOffset var action = 'get' + direction + 'CursorOffset', - moveAction = 'moveCursor' + direction, offset = this[action](e, this._selectionDirection === 'right'); if (e.shiftKey) { - moveAction += 'WithShift'; + this.moveCursorWithShift(offset); } else { - moveAction += 'WithoutShift'; + this.moveCursorWithoutShift(offset); } - if (this[moveAction](offset)) { + if (offset !== 0) { + this.setSelectionInBoundaries(); this.abortCursorAnimation(); this._currentCursorOpacity = 1; this.initDelayedCursor(); @@ -24602,23 +24670,14 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot }, /** - * Moves cursor up with shift + * Moves cursor with shift * @param {Number} offset */ - moveCursorUpWithShift: function(offset) { - if (this.selectionEnd === this.selectionStart) { - this._selectionDirection = 'left'; - } - if (this._selectionDirection === 'right') { - this.selectionEnd -= offset; - } - else { - this.selectionStart -= offset; - } - if (this.selectionEnd < this.selectionStart && this._selectionDirection === 'right') { - this.swapSelectionPoints(); - this._selectionDirection = 'left'; - } + moveCursorWithShift: function(offset) { + var newSelection = this._selectionDirection === 'left' + ? this.selectionStart + offset + : this.selectionEnd + offset; + this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection); return offset !== 0; }, @@ -24626,10 +24685,15 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot * Moves cursor up without shift * @param {Number} offset */ - moveCursorUpWithoutShift: function(offset) { - this._selectionDirection = 'left'; - this.selectionStart -= offset; - this.selectionEnd = this.selectionStart; + moveCursorWithoutShift: function(offset) { + if (offset < 0) { + this.selectionStart += offset; + this.selectionEnd = this.selectionStart; + } + else { + this.selectionEnd += offset; + this.selectionStart = this.selectionEnd; + } return offset !== 0; }, @@ -24902,14 +24966,12 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot */ _createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) { return [ - //jscs:disable validateIndentation '\t\t\n' - //jscs:enable validateIndentation ].join(''); }, @@ -24927,18 +24989,16 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot }, styleDecl)); return [ - //jscs:disable validateIndentation '\t\t\t', - fabric.util.string.escapeXml(_char), + toFixed(lineTopOffset - this.height / 2, NUM_FRACTION_DIGITS), '" ', + (styleDecl.fontFamily ? 'font-family="' + styleDecl.fontFamily.replace(/"/g, '\'') + '" ' : ''), + (styleDecl.fontSize ? 'font-size="' + styleDecl.fontSize + '" ' : ''), + (styleDecl.fontStyle ? 'font-style="' + styleDecl.fontStyle + '" ' : ''), + (styleDecl.fontWeight ? 'font-weight="' + styleDecl.fontWeight + '" ' : ''), + (styleDecl.textDecoration ? 'text-decoration="' + styleDecl.textDecoration + '" ' : ''), + 'style="', fillStyles, '">', + fabric.util.string.escapeXml(_char), '\n' - //jscs:enable validateIndentation ].join(''); } }); @@ -24982,10 +25042,12 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot /** * Minimum calculated width of a textbox, in pixels. + * fixed to 2 so that an empty textbox cannot go to 0 + * and is still selectable without text. * @type Number * @default */ - dynamicMinWidth: 0, + dynamicMinWidth: 2, /** * Cached array of text wrapping. @@ -25066,12 +25128,12 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot map = {}; for (var i = 0; i < this._textLines.length; i++) { - if (this.text[charCount] === '\n') { + if (this.text[charCount] === '\n' && i > 0) { realLineCharCount = 0; charCount++; realLineCount++; } - else if (this.text[charCount] === ' ') { + else if (this.text[charCount] === ' ' && i > 0) { // this case deals with space's that are removed from end of lines when wrapping realLineCharCount++; charCount++; @@ -25391,10 +25453,13 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot * @static * @memberOf fabric.Textbox * @param {Object} object Object to create an instance from + * @param {Function} [callback] Callback to invoke when an fabric.Textbox instance is created * @return {fabric.Textbox} instance of fabric.Textbox */ - fabric.Textbox.fromObject = function(object) { - return new fabric.Textbox(object.text, clone(object)); + fabric.Textbox.fromObject = function(object, callback) { + var textbox = new fabric.Textbox(object.text, clone(object)); + callback && callback(textbox); + return textbox; }; /** * Returns the default controls visibility required for Textboxes. @@ -25730,6 +25795,7 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot fabric.util.getScript = function(url, callback) { request(url, '', function(body) { + // eslint-disable-next-line no-eval eval(body); callback && callback(); }); @@ -25759,19 +25825,30 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot canvasEl.width = nodeCanvas.width; canvasEl.height = nodeCanvas.height; - + options = options || { }; + options.nodeCanvas = nodeCanvas; + options.nodeCacheCanvas = nodeCacheCanvas; var FabricCanvas = fabric.Canvas || fabric.StaticCanvas, fabricCanvas = new FabricCanvas(canvasEl, options); - - fabricCanvas.contextContainer = nodeCanvas.getContext('2d'); fabricCanvas.nodeCanvas = nodeCanvas; - fabricCanvas.contextCache = nodeCacheCanvas.getContext('2d'); fabricCanvas.nodeCacheCanvas = nodeCacheCanvas; + fabricCanvas.contextContainer = nodeCanvas.getContext('2d'); + fabricCanvas.contextCache = nodeCacheCanvas.getContext('2d'); fabricCanvas.Font = Canvas.Font; - return fabricCanvas; }; + var originaInitStatic = fabric.StaticCanvas.prototype._initStatic; + fabric.StaticCanvas.prototype._initStatic = function(el, options) { + el = el || fabric.document.createElement('canvas'); + this.nodeCanvas = new Canvas(el.width, el.height); + this.nodeCacheCanvas = new Canvas(el.width, el.height); + originaInitStatic.call(this, el, options); + this.contextContainer = this.nodeCanvas.getContext('2d'); + this.contextCache = this.nodeCacheCanvas.getContext('2d'); + this.Font = Canvas.Font; + } + /** @ignore */ fabric.StaticCanvas.prototype.createPNGStream = function() { return this.nodeCanvas.createPNGStream(); @@ -25781,24 +25858,30 @@ fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.protot return this.nodeCanvas.createJPEGStream(opts); }; - var origSetWidth = fabric.StaticCanvas.prototype.setWidth; - fabric.StaticCanvas.prototype.setWidth = function(width, options) { - origSetWidth.call(this, width, options); - this.nodeCanvas.width = width; + fabric.StaticCanvas.prototype._initRetinaScaling = function() { + if (!this._isRetinaScaling()) { + return; + } + + this.lowerCanvasEl.setAttribute('width', this.width * fabric.devicePixelRatio); + this.lowerCanvasEl.setAttribute('height', this.height * fabric.devicePixelRatio); + this.nodeCanvas.width = this.width * fabric.devicePixelRatio; + this.nodeCanvas.height = this.height * fabric.devicePixelRatio; + this.contextContainer.scale(fabric.devicePixelRatio, fabric.devicePixelRatio); return this; }; if (fabric.Canvas) { - fabric.Canvas.prototype.setWidth = fabric.StaticCanvas.prototype.setWidth; + fabric.Canvas.prototype._initRetinaScaling = fabric.StaticCanvas.prototype._initRetinaScaling; } - var origSetHeight = fabric.StaticCanvas.prototype.setHeight; - fabric.StaticCanvas.prototype.setHeight = function(height, options) { - origSetHeight.call(this, height, options); - this.nodeCanvas.height = height; + var origSetBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension; + fabric.StaticCanvas.prototype._setBackstoreDimension = function(prop, value) { + origSetBackstoreDimension.call(this, prop, value); + this.nodeCanvas[prop] = value; return this; }; if (fabric.Canvas) { - fabric.Canvas.prototype.setHeight = fabric.StaticCanvas.prototype.setHeight; + fabric.Canvas.prototype._setBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension; } })(); diff --git a/dist/fabric.min.js b/dist/fabric.min.js index 36f62d22..8ed014f0 100644 --- a/dist/fabric.min.js +++ b/dist/fabric.min.js @@ -1,8 +1,8 @@ -var fabric=fabric||{version:"1.6.4"};"undefined"!=typeof exports&&(exports.fabric=fabric),"undefined"!=typeof document&&"undefined"!=typeof window?(fabric.document=document,fabric.window=window,window.fabric=fabric):(fabric.document=require("jsdom").jsdom(""),fabric.document.createWindow?fabric.window=fabric.document.createWindow():fabric.window=fabric.document.parentWindow),fabric.isTouchSupported="ontouchstart"in fabric.document.documentElement,fabric.isLikelyNode="undefined"!=typeof Buffer&&"undefined"==typeof window,fabric.SHARED_ATTRIBUTES=["display","transform","fill","fill-opacity","fill-rule","opacity","stroke","stroke-dasharray","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","id"],fabric.DPI=96,fabric.reNum="(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:e[-+]?\\d+)?)",fabric.fontPaths={},fabric.charWidthsCache={},fabric.devicePixelRatio=fabric.window.devicePixelRatio||fabric.window.webkitDevicePixelRatio||fabric.window.mozDevicePixelRatio||1,function(){function t(t,e){if(this.__eventListeners[t]){var i=this.__eventListeners[t];e?i[i.indexOf(e)]=!1:fabric.util.array.fill(i,!1)}}function e(t,e){if(this.__eventListeners||(this.__eventListeners={}),1===arguments.length)for(var i in t)this.on(i,t[i]);else this.__eventListeners[t]||(this.__eventListeners[t]=[]),this.__eventListeners[t].push(e);return this}function i(e,i){if(this.__eventListeners){if(0===arguments.length)for(e in this.__eventListeners)t.call(this,e);else if(1===arguments.length&&"object"==typeof arguments[0])for(var r in e)t.call(this,r,e[r]);else t.call(this,e,i);return this}}function r(t,e){if(this.__eventListeners){var i=this.__eventListeners[t];if(i){for(var r=0,n=i.length;r-1},complexity:function(){return this.getObjects().reduce(function(t,e){return t+=e.complexity?e.complexity():0},0)}},function(t){var e=Math.sqrt,i=Math.atan2,r=Math.pow,n=Math.abs,s=Math.PI/180;fabric.util={removeFromArray:function(t,e){var i=t.indexOf(e);return i!==-1&&t.splice(i,1),t},getRandomInt:function(t,e){return Math.floor(Math.random()*(e-t+1))+t},degreesToRadians:function(t){return t*s},radiansToDegrees:function(t){return t/s},rotatePoint:function(t,e,i){t.subtractEquals(e);var r=fabric.util.rotateVector(t,i);return new fabric.Point(r.x,r.y).addEquals(e)},rotateVector:function(t,e){var i=Math.sin(e),r=Math.cos(e),n=t.x*r-t.y*i,s=t.x*i+t.y*r;return{x:n,y:s}},transformPoint:function(t,e,i){return i?new fabric.Point(e[0]*t.x+e[2]*t.y,e[1]*t.x+e[3]*t.y):new fabric.Point(e[0]*t.x+e[2]*t.y+e[4],e[1]*t.x+e[3]*t.y+e[5])},makeBoundingBoxFromPoints:function(t){var e=[t[0].x,t[1].x,t[2].x,t[3].x],i=fabric.util.array.min(e),r=fabric.util.array.max(e),n=Math.abs(i-r),s=[t[0].y,t[1].y,t[2].y,t[3].y],o=fabric.util.array.min(s),a=fabric.util.array.max(s),h=Math.abs(o-a);return{left:i,top:o,width:n,height:h}},invertTransform:function(t){var e=1/(t[0]*t[3]-t[1]*t[2]),i=[e*t[3],-e*t[1],-e*t[2],e*t[0]],r=fabric.util.transformPoint({x:t[4],y:t[5]},i,!0);return i[4]=-r.x,i[5]=-r.y,i},toFixed:function(t,e){return parseFloat(Number(t).toFixed(e))},parseUnit:function(t,e){var i=/\D{0,2}$/.exec(t),r=parseFloat(t);switch(e||(e=fabric.Text.DEFAULT_SVG_FONT_SIZE),i[0]){case"mm":return r*fabric.DPI/25.4;case"cm":return r*fabric.DPI/2.54;case"in":return r*fabric.DPI;case"pt":return r*fabric.DPI/72;case"pc":return r*fabric.DPI/72*12;case"em":return r*e;default:return r}},falseFunction:function(){return!1},getKlass:function(t,e){return t=fabric.util.string.camelize(t.charAt(0).toUpperCase()+t.slice(1)),fabric.util.resolveNamespace(e)[t]},resolveNamespace:function(e){if(!e)return fabric;for(var i=e.split("."),r=i.length,n=t||fabric.window,s=0;sr;)r+=a[d++%f],r>l&&(r=l),t[g?"lineTo":"moveTo"](r,0),g=!g;t.restore()},createCanvasElement:function(t){return t||(t=fabric.document.createElement("canvas")),t.getContext||"undefined"==typeof G_vmlCanvasManager||G_vmlCanvasManager.initElement(t),t},createImage:function(){return fabric.isLikelyNode?new(require("canvas").Image):fabric.document.createElement("img")},createAccessors:function(t){for(var e=t.prototype,i=e.stateProperties.length;i--;){var r=e.stateProperties[i],n=r.charAt(0).toUpperCase()+r.slice(1),s="set"+n,o="get"+n;e[o]||(e[o]=function(t){return new Function('return this.get("'+t+'")')}(r)),e[s]||(e[s]=function(t){return new Function("value",'return this.set("'+t+'", value)')}(r))}},clipContext:function(t,e){e.save(),e.beginPath(),t.clipTo(e),e.clip()},multiplyTransformMatrices:function(t,e,i){return[t[0]*e[0]+t[2]*e[1],t[1]*e[0]+t[3]*e[1],t[0]*e[2]+t[2]*e[3],t[1]*e[2]+t[3]*e[3],i?0:t[0]*e[4]+t[2]*e[5]+t[4],i?0:t[1]*e[4]+t[3]*e[5]+t[5]]},qrDecompose:function(t){var n=i(t[1],t[0]),o=r(t[0],2)+r(t[1],2),a=e(o),h=(t[0]*t[3]-t[2]*t[1])/a,c=i(t[0]*t[2]+t[1]*t[3],o);return{angle:n/s,scaleX:a,scaleY:h,skewX:c/s,skewY:0,translateX:t[4],translateY:t[5]}},customTransformMatrix:function(t,e,i){var r=[1,0,n(Math.tan(i*s)),1],o=[n(t),0,0,n(e)];return fabric.util.multiplyTransformMatrices(o,r,!0)},resetObjectTransform:function(t){t.scaleX=1,t.scaleY=1,t.skewX=0,t.skewY=0,t.flipX=!1,t.flipY=!1,t.setAngle(0)},getFunctionBody:function(t){return(String(t).match(/function[^{]*\{([\s\S]*)\}/)||{})[1]},isTransparent:function(t,e,i,r){r>0&&(e>r?e-=r:e=0,i>r?i-=r:i=0);for(var n=!0,s=t.getImageData(e,i,2*r||1,2*r||1),o=3,a=s.data.length;o0?I-=2*f:1===c&&I<0&&(I+=2*f);for(var L=Math.ceil(Math.abs(I/f*2)),E=[],D=I/L,R=8/3*Math.sin(D/4)*Math.sin(D/4)/Math.sin(D/2),F=P+D,B=0;B=n?s-n:2*Math.PI-(n-s)}function r(t,e,i,r,n,s,h,c){var l=a.call(arguments);if(o[l])return o[l];var u,f,d,g,p,v,b,m,y=Math.sqrt,_=Math.min,x=Math.max,S=Math.abs,C=[],w=[[],[]];f=6*t-12*i+6*n,u=-3*t+9*i-9*n+3*h,d=3*i-3*t;for(var O=0;O<2;++O)if(O>0&&(f=6*e-12*r+6*s,u=-3*e+9*r-9*s+3*c,d=3*r-3*e),S(u)<1e-12){if(S(f)<1e-12)continue;g=-d/f,0=e})}function i(t,e){return n(t,e,function(t,e){return t>>0;if(0===i)return-1;var r=0;if(arguments.length>0&&(r=Number(arguments[1]),r!==r?r=0:0!==r&&r!==Number.POSITIVE_INFINITY&&r!==Number.NEGATIVE_INFINITY&&(r=(r>0||-1)*Math.floor(Math.abs(r)))),r>=i)return-1;for(var n=r>=0?r:Math.max(i-Math.abs(r),0);n>>0;i>>0;r>>0;i>>0;i>>0;n>>0,r=0;if(arguments.length>1)e=arguments[1];else for(;;){if(r in this){e=this[r++];break}if(++r>=i)throw new TypeError}for(;r/g,">")}String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^[\s\xA0]+/,"").replace(/[\s\xA0]+$/,"")}),fabric.util.string={camelize:t,capitalize:e,escapeXml:i}}(),function(){var t=Array.prototype.slice,e=Function.prototype.apply,i=function(){};Function.prototype.bind||(Function.prototype.bind=function(r){var n,s=this,o=t.call(arguments,1);return n=o.length?function(){return e.call(s,this instanceof i?this:r,o.concat(t.call(arguments)))}:function(){return e.call(s,this instanceof i?this:r,arguments)},i.prototype=this.prototype,n.prototype=new i,n})}(),function(){function t(){}function e(t){var e=this.constructor.superclass.prototype[t];return arguments.length>1?e.apply(this,r.call(arguments,1)):e.call(this)}function i(){function i(){this.initialize.apply(this,arguments)}var s=null,a=r.call(arguments,0);"function"==typeof a[0]&&(s=a.shift()),i.superclass=s,i.subclasses=[],s&&(t.prototype=s.prototype,i.prototype=new t,s.subclasses.push(i));for(var h=0,c=a.length;h-1?t.prototype[r]=function(t){return function(){var r=this.constructor.superclass;this.constructor.superclass=i;var n=e[t].apply(this,arguments);if(this.constructor.superclass=r,"initialize"!==t)return n}}(r):t.prototype[r]=e[r],s&&(e.toString!==Object.prototype.toString&&(t.prototype.toString=e.toString),e.valueOf!==Object.prototype.valueOf&&(t.prototype.valueOf=e.valueOf))};fabric.util.createClass=i}(),function(){function t(t){var e,i,r=Array.prototype.slice.call(arguments,1),n=r.length;for(i=0;i-1?s(t,e.match(/opacity:\s*(\d?\.?\d*)/)[1]):t;for(var r in e)if("opacity"===r)s(t,e[r]);else{var n="float"===r||"cssFloat"===r?"undefined"==typeof i.styleFloat?"cssFloat":"styleFloat":r;i[n]=e[r]}return t}var e=fabric.document.createElement("div"),i="string"==typeof e.style.opacity,r="string"==typeof e.style.filter,n=/alpha\s*\(\s*opacity\s*=\s*([^\)]+)\)/,s=function(t){return t};i?s=function(t,e){return t.style.opacity=e,t}:r&&(s=function(t,e){var i=t.style;return t.currentStyle&&!t.currentStyle.hasLayout&&(i.zoom=1),n.test(i.filter)?(e=e>=.9999?"":"alpha(opacity="+100*e+")",i.filter=i.filter.replace(n,e)):i.filter+=" alpha(opacity="+100*e+")",t}),fabric.util.setStyle=t}(),function(){function t(t){return"string"==typeof t?fabric.document.getElementById(t):t}function e(t,e){var i=fabric.document.createElement(t);for(var r in e)"class"===r?i.className=e[r]:"for"===r?i.htmlFor=e[r]:i.setAttribute(r,e[r]);return i}function i(t,e){t&&(" "+t.className+" ").indexOf(" "+e+" ")===-1&&(t.className+=(t.className?" ":"")+e)}function r(t,i,r){return"string"==typeof i&&(i=e(i,r)),t.parentNode&&t.parentNode.replaceChild(i,t),i.appendChild(t),i}function n(t){for(var e=0,i=0,r=fabric.document.documentElement,n=fabric.document.body||{scrollLeft:0,scrollTop:0};t&&(t.parentNode||t.host)&&(t=t.parentNode||t.host,t===fabric.document?(e=n.scrollLeft||r.scrollLeft||0,i=n.scrollTop||r.scrollTop||0):(e+=t.scrollLeft||0,i+=t.scrollTop||0),1!==t.nodeType||"fixed"!==fabric.util.getElementStyle(t,"position")););return{left:e,top:i}}function s(t){var e,i,r=t&&t.ownerDocument,s={left:0,top:0},o={left:0,top:0},a={borderLeftWidth:"left",borderTopWidth:"top",paddingLeft:"left",paddingTop:"top"};if(!r)return o;for(var h in a)o[a[h]]+=parseInt(c(t,h),10)||0;return e=r.documentElement,"undefined"!=typeof t.getBoundingClientRect&&(s=t.getBoundingClientRect()),i=n(t),{left:s.left+i.left-(e.clientLeft||0)+o.left,top:s.top+i.top-(e.clientTop||0)+o.top}}var o,a=Array.prototype.slice,h=function(t){return a.call(t,0)};try{o=h(fabric.document.childNodes)instanceof Array}catch(t){}o||(h=function(t){for(var e=new Array(t.length),i=t.length;i--;)e[i]=t[i];return e});var c;c=fabric.document.defaultView&&fabric.document.defaultView.getComputedStyle?function(t,e){var i=fabric.document.defaultView.getComputedStyle(t,null);return i?i[e]:void 0}:function(t,e){var i=t.style[e];return!i&&t.currentStyle&&(i=t.currentStyle[e]),i},function(){function t(t){return"undefined"!=typeof t.onselectstart&&(t.onselectstart=fabric.util.falseFunction),r?t.style[r]="none":"string"==typeof t.unselectable&&(t.unselectable="on"),t}function e(t){return"undefined"!=typeof t.onselectstart&&(t.onselectstart=null),r?t.style[r]="":"string"==typeof t.unselectable&&(t.unselectable=""),t}var i=fabric.document.documentElement.style,r="userSelect"in i?"userSelect":"MozUserSelect"in i?"MozUserSelect":"WebkitUserSelect"in i?"WebkitUserSelect":"KhtmlUserSelect"in i?"KhtmlUserSelect":"";fabric.util.makeElementUnselectable=t,fabric.util.makeElementSelectable=e}(),function(){function t(t,e){var i=fabric.document.getElementsByTagName("head")[0],r=fabric.document.createElement("script"),n=!0;r.onload=r.onreadystatechange=function(t){if(n){if("string"==typeof this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)return;n=!1,e(t||fabric.window.event),r=r.onload=r.onreadystatechange=null}},r.src=t,i.appendChild(r)}fabric.util.getScript=t}(),fabric.util.getById=t,fabric.util.toArray=h,fabric.util.makeElement=e,fabric.util.addClass=i,fabric.util.wrapElement=r,fabric.util.getScrollLeftTop=n,fabric.util.getElementOffset=s,fabric.util.getElementStyle=c}(),function(){function t(t,e){return t+(/\?/.test(t)?"&":"?")+e}function e(){}function i(i,n){n||(n={});var s=n.method?n.method.toUpperCase():"GET",o=n.onComplete||function(){},a=r(),h=n.body||n.parameters;return a.onreadystatechange=function(){4===a.readyState&&(o(a),a.onreadystatechange=e)},"GET"===s&&(h=null,"string"==typeof n.parameters&&(i=t(i,n.parameters))),a.open(s,i,!0),"POST"!==s&&"PUT"!==s||a.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),a.send(h),a}var r=function(){for(var t=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP.3.0")},function(){return new XMLHttpRequest}],e=t.length;e--;)try{var i=t[e]();if(i)return t[e]}catch(t){}}();fabric.util.request=i}(),fabric.log=function(){},fabric.warn=function(){},"undefined"!=typeof console&&["log","warn"].forEach(function(t){"undefined"!=typeof console[t]&&"function"==typeof console[t].apply&&(fabric[t]=function(){return console[t].apply(console,arguments)})}),function(){function t(t){e(function(i){t||(t={});var r,n=i||+new Date,s=t.duration||500,o=n+s,a=t.onChange||function(){},h=t.abort||function(){return!1},c=t.easing||function(t,e,i,r){return-i*Math.cos(t/r*(Math.PI/2))+i+e},l="startValue"in t?t.startValue:0,u="endValue"in t?t.endValue:100,f=t.byValue||u-l;t.onStart&&t.onStart(),function i(u){r=u||+new Date;var d=r>o?s:r-n;return h()?void(t.onComplete&&t.onComplete()):(a(c(d,l,f,s)),r>o?void(t.onComplete&&t.onComplete()):void e(i))}(n)})}function e(){return i.apply(fabric.window,arguments)}var i=fabric.window.requestAnimationFrame||fabric.window.webkitRequestAnimationFrame||fabric.window.mozRequestAnimationFrame||fabric.window.oRequestAnimationFrame||fabric.window.msRequestAnimationFrame||function(t){fabric.window.setTimeout(t,1e3/60)};fabric.util.animate=t,fabric.util.requestAnimFrame=e}(),function(){function t(t,e,i,r){return ta?a:o),1===o&&1===a&&0===h&&0===c&&0===f&&0===d)return y;if((f||d)&&(_=" translate("+x(f)+" "+x(d)+") "),r=_+" matrix("+o+" 0 0 "+a+" "+h*o+" "+c*a+") ","svg"===t.nodeName){for(n=t.ownerDocument.createElement("g");null!=t.firstChild;)n.appendChild(t.firstChild);t.appendChild(n)}else n=t,r=n.getAttribute("transform")+r;return n.setAttribute("transform",r),y}function g(t){var e=t.objects,i=t.options;return e=e.map(function(t){return v[m(t.type)].fromObject(t)}),{objects:e,options:i}}function p(t,e,i){e[i]&&e[i].toSVG&&t.push('\t\n','\t\t\n\t\n')}var v=t.fabric||(t.fabric={}),b=v.util.object.extend,m=v.util.string.capitalize,y=v.util.object.clone,_=v.util.toFixed,x=v.util.parseUnit,S=v.util.multiplyTransformMatrices,C=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i,w=/^(symbol|image|marker|pattern|view|svg)$/i,O=/^(?:pattern|defs|symbol|metadata)$/i,T=/^(symbol|g|a|svg)$/i,k={cx:"left",x:"left",r:"radius",cy:"top",y:"top",display:"visible",visibility:"visible",transform:"transformMatrix","fill-opacity":"fillOpacity","fill-rule":"fillRule","font-family":"fontFamily","font-size":"fontSize","font-style":"fontStyle","font-weight":"fontWeight","stroke-dasharray":"strokeDashArray","stroke-linecap":"strokeLineCap","stroke-linejoin":"strokeLineJoin","stroke-miterlimit":"strokeMiterLimit","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","text-decoration":"textDecoration","text-anchor":"originX"},j={stroke:"strokeOpacity",fill:"fillOpacity"};v.cssRules={},v.gradientDefs={},v.parseTransformAttribute=function(){function t(t,e){var i=e[0],r=3===e.length?e[1]:0,n=3===e.length?e[2]:0;t[0]=Math.cos(i),t[1]=Math.sin(i),t[2]=-Math.sin(i),t[3]=Math.cos(i),t[4]=r-(t[0]*r+t[2]*n),t[5]=n-(t[1]*r+t[3]*n)}function e(t,e){var i=e[0],r=2===e.length?e[1]:e[0];t[0]=i,t[3]=r}function i(t,e){t[2]=Math.tan(v.util.degreesToRadians(e[0]))}function r(t,e){t[1]=Math.tan(v.util.degreesToRadians(e[0]))}function n(t,e){t[4]=e[0],2===e.length&&(t[5]=e[1])}var s=[1,0,0,1,0,0],o=v.reNum,a="(?:\\s+,?\\s*|,\\s*)",h="(?:(skewX)\\s*\\(\\s*("+o+")\\s*\\))",c="(?:(skewY)\\s*\\(\\s*("+o+")\\s*\\))",l="(?:(rotate)\\s*\\(\\s*("+o+")(?:"+a+"("+o+")"+a+"("+o+"))?\\s*\\))",u="(?:(scale)\\s*\\(\\s*("+o+")(?:"+a+"("+o+"))?\\s*\\))",f="(?:(translate)\\s*\\(\\s*("+o+")(?:"+a+"("+o+"))?\\s*\\))",d="(?:(matrix)\\s*\\(\\s*("+o+")"+a+"("+o+")"+a+"("+o+")"+a+"("+o+")"+a+"("+o+")"+a+"("+o+")\\s*\\))",g="(?:"+d+"|"+f+"|"+u+"|"+l+"|"+h+"|"+c+")",p="(?:"+g+"(?:"+a+"*"+g+")*)",b="^\\s*(?:"+p+"?)\\s*$",m=new RegExp(b),y=new RegExp(g,"g"); -return function(o){var a=s.concat(),h=[];if(!o||o&&!m.test(o))return a;o.replace(y,function(o){var c=new RegExp(g).exec(o).filter(function(t){return""!==t&&null!=t}),l=c[1],u=c.slice(2).map(parseFloat);switch(l){case"translate":n(a,u);break;case"rotate":u[0]=v.util.degreesToRadians(u[0]),t(a,u);break;case"scale":e(a,u);break;case"skewX":i(a,u);break;case"skewY":r(a,u);break;case"matrix":a=u}h.push(a.concat()),a=s.concat()});for(var c=h[0];h.length>1;)h.shift(),c=v.util.multiplyTransformMatrices(c,h[0]);return c}}();var A=new RegExp("^\\s*("+v.reNum+"+)\\s*,?\\s*("+v.reNum+"+)\\s*,?\\s*("+v.reNum+"+)\\s*,?\\s*("+v.reNum+"+)\\s*$");v.parseSVGDocument=function(){function t(t,e){for(;t&&(t=t.parentNode);)if(t.nodeName&&e.test(t.nodeName.replace("svg:",""))&&!t.getAttribute("instantiated_by_use"))return!0;return!1}return function(e,i,r){if(e){f(e);var n=new Date,s=v.Object.__uid++,o=d(e),a=v.util.toArray(e.getElementsByTagName("*"));if(o.svgUid=s,0===a.length&&v.isLikelyNode){a=e.selectNodes('//*[name(.)!="svg"]');for(var h=[],c=0,l=a.length;c/i,""))),n&&n.documentElement||e&&e(null),v.parseSVGDocument(n.documentElement,function(i,r){M.set(t,{objects:v.util.array.invoke(i,"toObject"),options:r}),e&&e(i,r)},i)}t=t.replace(/^\n\s*/,"").trim(),M.has(t,function(i){i?M.get(t,function(t){var i=g(t);e(i.objects,i.options)}):new v.util.request(t,{method:"get",onComplete:r})})},loadSVGFromString:function(t,e,i){t=t.trim();var r;if("undefined"!=typeof DOMParser){var n=new DOMParser;n&&n.parseFromString&&(r=n.parseFromString(t,"text/xml"))}else v.window.ActiveXObject&&(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(t.replace(//i,"")));v.parseSVGDocument(r.documentElement,function(t,i){e(t,i)},i)},createSVGFontFacesMarkup:function(t){for(var e,i,r,n,s,o,a,h="",c={},l=v.fontPaths,u=0,f=t.length;u',"","\n"].join("")),h},createSVGRefElementsMarkup:function(t){var e=[];return p(e,t,"backgroundColor"),p(e,t,"overlayColor"),e.join("")}})}("undefined"!=typeof exports?exports:this),fabric.ElementsParser=function(t,e,i,r){this.elements=t,this.callback=e,this.options=i,this.reviver=r,this.svgUid=i&&i.svgUid||0},fabric.ElementsParser.prototype.parse=function(){this.instances=new Array(this.elements.length),this.numElements=this.elements.length,this.createObjects()},fabric.ElementsParser.prototype.createObjects=function(){for(var t=0,e=this.elements.length;tt.x&&this.y>t.y},gte:function(t){return this.x>=t.x&&this.y>=t.y},lerp:function(t,i){return"undefined"==typeof i&&(i=.5),i=Math.max(Math.min(1,i),0),new e(this.x+(t.x-this.x)*i,this.y+(t.y-this.y)*i)},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 e(Math.min(this.x,t.x),Math.min(this.y,t.y))},max:function(t){return new e(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 e(this.x,this.y)}}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";function e(t){this.status=t,this.points=[]}var i=t.fabric||(t.fabric={});return i.Intersection?void i.warn("fabric.Intersection is already defined"):(i.Intersection=e,i.Intersection.prototype={constructor:e,appendPoint:function(t){return this.points.push(t),this},appendPoints:function(t){return this.points=this.points.concat(t),this}},i.Intersection.intersectLineLine=function(t,r,n,s){var o,a=(s.x-n.x)*(t.y-n.y)-(s.y-n.y)*(t.x-n.x),h=(r.x-t.x)*(t.y-n.y)-(r.y-t.y)*(t.x-n.x),c=(s.y-n.y)*(r.x-t.x)-(s.x-n.x)*(r.y-t.y);if(0!==c){var l=a/c,u=h/c;0<=l&&l<=1&&0<=u&&u<=1?(o=new e("Intersection"),o.appendPoint(new i.Point(t.x+l*(r.x-t.x),t.y+l*(r.y-t.y)))):o=new e}else o=new e(0===a||0===h?"Coincident":"Parallel");return o},i.Intersection.intersectLinePolygon=function(t,i,r){for(var n,s,o,a=new e,h=r.length,c=0;c0&&(a.status="Intersection"),a},i.Intersection.intersectPolygonPolygon=function(t,i){for(var r=new e,n=t.length,s=0;s0&&(r.status="Intersection"),r},void(i.Intersection.intersectPolygonRectangle=function(t,r,n){var s=r.min(n),o=r.max(n),a=new i.Point(o.x,s.y),h=new i.Point(s.x,o.y),c=e.intersectLinePolygon(s,a,t),l=e.intersectLinePolygon(a,o,t),u=e.intersectLinePolygon(o,h,t),f=e.intersectLinePolygon(h,s,t),d=new e;return d.appendPoints(c.points),d.appendPoints(l.points),d.appendPoints(u.points),d.appendPoints(f.points),d.points.length>0&&(d.status="Intersection"),d}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";function e(t){t?this._tryParsingColor(t):this.setSource([0,0,0,1])}function i(t,e,i){return i<0&&(i+=1),i>1&&(i-=1),i<1/6?t+6*(e-t)*i:i<.5?e:i<2/3?t+(e-t)*(2/3-i)*6:t}var r=t.fabric||(t.fabric={});return r.Color?void r.warn("fabric.Color is already defined."):(r.Color=e,r.Color.prototype={_tryParsingColor:function(t){var i;t in e.colorNameMap&&(t=e.colorNameMap[t]),"transparent"===t&&(i=[255,255,255,0]),i||(i=e.sourceFromHex(t)),i||(i=e.sourceFromRgb(t)),i||(i=e.sourceFromHsl(t)),i||(i=[0,0,0,1]),i&&this.setSource(i)},_rgbToHsl:function(t,e,i){t/=255,e/=255,i/=255;var n,s,o,a=r.util.array.max([t,e,i]),h=r.util.array.min([t,e,i]);if(o=(a+h)/2,a===h)n=s=0;else{var c=a-h;switch(s=o>.5?c/(2-a-h):c/(a+h),a){case t:n=(e-i)/c+(e1?1:s,n){var o=n.split(/\s*;\s*/);""===o[o.length-1]&&o.pop();for(var a=o.length;a--;){var h=o[a].split(/\s*:\s*/),c=h[0].trim(),l=h[1].trim();"stop-color"===c?e=l:"stop-opacity"===c&&(r=l)}}return e||(e=t.getAttribute("stop-color")||"rgb(0,0,0)"),r||(r=t.getAttribute("stop-opacity")),e=new fabric.Color(e),i=e.getAlpha(),r=isNaN(parseFloat(r))?1:parseFloat(r),r*=i,{offset:s,color:e.toRgb(),opacity:r}}function e(t){return{x1:t.getAttribute("x1")||0,y1:t.getAttribute("y1")||0,x2:t.getAttribute("x2")||"100%",y2:t.getAttribute("y2")||0}}function i(t){return{x1:t.getAttribute("fx")||t.getAttribute("cx")||"50%",y1:t.getAttribute("fy")||t.getAttribute("cy")||"50%",r1:0,x2:t.getAttribute("cx")||"50%",y2:t.getAttribute("cy")||"50%",r2:t.getAttribute("r")||"50%"}}function r(t,e,i){var r,n=0,s=1,o="";for(var a in e)"Infinity"===e[a]?e[a]=1:"-Infinity"===e[a]&&(e[a]=0),r=parseFloat(e[a],10),s="string"==typeof e[a]&&/^\d+%$/.test(e[a])?.01:1,"x1"===a||"x2"===a||"r2"===a?(s*="objectBoundingBox"===i?t.width:1,n="objectBoundingBox"===i?t.left||0:0):"y1"!==a&&"y2"!==a||(s*="objectBoundingBox"===i?t.height:1,n="objectBoundingBox"===i?t.top||0:0),e[a]=r*s+n;if("ellipse"===t.type&&null!==e.r2&&"objectBoundingBox"===i&&t.rx!==t.ry){var h=t.ry/t.rx;o=" scale(1, "+h+")",e.y1&&(e.y1/=h),e.y2&&(e.y2/=h)}return o}fabric.Gradient=fabric.util.createClass({offsetX:0,offsetY:0,initialize:function(t){t||(t={});var e={};this.id=fabric.Object.__uid++,this.type=t.type||"linear",e={x1:t.coords.x1||0,y1:t.coords.y1||0,x2:t.coords.x2||0,y2:t.coords.y2||0},"radial"===this.type&&(e.r1=t.coords.r1||0,e.r2=t.coords.r2||0),this.coords=e,this.colorStops=t.colorStops.slice(),t.gradientTransform&&(this.gradientTransform=t.gradientTransform),this.offsetX=t.offsetX||this.offsetX,this.offsetY=t.offsetY||this.offsetY},addColorStop:function(t){for(var e in t){var i=new fabric.Color(t[e]);this.colorStops.push({offset:e,color:i.toRgb(),opacity:i.getAlpha()})}return this},toObject:function(){return{type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY,gradientTransform:this.gradientTransform?this.gradientTransform.concat():this.gradientTransform}},toSVG:function(t){var e,i,r=fabric.util.object.clone(this.coords);if(this.colorStops.sort(function(t,e){return t.offset-e.offset}),!t.group||"path-group"!==t.group.type)for(var n in r)"x1"===n||"x2"===n||"r2"===n?r[n]+=this.offsetX-t.width/2:"y1"!==n&&"y2"!==n||(r[n]+=this.offsetY-t.height/2);i='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"',this.gradientTransform&&(i+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" '),"linear"===this.type?e=["\n']:"radial"===this.type&&(e=["\n']);for(var s=0;s\n');return e.push("linear"===this.type?"\n":"\n"),e.join("")},toLive:function(t,e){var i,r,n=fabric.util.object.clone(this.coords);if(this.type){if(e.group&&"path-group"===e.group.type)for(r in n)"x1"===r||"x2"===r?n[r]+=-this.offsetX+e.width/2:"y1"!==r&&"y2"!==r||(n[r]+=-this.offsetY+e.height/2);"linear"===this.type?i=t.createLinearGradient(n.x1,n.y1,n.x2,n.y2):"radial"===this.type&&(i=t.createRadialGradient(n.x1,n.y1,n.r1,n.x2,n.y2,n.r2));for(var s=0,o=this.colorStops.length;s\n\n\n'},toLive:function(t){var e="function"==typeof this.source?this.source():this.source;if(!e)return"";if("undefined"!=typeof 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 e=t.fabric||(t.fabric={}),i=e.util.toFixed;return e.Shadow?void e.warn("fabric.Shadow is already defined."):(e.Shadow=e.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(t){"string"==typeof t&&(t=this._parseShadow(t));for(var i in t)this[i]=t[i];this.id=e.Object.__uid++},_parseShadow:function(t){var i=t.trim(),r=e.Shadow.reOffsetsAndBlur.exec(i)||[],n=i.replace(e.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)";return{color:n.trim(),offsetX:parseInt(r[1],10)||0,offsetY:parseInt(r[2],10)||0,blur:parseInt(r[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(t){var r=40,n=40,s=e.Object.NUM_FRACTION_DIGITS,o=e.util.rotateVector({x:this.offsetX,y:this.offsetY},e.util.degreesToRadians(-t.angle)),a=20;return t.width&&t.height&&(r=100*i((Math.abs(o.x)+this.blur)/t.width,s)+a,n=100*i((Math.abs(o.y)+this.blur)/t.height,s)+a),t.flipX&&(o.x*=-1),t.flipY&&(o.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};var t={},i=e.Shadow.prototype;return["color","blur","offsetX","offsetY","affectStroke"].forEach(function(e){this[e]!==i[e]&&(t[e]=this[e])},this),t}}),void(e.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/))}("undefined"!=typeof exports?exports:this),function(){"use strict";if(fabric.StaticCanvas)return void fabric.warn("fabric.StaticCanvas is already defined.");var t=fabric.util.object.extend,e=fabric.util.getElementOffset,i=fabric.util.removeFromArray,r=fabric.util.toFixed,n=new Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass({initialize:function(t,e){e||(e={}),this._initStatic(t,e)},backgroundColor:"",backgroundImage:null,overlayColor:"",overlayImage:null,includeDefaultValues:!0,stateful:!0,renderOnAddRemove:!0,clipTo:null,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,viewportTransform:[1,0,0,1,0,0],backgroundVpt:!0,overlayVpt:!0,onBeforeScaleRotate:function(){},enableRetinaScaling:!0,_initStatic:function(t,e){var i=fabric.StaticCanvas.prototype.renderAll.bind(this);this._objects=[],this._createLowerCanvas(t),this._initOptions(e),this._setImageSmoothing(),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(){this._isRetinaScaling()&&(this.lowerCanvasEl.setAttribute("width",this.width*fabric.devicePixelRatio),this.lowerCanvasEl.setAttribute("height",this.height*fabric.devicePixelRatio),this.contextContainer.scale(fabric.devicePixelRatio,fabric.devicePixelRatio))},calcOffset:function(){return this._offset=e(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)},_setImageSmoothing:function(){var t=this.getContext();t.imageSmoothingEnabled=t.imageSmoothingEnabled||t.webkitImageSmoothingEnabled||t.mozImageSmoothingEnabled||t.msImageSmoothingEnabled||t.oImageSmoothingEnabled,t.imageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(t,e,i,r){return"string"==typeof e?fabric.util.loadImage(e,function(e){e&&(this[t]=new fabric.Image(e,r)),i&&i(e)},this,r&&r.crossOrigin):(r&&e.setOptions(r),this[t]=e,i&&i(e)),this},__setBgOverlayColor:function(t,e,i){if(e&&e.source){var r=this;fabric.util.loadImage(e.source,function(n){r[t]=new fabric.Pattern({source:n,repeat:e.repeat,offsetX:e.offsetX,offsetY:e.offsetY}),i&&i()})}else this[t]=e,i&&i();return this},_createCanvasElement:function(){var t=fabric.document.createElement("canvas");if(t.style||(t.style={}),!t)throw n;return this._initCanvasElement(t),t},_initCanvasElement:function(t){if(fabric.util.createCanvasElement(t),"undefined"==typeof t.getContext)throw n},_initOptions:function(t){for(var e in t)this[e]=t[e];this.width=this.width||parseInt(this.lowerCanvasEl.width,10)||0,this.height=this.height||parseInt(this.lowerCanvasEl.height,10)||0,this.lowerCanvasEl.style&&(this.lowerCanvasEl.width=this.width,this.lowerCanvasEl.height=this.height,this.lowerCanvasEl.style.width=this.width+"px",this.lowerCanvasEl.style.height=this.height+"px",this.viewportTransform=this.viewportTransform.slice())},_createLowerCanvas:function(t){this.lowerCanvasEl=fabric.util.getById(t)||this._createCanvasElement(),this._initCanvasElement(this.lowerCanvasEl),fabric.util.addClass(this.lowerCanvasEl,"lower-canvas"),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;e=e||{};for(var r in t)i=t[r],e.cssOnly||(this._setBackstoreDimension(r,t[r]),i+="px"),e.backstoreOnly||this._setCssDimension(r,i);return this._initRetinaScaling(),this._setImageSmoothing(),this.calcOffset(),e.cssOnly||this.renderAll(),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 Math.sqrt(this.viewportTransform[0]*this.viewportTransform[3])},setViewportTransform:function(t){var e=this.getActiveGroup();this.viewportTransform=t;for(var i=0,r=this._objects.length;i"),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,n=e.width||this.width,s=e.height||this.height,o='viewBox="0 0 '+this.width+" "+this.height+'" ',a=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?o='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,o='viewBox="'+r(-i[4]/i[0],a)+" "+r(-i[5]/i[3],a)+" "+r(this.width/i[0],a)+" "+r(this.height/i[3],a)+'" '),t.push("\n',"Created with Fabric.js ",fabric.version,"\n","",fabric.createSVGFontFacesMarkup(this.getObjects()),fabric.createSVGRefElementsMarkup(this),"\n")},_setSVGObjects:function(t,e){for(var i,r,n=0,s=this.getObjects(),o=s.length;n\n"):this[e]&&"overlayColor"===e&&t.push('\n")},sendToBack:function(t){if(!t)return this;var e,r,n,s=this.getActiveGroup?this.getActiveGroup():null;if(t===s)for(n=s._objects,e=n.length;e--;)r=n[e],i(this._objects,r),this._objects.unshift(r);else i(this._objects,t),this._objects.unshift(t);return this.renderAll&&this.renderAll()},bringToFront:function(t){if(!t)return this;var e,r,n,s=this.getActiveGroup?this.getActiveGroup():null;if(t===s)for(n=s._objects,e=0;e=0;--n){var s=t.intersectsWithObject(this._objects[n])||t.isContainedWithinObject(this._objects[n])||this._objects[n].isContainedWithinObject(t);if(s){r=n;break}}}else r=e-1;return r},bringForward:function(t,e){if(!t)return this;var r,n,s,o,a,h=this.getActiveGroup?this.getActiveGroup():null;if(t===h)for(a=h._objects,r=a.length;r--;)n=a[r],s=this._objects.indexOf(n),s!==this._objects.length-1&&(o=s+1,i(this._objects,n),this._objects.splice(o,0,n));else s=this._objects.indexOf(t),s!==this._objects.length-1&&(o=this._findNewUpperIndex(t,s,e),i(this._objects,t),this._objects.splice(o,0,t));return this.renderAll&&this.renderAll(),this},_findNewUpperIndex:function(t,e,i){var r;if(i){r=e;for(var n=e+1;n"}}),t(fabric.StaticCanvas.prototype,fabric.Observable),t(fabric.StaticCanvas.prototype,fabric.Collection),t(fabric.StaticCanvas.prototype,fabric.DataURLExporter),t(fabric.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(t){var e=fabric.util.createCanvasElement();if(!e||!e.getContext)return null;var i=e.getContext("2d");if(!i)return null;switch(t){case"getImageData":return"undefined"!=typeof i.getImageData;case"setLineDash":return"undefined"!=typeof i.setLineDash;case"toDataURL":return"undefined"!=typeof e.toDataURL;case"toDataURLWithQuality":try{return e.toDataURL("image/jpeg",0),!0}catch(t){}return!1;default:return null}}}),fabric.StaticCanvas.prototype.toJSON=fabric.StaticCanvas.prototype.toObject}(),fabric.BaseBrush=fabric.util.createClass({color:"rgb(0, 0, 0)",width:1,shadow:null,strokeLineCap:"round",strokeLineJoin:"round",strokeDashArray:null,setShadow:function(t){return this.shadow=new fabric.Shadow(t),this},_setBrushStyles:function(){var t=this.canvas.contextTop;t.strokeStyle=this.color,t.lineWidth=this.width,t.lineCap=this.strokeLineCap,t.lineJoin=this.strokeLineJoin,this.strokeDashArray&&fabric.StaticCanvas.supports("setLineDash")&&t.setLineDash(this.strokeDashArray)},_setShadow:function(){if(this.shadow){var t=this.canvas.contextTop;t.shadowColor=this.shadow.color,t.shadowBlur=this.shadow.blur,t.shadowOffsetX=this.shadow.offsetX,t.shadowOffsetY=this.shadow.offsetY}},_resetShadow:function(){var t=this.canvas.contextTop;t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0}}),function(){fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{initialize:function(t){this.canvas=t,this._points=[]},onMouseDown:function(t){this._prepareForDrawing(t),this._captureDrawingPath(t),this._render()},onMouseMove:function(t){this._captureDrawingPath(t),this.canvas.clearContext(this.canvas.contextTop),this._render()},onMouseUp:function(){this._finalizeAndAddPath()},_prepareForDrawing:function(t){var e=new fabric.Point(t.x,t.y);this._reset(),this._addPoint(e),this.canvas.contextTop.moveTo(e.x,e.y)},_addPoint:function(t){this._points.push(t)},_reset:function(){this._points.length=0,this._setBrushStyles(),this._setShadow()},_captureDrawingPath:function(t){var e=new fabric.Point(t.x,t.y);this._addPoint(e)},_render:function(){var t=this.canvas.contextTop,e=this.canvas.viewportTransform,i=this._points[0],r=this._points[1];t.save(),t.transform(e[0],e[1],e[2],e[3],e[4],e[5]),t.beginPath(),2===this._points.length&&i.x===r.x&&i.y===r.y&&(i.x-=.5,r.x+=.5),t.moveTo(i.x,i.y);for(var n=1,s=this._points.length;n0?1:-1,"y"===i&&(s=e.target.skewY,o="top",a="bottom",r="originY"),n[-1]=o,n[1]=a,e.target.flipX&&(c*=-1),e.target.flipY&&(c*=-1),0===s?(e.skewSign=-h*t*c,e[r]=n[-t]):(s=s>0?1:-1,e.skewSign=s,e[r]=n[s*h*c])},_skewObject:function(t,e,i){var r=this._currentTransform,n=r.target,s=!1,o=n.get("lockSkewingX"),a=n.get("lockSkewingY");if(o&&"x"===i||a&&"y"===i)return!1;var h,c,l=n.getCenterPoint(),u=n.toLocalPoint(new fabric.Point(t,e),"center","center")[i],f=n.toLocalPoint(new fabric.Point(r.lastX,r.lastY),"center","center")[i],d=n._getTransformedDimensions();return this._changeSkewTransformOrigin(u-f,r,i),h=n.toLocalPoint(new fabric.Point(t,e),r.originX,r.originY)[i],c=n.translateToOriginPoint(l,r.originX,r.originY),s=this._setObjectSkew(h,r,i,d),r.lastX=t,r.lastY=e,n.setPositionByOrigin(c,r.originX,r.originY),s},_setObjectSkew:function(t,e,i,r){var n,s,o,a,h,c,l,u,f,d=e.target,g=!1,p=e.skewSign;return"x"===i?(a="y",h="Y",c="X",u=0,f=d.skewY):(a="x",h="X",c="Y",u=d.skewX,f=0),o=d._getTransformedDimensions(u,f),l=2*Math.abs(t)-o[i],l<=2?n=0:(n=p*Math.atan(l/d["scale"+c]/(o[a]/d["scale"+h])),n=fabric.util.radiansToDegrees(n)),g=d["skew"+c]!==n,d.set("skew"+c,n),0!==d["skew"+h]&&(s=d._getTransformedDimensions(),n=r[a]/s[a]*d["scale"+h],d.set("scale"+h,n)),g},_scaleObject:function(t,e,i){var r=this._currentTransform,n=r.target,s=n.get("lockScalingX"),o=n.get("lockScalingY"),a=n.get("lockScalingFlip");if(s&&o)return!1;var h=n.translateToOriginPoint(n.getCenterPoint(),r.originX,r.originY),c=n.toLocalPoint(new fabric.Point(t,e),r.originX,r.originY),l=n._getTransformedDimensions(),u=!1;return this._setLocalMouse(c,r),u=this._setObjectScale(c,r,s,o,i,a,l),n.setPositionByOrigin(h,r.originX,r.originY),u},_setObjectScale:function(t,e,i,r,n,s,o){var a,h,c,l,u=e.target,f=!1,d=!1,g=!1;return c=t.x*u.scaleX/o.x,l=t.y*u.scaleY/o.y,a=u.scaleX!==c,h=u.scaleY!==l,s&&c<=0&&ci.padding?t.x<0?t.x+=i.padding:t.x-=i.padding:t.x=0,n(t.y)>i.padding?t.y<0?t.y+=i.padding:t.y-=i.padding:t.y=0},_rotateObject:function(t,e){var n=this._currentTransform;if(n.target.get("lockRotation"))return!1;var s=r(n.ey-n.top,n.ex-n.left),o=r(e-n.top,t-n.left),a=i(o-s+n.theta);return a<0&&(a=360+a),n.target.angle=a%360,!0},setCursor:function(t){this.upperCanvasEl.style.cursor=t},_resetObjectTransform:function(t){t.scaleX=1,t.scaleY=1,t.skewX=0,t.skewY=0,t.setAngle(0)},_drawSelection:function(t){var e=this._groupSelector,i=e.left,r=e.top,o=n(i),a=n(r);if(t.fillStyle=this.selectionColor,t.fillRect(e.ex-(i>0?0:-i),e.ey-(r>0?0:-r),o,a),t.lineWidth=this.selectionLineWidth,t.strokeStyle=this.selectionBorderColor,this.selectionDashArray.length>1){var h=e.ex+s-(i>0?0:o),c=e.ey+s-(r>0?0:a);t.beginPath(),fabric.util.drawDashedLine(t,h,c,h+o,c,this.selectionDashArray),fabric.util.drawDashedLine(t,h,c+a-1,h+o,c+a-1,this.selectionDashArray),fabric.util.drawDashedLine(t,h,c,h,c+a,this.selectionDashArray),fabric.util.drawDashedLine(t,h+o-1,c,h+o-1,c+a,this.selectionDashArray),t.closePath(),t.stroke()}else t.strokeRect(e.ex+s-(i>0?0:o),e.ey+s-(r>0?0:a),o,a)},findTarget:function(t,e){if(!this.skipTargetFind){var i=!0,r=this.getPointer(t,i),n=this.getActiveGroup(),s=this.getActiveObject();if(n&&!e&&this._checkTarget(r,n))return n;if(s&&this._checkTarget(r,s))return s;this.targets=[];var o=this._searchPossibleTargets(this._objects,r);return this._fireOverOutEvents(o,t),o}},_fireOverOutEvents:function(t,e){t?this._hoveredTarget!==t&&(this._hoveredTarget&&(this.fire("mouse:out",{target:this._hoveredTarget,e:e}),this._hoveredTarget.fire("mouseout")),this.fire("mouse:over",{target:t,e:e}),t.fire("mouseover"),this._hoveredTarget=t):this._hoveredTarget&&(this.fire("mouse:out",{target:this._hoveredTarget,e:e}),this._hoveredTarget.fire("mouseout"),this._hoveredTarget=null)},_checkTarget:function(t,e){if(e&&e.visible&&e.evented&&this.containsPoint(null,e,t)){if(!this.perPixelTargetFind&&!e.perPixelTargetFind||e.isEditing)return!0;var i=this.isTargetTransparent(e,t.x,t.y);if(!i)return!0}},_searchPossibleTargets:function(t,e){for(var i,r,n,s=t.length;s--;)if(this._checkTarget(e,t[s])){i=t[s],"group"===i.type&&i.subTargetCheck&&(r=this._normalizePointer(i,e),n=this._searchPossibleTargets(i._objects,r),n&&this.targets.push(n));break}return i},restorePointerVpt:function(t){return fabric.util.transformPoint(t,fabric.util.invertTransform(this.viewportTransform))},getPointer:function(e,i,r){r||(r=this.upperCanvasEl);var n,s=t(e),o=r.getBoundingClientRect(),a=o.width||0,h=o.height||0;return a&&h||("top"in o&&"bottom"in o&&(h=Math.abs(o.top-o.bottom)),"right"in o&&"left"in o&&(a=Math.abs(o.right-o.left))),this.calcOffset(),s.x=s.x-this._offset.left,s.y=s.y-this._offset.top,i||(s=this.restorePointerVpt(s)),n=0===a||0===h?{width:1,height:1}:{width:r.width/a,height:r.height/h},{x:s.x*n.width,y:s.y*n.height}},_createUpperCanvas:function(){var t=this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/,"");this.upperCanvasEl=this._createCanvasElement(),fabric.util.addClass(this.upperCanvasEl,"upper-canvas "+t),this.wrapperEl.appendChild(this.upperCanvasEl),this._copyCanvasStyle(this.lowerCanvasEl,this.upperCanvasEl),this._applyCanvasStyle(this.upperCanvasEl),this.contextTop=this.upperCanvasEl.getContext("2d")},_createCacheCanvas:function(){this.cacheCanvasEl=this._createCanvasElement(),this.cacheCanvasEl.setAttribute("width",this.width),this.cacheCanvasEl.setAttribute("height",this.height),this.contextCache=this.cacheCanvasEl.getContext("2d")},_initWrapperElement:function(){this.wrapperEl=fabric.util.wrapElement(this.lowerCanvasEl,"div",{class:this.containerClass}),fabric.util.setStyle(this.wrapperEl,{width:this.getWidth()+"px",height:this.getHeight()+"px",position:"relative"}),fabric.util.makeElementUnselectable(this.wrapperEl)},_applyCanvasStyle:function(t){var e=this.getWidth()||t.width,i=this.getHeight()||t.height;fabric.util.setStyle(t,{position:"absolute",width:e+"px",height:i+"px",left:0,top:0}),t.width=e,t.height=i,fabric.util.makeElementUnselectable(t)},_copyCanvasStyle:function(t,e){e.style.cssText=t.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl},_setActiveObject:function(t){this._activeObject&&this._activeObject.set("active",!1),this._activeObject=t,t.set("active",!0)},setActiveObject:function(t,e){return this._setActiveObject(t),this.renderAll(),this.fire("object:selected",{target:t,e:e}),t.fire("selected",{e:e}),this},getActiveObject:function(){return this._activeObject},_onObjectRemoved:function(t){this.getActiveObject()===t&&(this.fire("before:selection:cleared",{target:t}),this._discardActiveObject(),this.fire("selection:cleared",{target:t}),t.fire("deselected")),this.callSuper("_onObjectRemoved",t)},_discardActiveObject:function(){this._activeObject&&this._activeObject.set("active",!1),this._activeObject=null},discardActiveObject:function(t){var e=this._activeObject;return this.fire("before:selection:cleared",{target:e,e:t}),this._discardActiveObject(),this.fire("selection:cleared",{e:t}),e&&e.fire("deselected",{e:t}),this},_setActiveGroup:function(t){this._activeGroup=t,t&&t.set("active",!0)},setActiveGroup:function(t,e){return this._setActiveGroup(t),t&&(this.fire("object:selected",{target:t,e:e}),t.fire("selected",{e:e})),this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var t=this.getActiveGroup();t&&t.destroy(),this.setActiveGroup(null)},discardActiveGroup:function(t){var e=this.getActiveGroup();return this.fire("before:selection:cleared",{e:t,target:e}),this._discardActiveGroup(),this.fire("selection:cleared",{e:t}),this},deactivateAll:function(){for(var t=this.getObjects(),e=0,i=t.length;e1)){var r=this._groupSelector;r?(i=this.getPointer(t,!0),r.left=i.x-r.ex,r.top=i.y-r.ey,this.renderTop()):this._currentTransform?this._transformObject(t):(e=this.findTarget(t),this._setCursorFromEvent(t,e)),this._handleEvent(t,"move",e?e:null)}},__onMouseWheel:function(t){this.fire("mouse:wheel",{e:t})},_transformObject:function(t){var e=this.getPointer(t),i=this._currentTransform;i.reset=!1,i.target.isMoving=!0,this._beforeScaleTransform(t,i),this._performTransformAction(t,i,e),i.actionPerformed&&this.renderAll()},_performTransformAction:function(t,e,i){var r=i.x,n=i.y,s=e.target,o=e.action,a=!1;"rotate"===o?(a=this._rotateObject(r,n))&&this._fire("rotating",s,t):"scale"===o?(a=this._onScale(t,e,r,n))&&this._fire("scaling",s,t):"scaleX"===o?(a=this._scaleObject(r,n,"x"))&&this._fire("scaling",s,t):"scaleY"===o?(a=this._scaleObject(r,n,"y"))&&this._fire("scaling",s,t):"skewX"===o?(a=this._skewObject(r,n,"x"))&&this._fire("skewing",s,t):"skewY"===o?(a=this._skewObject(r,n,"y"))&&this._fire("skewing",s,t):(a=this._translateObject(r,n),a&&(this._fire("moving",s,t),this.setCursor(s.moveCursor||this.moveCursor))),e.actionPerformed=a},_fire:function(t,e,i){this.fire("object:"+t,{target:e,e:i}),e.fire(t,{e:i})},_beforeScaleTransform:function(t,e){if("scale"===e.action||"scaleX"===e.action||"scaleY"===e.action){var i=this._shouldCenterTransform(e.target);(i&&("center"!==e.originX||"center"!==e.originY)||!i&&"center"===e.originX&&"center"===e.originY)&&(this._resetCurrentTransform(),e.reset=!0)}},_onScale:function(t,e,i,r){return!t[this.uniScaleKey]&&!this.uniScaleTransform||e.target.get("lockUniScaling")?(e.reset||"scale"!==e.currentAction||this._resetCurrentTransform(),e.currentAction="scaleEqually",this._scaleObject(i,r,"equally")):(e.currentAction="scale",this._scaleObject(i,r))},_setCursorFromEvent:function(t,e){if(!e)return this.setCursor(this.defaultCursor),!1;var i=e.hoverCursor||this.hoverCursor;if(e.selectable){var r=this.getActiveGroup(),n=e._findTargetCorner&&(!r||!r.contains(e))&&e._findTargetCorner(this.getPointer(t,!0));n?this._setCornerCursor(n,e,t):this.setCursor(i)}else this.setCursor(i);return!0},_setCornerCursor:function(e,i,r){if(e in t)this.setCursor(this._getRotatedCornerCursor(e,i,r));else{if("mtr"!==e||!i.hasRotatingPoint)return this.setCursor(this.defaultCursor),!1;this.setCursor(this.rotationCursor)}},_getRotatedCornerCursor:function(e,i,r){var n=Math.round(i.getAngle()%360/45);return n<0&&(n+=8),n+=t[e],r[this.altActionKey]&&t[e]%2===0&&(n+=2),n%=8,this.cursorMap[n]}})}(),function(){var t=Math.min,e=Math.max;fabric.util.object.extend(fabric.Canvas.prototype,{_shouldGroup:function(t,e){var i=this.getActiveObject();return t[this.selectionKey]&&e&&e.selectable&&(this.getActiveGroup()||i&&i!==e)&&this.selection},_handleGrouping:function(t,e){var i=this.getActiveGroup();(e!==i||(e=this.findTarget(t,!0)))&&(i?this._updateActiveGroup(e,t):this._createActiveGroup(e,t),this._activeGroup&&this._activeGroup.saveCoords())},_updateActiveGroup:function(t,e){var i=this.getActiveGroup();if(i.contains(t)){if(i.removeWithUpdate(t),t.set("active",!1),1===i.size())return this.discardActiveGroup(e),void this.setActiveObject(i.item(0))}else i.addWithUpdate(t);this.fire("selection:created",{target:i,e:e}),i.set("active",!0)},_createActiveGroup:function(t,e){if(this._activeObject&&t!==this._activeObject){var i=this._createGroup(t);i.addWithUpdate(),this.setActiveGroup(i),this._activeObject=null,this.fire("selection:created",{target:i,e:e})}t.set("active",!0)},_createGroup:function(t){var e=this.getObjects(),i=e.indexOf(this._activeObject)1&&(e=new fabric.Group(e.reverse(),{canvas:this}),e.addWithUpdate(),this.setActiveGroup(e,t),e.saveCoords(),this.fire("selection:created",{target:e}),this.renderAll())},_collectObjects:function(){for(var i,r=[],n=this._groupSelector.ex,s=this._groupSelector.ey,o=n+this._groupSelector.left,a=s+this._groupSelector.top,h=new fabric.Point(t(n,o),t(s,a)),c=new fabric.Point(e(n,o),e(s,a)),l=n===o&&s===a,u=this._objects.length;u--&&(i=this._objects[u],!(i&&i.selectable&&i.visible&&(i.intersectsWithRect(h,c)||i.isContainedWithinRect(h,c)||i.containsPoint(h)||i.containsPoint(c))&&(i.set("active",!0),r.push(i),l))););return r},_maybeGroupObjects:function(t){this.selection&&this._groupSelector&&this._groupSelectedObjects(t);var e=this.getActiveGroup();e&&(e.setObjectsCoords().setCoords(),e.isMoving=!1,this.setCursor(this.defaultCursor)),this._groupSelector=null,this._currentTransform=null}})}(),fabric.util.object.extend(fabric.StaticCanvas.prototype,{toDataURL:function(t){t||(t={});var e=t.format||"png",i=t.quality||1,r=t.multiplier||1,n={left:t.left,top:t.top,width:t.width,height:t.height};return this._isRetinaScaling()&&(r*=fabric.devicePixelRatio),1!==r?this.__toDataURLWithMultiplier(e,i,n,r):this.__toDataURL(e,i,n)},__toDataURL:function(t,e,i){this.renderAll();var r=this.contextContainer.canvas,n=this.__getCroppedCanvas(r,i);"jpg"===t&&(t="jpeg");var s=fabric.StaticCanvas.supports("toDataURLWithQuality")?(n||r).toDataURL("image/"+t,e):(n||r).toDataURL("image/"+t);return n&&(n=null),s},__getCroppedCanvas:function(t,e){var i,r,n="left"in e||"top"in e||"width"in e||"height"in e;return n&&(i=fabric.util.createCanvasElement(),r=i.getContext("2d"),i.width=e.width||this.width,i.height=e.height||this.height,r.drawImage(t,-e.left||0,-e.top||0)),i},__toDataURLWithMultiplier:function(t,e,i,r){var n=this.getWidth(),s=this.getHeight(),o=n*r,a=s*r,h=this.getActiveObject(),c=this.getActiveGroup(),l=this.getZoom(),u=l*r/fabric.devicePixelRatio;r>1&&this.setDimensions({width:o,height:a}),this.setZoom(u),i.left&&(i.left*=r),i.top&&(i.top*=r),i.width?i.width*=r:r<1&&(i.width=o),i.height?i.height*=r:r<1&&(i.height=a),c?this._tempRemoveBordersControlsFromGroup(c):h&&this.deactivateAll&&this.deactivateAll();var f=this.__toDataURL(t,e,i);return c?this._restoreBordersControlsOnGroup(c):h&&this.setActiveObject&&this.setActiveObject(h),this.setZoom(l),this.setDimensions({width:n,height:s}),f},toDataURLWithMultiplier:function(t,e,i){return this.toDataURL({format:t,multiplier:e,quality:i})},_tempRemoveBordersControlsFromGroup:function(t){t.origHasControls=t.hasControls,t.origBorderColor=t.borderColor,t.hasControls=!0,t.borderColor="rgba(0,0,0,0)",t.forEachObject(function(t){t.origBorderColor=t.borderColor,t.borderColor="rgba(0,0,0,0)"})},_restoreBordersControlsOnGroup:function(t){t.hideControls=t.origHideControls,t.borderColor=t.origBorderColor,t.forEachObject(function(t){t.borderColor=t.origBorderColor,delete t.origBorderColor})}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{loadFromDatalessJSON:function(t,e,i){return this.loadFromJSON(t,e,i)},loadFromJSON:function(t,e,i){if(t){var r="string"==typeof t?JSON.parse(t):fabric.util.object.clone(t);this.clear();var n=this;return this._enlivenObjects(r.objects,function(){n._setBgOverlay(r,function(){delete r.objects,delete r.backgroundImage,delete r.overlayImage,delete r.background,delete r.overlay;for(var t in r)n[t]=r[t];e&&e()})},i),this}},_setBgOverlay:function(t,e){var i=this,r={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(!(t.backgroundImage||t.overlayImage||t.background||t.overlay))return void(e&&e());var n=function(){r.backgroundImage&&r.overlayImage&&r.backgroundColor&&r.overlayColor&&(i.renderAll(),e&&e())};this.__setBgOverlay("backgroundImage",t.backgroundImage,r,n),this.__setBgOverlay("overlayImage",t.overlayImage,r,n),this.__setBgOverlay("backgroundColor",t.background,r,n),this.__setBgOverlay("overlayColor",t.overlay,r,n),n()},__setBgOverlay:function(t,e,i,r){var n=this;return e?void("backgroundImage"===t||"overlayImage"===t?fabric.Image.fromObject(e,function(e){n[t]=e,i[t]=!0,r&&r()}):this["set"+fabric.util.string.capitalize(t,!0)](e,function(){i[t]=!0,r&&r()})):void(i[t]=!0)},_enlivenObjects:function(t,e,i){var r=this;if(!t||0===t.length)return void(e&&e());var n=this.renderOnAddRemove;this.renderOnAddRemove=!1,fabric.util.enlivenObjects(t,function(t){t.forEach(function(t,e){r.insertAt(t,e)}),r.renderOnAddRemove=n,e&&e()},null,i)},_toDataURL:function(t,e){this.clone(function(i){e(i.toDataURL(t))})},_toDataURLWithMultiplier:function(t,e,i){this.clone(function(r){i(r.toDataURLWithMultiplier(t,e))})},clone:function(t,e){var i=JSON.stringify(this.toJSON(e));this.cloneWithoutData(function(e){e.loadFromJSON(i,function(){t&&t(e)})})},cloneWithoutData:function(t){var e=fabric.document.createElement("canvas");e.width=this.getWidth(),e.height=this.getHeight();var i=new fabric.Canvas(e);i.clipTo=this.clipTo,this.backgroundImage?(i.setBackgroundImage(this.backgroundImage.src,function(){i.renderAll(),t&&t(i)}),i.backgroundImageOpacity=this.backgroundImageOpacity,i.backgroundImageStretch=this.backgroundImageStretch):t&&t(i)}}),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend,r=e.util.toFixed,n=e.util.string.capitalize,s=e.util.degreesToRadians,o=e.StaticCanvas.supports("setLineDash");e.Object||(e.Object=e.util.createClass({type:"object",originX:"left",originY:"top",top:0,left:0,width:0,height:0,scaleX:1,scaleY:1,flipX:!1,flipY:!1,opacity:1,angle:0,skewX:0,skewY:0,cornerSize:13,transparentCorners:!0,hoverCursor:null,moveCursor:null,padding:0,borderColor:"rgba(102,153,255,0.75)",borderDashArray:null,cornerColor:"rgba(102,153,255,0.5)",cornerStrokeColor:null,cornerStyle:"rect",cornerDashArray:null,centeredScaling:!1,centeredRotation:!0,fill:"rgb(0,0,0)",fillRule:"nonzero",globalCompositeOperation:"source-over",backgroundColor:"",selectionBackgroundColor:"",stroke:null,strokeWidth:1,strokeDashArray:null,strokeLineCap:"butt",strokeLineJoin:"miter",strokeMiterLimit:10,shadow:null,borderOpacityWhenMoving:.4,borderScaleFactor:1,transformMatrix:null,minScaleLimit:.01,selectable:!0,evented:!0,visible:!0,hasControls:!0,hasBorders:!0,hasRotatingPoint:!0,rotatingPointOffset:40,perPixelTargetFind:!1,includeDefaultValues:!0,clipTo:null,lockMovementX:!1,lockMovementY:!1,lockRotation:!1,lockScalingX:!1,lockScalingY:!1,lockUniScaling:!1,lockSkewingX:!1,lockSkewingY:!1,lockScalingFlip:!1,excludeFromExport:!1,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor alignX alignY meetOrSlice skewX skewY".split(" "),initialize:function(t){t&&this.setOptions(t)},_initGradient:function(t){!t.fill||!t.fill.colorStops||t.fill instanceof e.Gradient||this.set("fill",new e.Gradient(t.fill)),!t.stroke||!t.stroke.colorStops||t.stroke instanceof e.Gradient||this.set("stroke",new e.Gradient(t.stroke))},_initPattern:function(t){!t.fill||!t.fill.source||t.fill instanceof e.Pattern||this.set("fill",new e.Pattern(t.fill)),!t.stroke||!t.stroke.source||t.stroke instanceof e.Pattern||this.set("stroke",new e.Pattern(t.stroke))},_initClipping:function(t){if(t.clipTo&&"string"==typeof t.clipTo){var i=e.util.getFunctionBody(t.clipTo);"undefined"!=typeof i&&(this.clipTo=new Function("ctx",i))}},setOptions:function(t){for(var e in t)this.set(e,t[e]);this._initGradient(t),this._initPattern(t),this._initClipping(t)},transform:function(t,e){this.group&&!this.group._transformDone&&this.group===this.canvas._activeGroup&&this.group.transform(t);var i=e?this._getLeftTopCoords():this.getCenterPoint();t.translate(i.x,i.y),t.rotate(s(this.angle)),t.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1)),t.transform(1,0,Math.tan(s(this.skewX)),1,0,0),t.transform(1,Math.tan(s(this.skewY)),0,1,0,0)},toObject:function(t){var i=e.Object.NUM_FRACTION_DIGITS,n={type:this.type,originX:this.originX,originY:this.originY,left:r(this.left,i),top:r(this.top,i),width:r(this.width,i),height:r(this.height,i),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject?this.stroke.toObject():this.stroke,strokeWidth:r(this.strokeWidth,i),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:r(this.strokeMiterLimit,i),scaleX:r(this.scaleX,i),scaleY:r(this.scaleY,i),angle:r(this.getAngle(),i),flipX:this.flipX,flipY:this.flipY,opacity:r(this.opacity,i),shadow:this.shadow&&this.shadow.toObject?this.shadow.toObject():this.shadow,visible:this.visible,clipTo:this.clipTo&&String(this.clipTo),backgroundColor:this.backgroundColor,fillRule:this.fillRule,globalCompositeOperation:this.globalCompositeOperation,transformMatrix:this.transformMatrix?this.transformMatrix.concat():this.transformMatrix,skewX:r(this.skewX,i),skewY:r(this.skewY,i)};return this.includeDefaultValues||(n=this._removeDefaultValues(n)),e.util.populateWithProperties(this,n,t),n},toDatalessObject:function(t){return this.toObject(t)},_removeDefaultValues:function(t){var i=e.util.getKlass(t.type).prototype,r=i.stateProperties;return r.forEach(function(e){t[e]===i[e]&&delete t[e];var r="[object Array]"===Object.prototype.toString.call(t[e])&&"[object Array]"===Object.prototype.toString.call(i[e]);r&&0===t[e].length&&0===i[e].length&&delete t[e]}),t},toString:function(){return"#"},get:function(t){return this[t]},getObjectScaling:function(){var t=this.scaleX,e=this.scaleY;if(this.group){var i=this.group.getObjectScaling();t*=i.scaleX,e*=i.scaleY}return{scaleX:t,scaleY:e}},_setObject:function(t){for(var e in t)this._set(e,t[e])},set:function(t,e){return"object"==typeof t?this._setObject(t):"function"==typeof e&&"clipTo"!==t?this._set(t,e(this.get(t))):this._set(t,e),this},_set:function(t,i){var r="scaleX"===t||"scaleY"===t;return r&&(i=this._constrainScale(i)),"scaleX"===t&&i<0?(this.flipX=!this.flipX,i*=-1):"scaleY"===t&&i<0?(this.flipY=!this.flipY,i*=-1):"shadow"!==t||!i||i instanceof e.Shadow||(i=new e.Shadow(i)),this[t]=i,"width"!==t&&"height"!==t||(this.minScaleLimit=Math.min(.1,1/Math.max(this.width,this.height))),this},setOnGroup:function(){},toggle:function(t){var e=this.get(t);return"boolean"==typeof e&&this.set(t,!e),this},setSourcePath:function(t){return this.sourcePath=t,this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:[1,0,0,1,0,0]},render:function(t,i){0===this.width&&0===this.height||!this.visible||(t.save(),this._setupCompositeOperation(t),this.drawSelectionBackground(t),i||this.transform(t),this._setStrokeStyles(t),this._setFillStyles(t),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this._setOpacity(t),this._setShadow(t),this.clipTo&&e.util.clipContext(this,t),this._render(t,i),this.clipTo&&t.restore(),t.restore())},_setOpacity:function(t){this.group&&this.group._setOpacity(t),t.globalAlpha*=this.opacity},_setStrokeStyles:function(t){this.stroke&&(t.lineWidth=this.strokeWidth,t.lineCap=this.strokeLineCap,t.lineJoin=this.strokeLineJoin,t.miterLimit=this.strokeMiterLimit,t.strokeStyle=this.stroke.toLive?this.stroke.toLive(t,this):this.stroke)},_setFillStyles:function(t){this.fill&&(t.fillStyle=this.fill.toLive?this.fill.toLive(t,this):this.fill)},_setLineDash:function(t,e,i){e&&(1&e.length&&e.push.apply(e,e),o?t.setLineDash(e):i&&i(t))},_renderControls:function(t,i){if(!(!this.active||i||this.group&&this.group!==this.canvas.getActiveGroup())){var r,n=this.getViewportTransform(),o=this.calcTransformMatrix();o=e.util.multiplyTransformMatrices(n,o),r=e.util.qrDecompose(o),t.save(),t.translate(r.translateX,r.translateY),t.lineWidth=1*this.borderScaleFactor,t.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,this.group&&this.group===this.canvas.getActiveGroup()?(t.rotate(s(r.angle)),this.drawBordersInGroup(t,r)):(t.rotate(s(this.angle)),this.drawBorders(t)),this.drawControls(t),t.restore()}},_setShadow:function(t){if(this.shadow){var i=this.canvas&&this.canvas.viewportTransform[0]||1,r=this.canvas&&this.canvas.viewportTransform[3]||1,n=this.getObjectScaling();this.canvas&&this.canvas._isRetinaScaling()&&(i*=e.devicePixelRatio,r*=e.devicePixelRatio),t.shadowColor=this.shadow.color,t.shadowBlur=this.shadow.blur*(i+r)*(n.scaleX+n.scaleY)/4,t.shadowOffsetX=this.shadow.offsetX*i*n.scaleX,t.shadowOffsetY=this.shadow.offsetY*r*n.scaleY}},_removeShadow:function(t){this.shadow&&(t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0)},_renderFill:function(t){if(this.fill){if(t.save(),this.fill.gradientTransform){var e=this.fill.gradientTransform;t.transform.apply(t,e)}this.fill.toLive&&t.translate(-this.width/2+this.fill.offsetX||0,-this.height/2+this.fill.offsetY||0),"evenodd"===this.fillRule?t.fill("evenodd"):t.fill(),t.restore()}},_renderStroke:function(t){if(this.stroke&&0!==this.strokeWidth){if(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(t),t.save(),this._setLineDash(t,this.strokeDashArray,this._renderDashedStroke),this.stroke.gradientTransform){var e=this.stroke.gradientTransform;t.transform.apply(t,e)}this.stroke.toLive&&t.translate(-this.width/2+this.stroke.offsetX||0,-this.height/2+this.stroke.offsetY||0),t.stroke(),t.restore()}},clone:function(t,i){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(i),t):new e.Object(this.toObject(i))},cloneAsImage:function(t,i){var r=this.toDataURL(i);return e.util.loadImage(r,function(i){t&&t(new e.Image(i))}),this},toDataURL:function(t){t||(t={});var i=e.util.createCanvasElement(),r=this.getBoundingRect();i.width=r.width,i.height=r.height,e.util.wrapElement(i,"div");var n=new e.StaticCanvas(i,{enableRetinaScaling:t.enableRetinaScaling});"jpg"===t.format&&(t.format="jpeg"),"jpeg"===t.format&&(n.backgroundColor="#fff");var s={active:this.get("active"),left:this.getLeft(),top:this.getTop()};this.set("active",!1),this.setPositionByOrigin(new e.Point(n.getWidth()/2,n.getHeight()/2),"center","center");var o=this.canvas;n.add(this);var a=n.toDataURL(t);return this.set(s).setCoords(),this.canvas=o,n.dispose(),n=null,a},isType:function(t){return this.type===t},complexity:function(){return 0},toJSON:function(t){return this.toObject(t)},setGradient:function(t,i){i||(i={});var r={colorStops:[]};r.type=i.type||(i.r1||i.r2?"radial":"linear"),r.coords={x1:i.x1,y1:i.y1,x2:i.x2,y2:i.y2},(i.r1||i.r2)&&(r.coords.r1=i.r1,r.coords.r2=i.r2),i.gradientTransform&&(r.gradientTransform=i.gradientTransform);for(var n in i.colorStops){var s=new e.Color(i.colorStops[n]);r.colorStops.push({offset:n,color:s.toRgb(),opacity:s.getAlpha()})}return this.set(t,e.Gradient.forObject(this,r))},setPatternFill:function(t){return this.set("fill",new e.Pattern(t))},setShadow:function(t){return this.set("shadow",t?new e.Shadow(t):null)},setColor:function(t){return this.set("fill",t),this},setAngle:function(t){var e=("center"!==this.originX||"center"!==this.originY)&&this.centeredRotation;return e&&this._setOriginToCenter(),this.set("angle",t),e&&this._resetOrigin(),this},centerH:function(){return this.canvas&&this.canvas.centerObjectH(this),this},viewportCenterH:function(){return this.canvas&&this.canvas.viewportCenterObjectH(this),this},centerV:function(){return this.canvas&&this.canvas.centerObjectV(this),this},viewportCenterV:function(){return this.canvas&&this.canvas.viewportCenterObjectV(this),this},center:function(){return this.canvas&&this.canvas.centerObject(this),this},viewportCenter:function(){return this.canvas&&this.canvas.viewportCenterObject(this),this},remove:function(){return this.canvas&&this.canvas.remove(this),this},getLocalPointer:function(t,i){i=i||this.canvas.getPointer(t);var r=new e.Point(i.x,i.y),n=this._getLeftTopCoords();return this.angle&&(r=e.util.rotatePoint(r,n,e.util.degreesToRadians(-this.angle))),{x:r.x-n.x,y:r.y-n.y}},_setupCompositeOperation:function(t){this.globalCompositeOperation&&(t.globalCompositeOperation=this.globalCompositeOperation)}}),e.util.createAccessors(e.Object),e.Object.prototype.rotate=e.Object.prototype.setAngle,i(e.Object.prototype,e.Observable),e.Object.NUM_FRACTION_DIGITS=2,e.Object.__uid=0)}("undefined"!=typeof exports?exports:this),function(){var t=fabric.util.degreesToRadians,e={left:-.5,center:0,right:.5},i={top:-.5,center:0,bottom:.5};fabric.util.object.extend(fabric.Object.prototype,{translateToGivenOrigin:function(t,r,n,s,o){var a,h,c,l=t.x,u=t.y;return"string"==typeof r?r=e[r]:r-=.5,"string"==typeof s?s=e[s]:s-=.5,a=s-r,"string"==typeof n?n=i[n]:n-=.5,"string"==typeof o?o=i[o]:o-=.5,h=o-n,(a||h)&&(c=this._getTransformedDimensions(),l=t.x+a*c.x,u=t.y+h*c.y),new fabric.Point(l,u)},translateToCenterPoint:function(e,i,r){var n=this.translateToGivenOrigin(e,i,r,"center","center");return this.angle?fabric.util.rotatePoint(n,e,t(this.angle)):n},translateToOriginPoint:function(e,i,r){var n=this.translateToGivenOrigin(e,"center","center",i,r);return this.angle?fabric.util.rotatePoint(n,e,t(this.angle)):n},getCenterPoint:function(){var t=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(t,this.originX,this.originY)},getPointByOrigin:function(t,e){var i=this.getCenterPoint();return this.translateToOriginPoint(i,t,e)},toLocalPoint:function(e,i,r){var n,s,o=this.getCenterPoint();return n="undefined"!=typeof i&&"undefined"!=typeof r?this.translateToGivenOrigin(o,"center","center",i,r):new fabric.Point(this.left,this.top),s=new fabric.Point(e.x,e.y),this.angle&&(s=fabric.util.rotatePoint(s,o,-t(this.angle))),s.subtractEquals(n)},setPositionByOrigin:function(t,e,i){var r=this.translateToCenterPoint(t,e,i),n=this.translateToOriginPoint(r,this.originX,this.originY);this.set("left",n.x),this.set("top",n.y)},adjustPosition:function(i){var r,n,s=t(this.angle),o=this.getWidth(),a=Math.cos(s)*o,h=Math.sin(s)*o;r="string"==typeof this.originX?e[this.originX]:this.originX-.5,n="string"==typeof i?e[i]:i-.5,this.left+=a*(n-r),this.top+=h*(n-r),this.setCoords(),this.originX=i},_setOriginToCenter:function(){this._originalOriginX=this.originX,this._originalOriginY=this.originY;var t=this.getCenterPoint();this.originX="center",this.originY="center",this.left=t.x,this.top=t.y},_resetOrigin:function(){var t=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX,this._originalOriginY);this.originX=this._originalOriginX,this.originY=this._originalOriginY,this.left=t.x,this.top=t.y,this._originalOriginX=null,this._originalOriginY=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),"left","top")}})}(),function(){function t(t){return[new fabric.Point(t.tl.x,t.tl.y),new fabric.Point(t.tr.x,t.tr.y),new fabric.Point(t.br.x,t.br.y),new fabric.Point(t.bl.x,t.bl.y)]}var e=fabric.util.degreesToRadians,i=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,intersectsWithRect:function(e,i){var r=t(this.oCoords),n=fabric.Intersection.intersectPolygonRectangle(r,e,i);return"Intersection"===n.status},intersectsWithObject:function(e){var i=fabric.Intersection.intersectPolygonPolygon(t(this.oCoords),t(e.oCoords));return"Intersection"===i.status},isContainedWithinObject:function(t){var e=t.getBoundingRect(),i=new fabric.Point(e.left,e.top),r=new fabric.Point(e.left+e.width,e.top+e.height);return this.isContainedWithinRect(i,r)},isContainedWithinRect:function(t,e){var i=this.getBoundingRect();return i.left>=t.x&&i.left+i.width<=e.x&&i.top>=t.y&&i.top+i.height<=e.y},containsPoint:function(t){this.oCoords||this.setCoords();var e=this._getImageLines(this.oCoords),i=this._findCrossPoints(t,e);return 0!==i&&i%2===1},_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,o,a,h,c=0;for(var l in e)if(h=e[l],!(h.o.y=t.y&&h.d.y>=t.y||(h.o.x===h.d.x&&h.o.x>=t.x?(o=h.o.x,a=t.y):(i=0,r=(h.d.y-h.o.y)/(h.d.x-h.o.x),n=t.y-i*t.x,s=h.o.y-r*h.o.x,o=-(n-s)/(i-r),a=n+i*o),o>=t.x&&(c+=1),2!==c)))break;return c},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(){return this.oCoords||this.setCoords(),fabric.util.makeBoundingBoxFromPoints([this.oCoords.tl,this.oCoords.tr,this.oCoords.br,this.oCoords.bl])},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(t){return Math.abs(t)0?Math.atan(s/n):0,c=n/Math.cos(h)/2,l=Math.cos(h+t)*c,u=Math.sin(h+t)*c,f=fabric.util.transformPoint(this.getCenterPoint(),i),d=new fabric.Point(f.x-l,f.y-u),g=new fabric.Point(d.x+n*a,d.y+n*o),p=new fabric.Point(d.x-s*o,d.y+s*a),v=new fabric.Point(f.x+l,f.y+u),b=new fabric.Point((d.x+p.x)/2,(d.y+p.y)/2),m=new fabric.Point((g.x+d.x)/2,(g.y+d.y)/2),y=new fabric.Point((v.x+g.x)/2,(v.y+g.y)/2),_=new fabric.Point((v.x+p.x)/2,(v.y+p.y)/2),x=new fabric.Point(m.x+o*this.rotatingPointOffset,m.y-a*this.rotatingPointOffset);return this.oCoords={tl:d,tr:g,br:v,bl:p,ml:b,mt:m,mr:y,mb:_,mtr:x},this._setCornerCoords&&this._setCornerCoords(),this},_calcRotateMatrix:function(){if(this.angle){var t=e(this.angle),i=Math.cos(t),r=Math.sin(t);return[i,r,-r,i,0,0]}return[1,0,0,1,0,0]},calcTransformMatrix:function(){var t=this.getCenterPoint(),e=[1,0,0,1,t.x,t.y],r=this._calcRotateMatrix(),n=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0),s=this.group?this.group.calcTransformMatrix():[1,0,0,1,0,0];return s=i(s,e),s=i(s,r),s=i(s,n)},_calcDimensionsTransformMatrix:function(t,r,n){var s=[1,0,Math.tan(e(t)),1],o=[1,Math.tan(e(r)),0,1],a=this.scaleX*(n&&this.flipX?-1:1),h=this.scaleY*(n&&this.flipY?-1:1),c=[a,0,0,h],l=i(c,s,!0);return i(l,o,!0)}})}(),fabric.util.object.extend(fabric.Object.prototype,{sendToBack:function(){return this.group?fabric.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this),this},bringToFront:function(){return this.group?fabric.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this), -this},sendBackwards:function(t){return this.group?fabric.StaticCanvas.prototype.sendBackwards.call(this.group,this,t):this.canvas.sendBackwards(this,t),this},bringForward:function(t){return this.group?fabric.StaticCanvas.prototype.bringForward.call(this.group,this,t):this.canvas.bringForward(this,t),this},moveTo:function(t){return this.group?fabric.StaticCanvas.prototype.moveTo.call(this.group,this,t):this.canvas.moveTo(this,t),this}}),function(){function t(t,e){if(e){if(e.toLive)return t+": url(#SVGID_"+e.id+"); ";var i=new fabric.Color(e),r=t+": "+i.toRgb()+"; ",n=i.getAlpha();return 1!==n&&(r+=t+"-opacity: "+n.toString()+"; "),r}return t+": none; "}fabric.util.object.extend(fabric.Object.prototype,{getSvgStyles:function(e){var i=this.fillRule,r=this.strokeWidth?this.strokeWidth:"0",n=this.strokeDashArray?this.strokeDashArray.join(" "):"none",s=this.strokeLineCap?this.strokeLineCap:"butt",o=this.strokeLineJoin?this.strokeLineJoin:"miter",a=this.strokeMiterLimit?this.strokeMiterLimit:"4",h="undefined"!=typeof this.opacity?this.opacity:"1",c=this.visible?"":" visibility: hidden;",l=e?"":this.getSvgFilter(),u=t("fill",this.fill),f=t("stroke",this.stroke);return[f,"stroke-width: ",r,"; ","stroke-dasharray: ",n,"; ","stroke-linecap: ",s,"; ","stroke-linejoin: ",o,"; ","stroke-miterlimit: ",a,"; ",u,"fill-rule: ",i,"; ","opacity: ",h,";",l,c].join("")},getSvgFilter:function(){return this.shadow?"filter: url(#SVGID_"+this.shadow.id+");":""},getSvgId:function(){return this.id?'id="'+this.id+'" ':""},getSvgTransform:function(){if(this.group&&"path-group"===this.group.type)return"";var t=fabric.util.toFixed,e=this.getAngle(),i=this.getSkewX()%360,r=this.getSkewY()%360,n=this.getCenterPoint(),s=fabric.Object.NUM_FRACTION_DIGITS,o="path-group"===this.type?"":"translate("+t(n.x,s)+" "+t(n.y,s)+")",a=0!==e?" rotate("+t(e,s)+")":"",h=1===this.scaleX&&1===this.scaleY?"":" scale("+t(this.scaleX,s)+" "+t(this.scaleY,s)+")",c=0!==i?" skewX("+t(i,s)+")":"",l=0!==r?" skewY("+t(r,s)+")":"",u="path-group"===this.type?this.width:0,f=this.flipX?" matrix(-1 0 0 1 "+u+" 0) ":"",d="path-group"===this.type?this.height:0,g=this.flipY?" matrix(1 0 0 -1 0 "+d+")":"";return[o,a,h,f,g,c,l].join("")},getSvgTransformMatrix:function(){return this.transformMatrix?" matrix("+this.transformMatrix.join(" ")+") ":""},_createBaseSVGMarkup:function(){var t=[];return this.fill&&this.fill.toLive&&t.push(this.fill.toSVG(this,!1)),this.stroke&&this.stroke.toLive&&t.push(this.stroke.toSVG(this,!1)),this.shadow&&t.push(this.shadow.toSVG(this)),t}})}(),fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(){return this.stateProperties.some(function(t){return this.get(t)!==this.originalState[t]},this)},saveState:function(t){return this.stateProperties.forEach(function(t){this.originalState[t]=this.get(t)},this),t&&t.stateProperties&&t.stateProperties.forEach(function(t){this.originalState[t]=this.get(t)},this),this},setupState:function(){return this.originalState={},this.saveState(),this}}),function(){var t=fabric.util.degreesToRadians,e=function(){return"undefined"!=typeof G_vmlCanvasManager};fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(t){if(!this.hasControls||!this.active)return!1;var e,i,r=t.x,n=t.y;this.__corner=0;for(var s in this.oCoords)if(this.isControlVisible(s)&&("mtr"!==s||this.hasRotatingPoint)&&(!this.get("lockUniScaling")||"mt"!==s&&"mr"!==s&&"mb"!==s&&"ml"!==s)&&(i=this._getImageLines(this.oCoords[s].corner),e=this._findCrossPoints({x:r,y:n},i),0!==e&&e%2===1))return this.__corner=s,s;return!1},_setCornerCoords:function(){var e,i,r=this.oCoords,n=t(45-this.angle),s=.707106*this.cornerSize,o=s*Math.cos(n),a=s*Math.sin(n);for(var h in r)e=r[h].x,i=r[h].y,r[h].corner={tl:{x:e-a,y:i-o},tr:{x:e+o,y:i-a},bl:{x:e-o,y:i+a},br:{x:e+a,y:i+o}}},_getNonTransformedDimensions:function(){var t=this.strokeWidth,e=this.width,i=this.height,r=!0,n=!0;return"line"===this.type&&"butt"===this.strokeLineCap&&(n=e,r=i),n&&(i+=i<0?-t:t),r&&(e+=e<0?-t:t),{x:e,y:i}},_getTransformedDimensions:function(t,e){"undefined"==typeof t&&(t=this.skewX),"undefined"==typeof e&&(e=this.skewY);var i,r,n=this._getNonTransformedDimensions(),s=n.x/2,o=n.y/2,a=[{x:-s,y:-o},{x:s,y:-o},{x:-s,y:o},{x:s,y:o}],h=this._calcDimensionsTransformMatrix(t,e,!1);for(i=0;i\n'),t?t(e.join("")):e.join("")},complexity:function(){return 1}}),i.Line.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),i.Line.fromElement=function(t,e){var n=i.parseAttributes(t,i.Line.ATTRIBUTE_NAMES),s=[n.x1||0,n.y1||0,n.x2||0,n.y2||0];return new i.Line(s,r(n,e))},void(i.Line.fromObject=function(t){var e=[t.x1,t.y1,t.x2,t.y2];return new i.Line(e,t)}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";function e(t){return"radius"in t&&t.radius>=0}var i=t.fabric||(t.fabric={}),r=Math.PI,n=i.util.object.extend;return i.Circle?void i.warn("fabric.Circle is already defined."):(i.Circle=i.util.createClass(i.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*r,initialize:function(t){t=t||{},this.callSuper("initialize",t),this.set("radius",t.radius||0),this.startAngle=t.startAngle||this.startAngle,this.endAngle=t.endAngle||this.endAngle},_set:function(t,e){return this.callSuper("_set",t,e),"radius"===t&&this.setRadius(e),this},toObject:function(t){return n(this.callSuper("toObject",t),{radius:this.get("radius"),startAngle:this.startAngle,endAngle:this.endAngle})},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=0,n=0,s=(this.endAngle-this.startAngle)%(2*r);if(0===s)this.group&&"path-group"===this.group.type&&(i=this.left+this.radius,n=this.top+this.radius),e.push("\n');else{var o=Math.cos(this.startAngle)*this.radius,a=Math.sin(this.startAngle)*this.radius,h=Math.cos(this.endAngle)*this.radius,c=Math.sin(this.endAngle)*this.radius,l=s>r?"1":"0";e.push('\n')}return t?t(e.join("")):e.join("")},_render:function(t,e){t.beginPath(),t.arc(e?this.left+this.radius:0,e?this.top+this.radius:0,this.radius,this.startAngle,this.endAngle,!1),this._renderFill(t),this._renderStroke(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)},complexity:function(){return 1}}),i.Circle.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),i.Circle.fromElement=function(t,r){r||(r={});var s=i.parseAttributes(t,i.Circle.ATTRIBUTE_NAMES);if(!e(s))throw new Error("value of `r` attribute is required and can not be negative");s.left=s.left||0,s.top=s.top||0;var o=new i.Circle(n(s,r));return o.left-=o.radius,o.top-=o.radius,o},void(i.Circle.fromObject=function(t){return new i.Circle(t)}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={});return e.Triangle?void e.warn("fabric.Triangle is already defined"):(e.Triangle=e.util.createClass(e.Object,{type:"triangle",initialize:function(t){t=t||{},this.callSuper("initialize",t),this.set("width",t.width||100).set("height",t.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._renderFill(t),this._renderStroke(t)},_renderDashedStroke:function(t){var i=this.width/2,r=this.height/2;t.beginPath(),e.util.drawDashedLine(t,-i,r,0,-r,this.strokeDashArray),e.util.drawDashedLine(t,0,-r,i,r,this.strokeDashArray),e.util.drawDashedLine(t,i,r,-i,r,this.strokeDashArray),t.closePath()},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=this.width/2,r=this.height/2,n=[-i+" "+r,"0 "+-r,i+" "+r].join(",");return e.push("'),t?t(e.join("")):e.join("")},complexity:function(){return 1}}),void(e.Triangle.fromObject=function(t){return new e.Triangle(t)}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=2*Math.PI,r=e.util.object.extend;return e.Ellipse?void e.warn("fabric.Ellipse is already defined."):(e.Ellipse=e.util.createClass(e.Object,{type:"ellipse",rx:0,ry:0,initialize:function(t){t=t||{},this.callSuper("initialize",t),this.set("rx",t.rx||0),this.set("ry",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 r(this.callSuper("toObject",t),{rx:this.get("rx"),ry:this.get("ry")})},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=0,r=0;return this.group&&"path-group"===this.group.type&&(i=this.left+this.rx,r=this.top+this.ry),e.push("\n'),t?t(e.join("")):e.join("")},_render:function(t,e){t.beginPath(),t.save(),t.transform(1,0,0,this.ry/this.rx,0,0),t.arc(e?this.left+this.rx:0,e?(this.top+this.ry)*this.rx/this.ry:0,this.rx,0,i,!1),t.restore(),this._renderFill(t),this._renderStroke(t)},complexity:function(){return 1}}),e.Ellipse.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("cx cy rx ry".split(" ")),e.Ellipse.fromElement=function(t,i){i||(i={});var n=e.parseAttributes(t,e.Ellipse.ATTRIBUTE_NAMES);n.left=n.left||0,n.top=n.top||0;var s=new e.Ellipse(r(n,i));return s.top-=s.ry,s.left-=s.rx,s},void(e.Ellipse.fromObject=function(t){return new e.Ellipse(t)}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;if(e.Rect)return void e.warn("fabric.Rect is already defined");var r=e.Object.prototype.stateProperties.concat();r.push("rx","ry","x","y"),e.Rect=e.util.createClass(e.Object,{stateProperties:r,type:"rect",rx:0,ry:0,strokeDashArray:null,initialize:function(t){t=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,e){if(1===this.width&&1===this.height)return void t.fillRect(-.5,-.5,1,1);var i=this.rx?Math.min(this.rx,this.width/2):0,r=this.ry?Math.min(this.ry,this.height/2):0,n=this.width,s=this.height,o=e?this.left:-this.width/2,a=e?this.top:-this.height/2,h=0!==i||0!==r,c=.4477152502;t.beginPath(),t.moveTo(o+i,a),t.lineTo(o+n-i,a),h&&t.bezierCurveTo(o+n-c*i,a,o+n,a+c*r,o+n,a+r),t.lineTo(o+n,a+s-r),h&&t.bezierCurveTo(o+n,a+s-c*r,o+n-c*i,a+s,o+n-i,a+s),t.lineTo(o+i,a+s),h&&t.bezierCurveTo(o+c*i,a+s,o,a+s-c*r,o,a+s-r),t.lineTo(o,a+r),h&&t.bezierCurveTo(o,a+c*r,o+c*i,a,o+i,a),t.closePath(),this._renderFill(t),this._renderStroke(t)},_renderDashedStroke:function(t){var i=-this.width/2,r=-this.height/2,n=this.width,s=this.height;t.beginPath(),e.util.drawDashedLine(t,i,r,i+n,r,this.strokeDashArray),e.util.drawDashedLine(t,i+n,r,i+n,r+s,this.strokeDashArray),e.util.drawDashedLine(t,i+n,r+s,i,r+s,this.strokeDashArray),e.util.drawDashedLine(t,i,r+s,i,r,this.strokeDashArray),t.closePath()},toObject:function(t){var e=i(this.callSuper("toObject",t),{rx:this.get("rx")||0,ry:this.get("ry")||0});return this.includeDefaultValues||this._removeDefaultValues(e),e},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=this.left,r=this.top;return this.group&&"path-group"===this.group.type||(i=-this.width/2,r=-this.height/2),e.push("\n'),t?t(e.join("")):e.join("")},complexity:function(){return 1}}),e.Rect.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),e.Rect.fromElement=function(t,r){if(!t)return null;r=r||{};var n=e.parseAttributes(t,e.Rect.ATTRIBUTE_NAMES);n.left=n.left||0,n.top=n.top||0;var s=new e.Rect(i(r?e.util.object.clone(r):{},n));return s.visible=s.visible&&s.width>0&&s.height>0,s},e.Rect.fromObject=function(t){return new e.Rect(t)}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={});return e.Polyline?void e.warn("fabric.Polyline is already defined"):(e.Polyline=e.util.createClass(e.Object,{type:"polyline",points:null,minX:0,minY:0,initialize:function(t,i){return e.Polygon.prototype.initialize.call(this,t,i)},_calcDimensions:function(){return e.Polygon.prototype._calcDimensions.call(this)},toObject:function(t){return e.Polygon.prototype.toObject.call(this,t)},toSVG:function(t){return e.Polygon.prototype.toSVG.call(this,t)},_render:function(t,i){e.Polygon.prototype.commonRender.call(this,t,i)&&(this._renderFill(t),this._renderStroke(t))},_renderDashedStroke:function(t){var i,r;t.beginPath();for(var n=0,s=this.points.length;n\n'),t?t(r.join("")):r.join("")},_render:function(t,e){this.commonRender(t,e)&&(this._renderFill(t),(this.stroke||this.strokeDashArray)&&(t.closePath(),this._renderStroke(t)))},commonRender:function(t,e){var i,r=this.points.length;if(!r||isNaN(this.points[r-1].y))return!1;e||t.translate(-this.pathOffset.x,-this.pathOffset.y),t.beginPath(),t.moveTo(this.points[0].x,this.points[0].y);for(var n=0;n"},toObject:function(t){var e=n(this.callSuper("toObject",t),{path:this.path.map(function(t){return t.slice()}),pathOffset:this.pathOffset});return this.sourcePath&&(e.sourcePath=this.sourcePath),this.transformMatrix&&(e.transformMatrix=this.transformMatrix),e},toDatalessObject:function(t){var e=this.toObject(t);return this.sourcePath&&(e.path=this.sourcePath),delete e.sourcePath,e},toSVG:function(t){for(var e=[],i=this._createBaseSVGMarkup(),r="",n=0,s=this.path.length;n\n"),t?t(i.join("")):i.join("")},complexity:function(){return this.path.length},_parsePath:function(){for(var t,e,i,r,n,s=[],o=[],c=/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi,l=0,u=this.path.length;lp)for(var b=1,m=n.length;b\n");for(var s=0,o=e.length;s\n"),t?t(n.join("")):n.join("")},toString:function(){return"#"},isSameColor:function(){var t=this.getObjects()[0].get("fill")||"";return"string"==typeof t&&(t=t.toLowerCase(),this.getObjects().every(function(e){var i=e.get("fill")||"";return"string"==typeof i&&i.toLowerCase()===t}))},complexity:function(){return this.paths.reduce(function(t,e){return t+(e&&e.complexity?e.complexity():0)},0)},getObjects:function(){return this.paths}}),e.PathGroup.fromObject=function(t,i){"string"==typeof t.paths?e.loadSVGFromURL(t.paths,function(r){var n=t.paths;delete t.paths;var s=e.util.groupSVGElements(r,t,n);i(s)}):e.util.enlivenObjects(t.paths,function(r){delete t.paths,i(new e.PathGroup(r,t))})},void(e.PathGroup.async=!0))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend,r=e.util.array.min,n=e.util.array.max,s=e.util.array.invoke;if(!e.Group){var o={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};e.Group=e.util.createClass(e.Object,e.Collection,{type:"group",strokeWidth:0,subTargetCheck:!1,initialize:function(t,e,i){e=e||{},this._objects=[],i&&this.callSuper("initialize",e),this._objects=t||[];for(var r=this._objects.length;r--;)this._objects[r].group=this;this.originalState={},e.originX&&(this.originX=e.originX),e.originY&&(this.originY=e.originY),i?this._updateObjectsCoords(!0):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",e)),this.setCoords(),this.saveCoords()},_updateObjectsCoords:function(t){for(var e=this._objects.length;e--;)this._updateObjectCoords(this._objects[e],t)},_updateObjectCoords:function(t,e){if(t.__origHasControls=t.hasControls,t.hasControls=!1,!e){var i=t.getLeft(),r=t.getTop(),n=this.getCenterPoint();t.set({originalLeft:i,originalTop:r,left:i-n.x,top:r-n.y}),t.setCoords()}},toString:function(){return"#"},addWithUpdate:function(t){return this._restoreObjectsState(),e.util.resetObjectTransform(this),t&&(this._objects.push(t),t.group=this,t._set("canvas",this.canvas)),this.forEachObject(this._setObjectActive,this),this._calcBounds(),this._updateObjectsCoords(),this},_setObjectActive:function(t){t.set("active",!0),t.group=this},removeWithUpdate:function(t){return this._restoreObjectsState(),e.util.resetObjectTransform(this),this.forEachObject(this._setObjectActive,this),this.remove(t),this._calcBounds(),this._updateObjectsCoords(),this},_onObjectAdded:function(t){t.group=this,t._set("canvas",this.canvas)},_onObjectRemoved:function(t){delete t.group,t.set("active",!1)},delegatedProperties:{fill:!0,stroke:!0,strokeWidth:!0,fontFamily:!0,fontWeight:!0,fontSize:!0,fontStyle:!0,lineHeight:!0,textDecoration:!0,textAlign:!0,backgroundColor:!0},_set:function(t,e){var i=this._objects.length;if(this.delegatedProperties[t]||"canvas"===t)for(;i--;)this._objects[i].set(t,e);else for(;i--;)this._objects[i].setOnGroup(t,e);this.callSuper("_set",t,e)},toObject:function(t){return i(this.callSuper("toObject",t),{objects:s(this._objects,"toObject",t)})},render:function(t){if(this.visible){t.save(),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.transform(t),this._setShadow(t),this.clipTo&&e.util.clipContext(this,t),this._transformDone=!0;for(var i=0,r=this._objects.length;i\n');for(var i=0,r=this._objects.length;i\n"),t?t(e.join("")):e.join("")},get:function(t){if(t in o){if(this[t])return this[t];for(var e=0,i=this._objects.length;e\n',"\n"),this.stroke||this.strokeDashArray){var s=this.fill;this.fill=null,e.push("\n'),this.fill=s}return e.push("\n"),t?t(e.join("")):e.join("")},getSrc:function(){var t=this._originalElement;return t?fabric.isLikelyNode?t._src:t.src:this.src||""},setSrc:function(t,e,i){fabric.util.loadImage(t,function(t){return this.setElement(t,e,i)},this,i&&i.crossOrigin)},toString:function(){return'#'},clone:function(t,e){this.constructor.fromObject(this.toObject(e),t)},applyFilters:function(t,e,i,r){if(e=e||this.filters,i=i||this._originalElement){var n,s,o=fabric.util.createImage(),a=this.canvas?this.canvas.getRetinaScaling():fabric.devicePixelRatio,h=this.minimumScaleTrigger/a,c=this;if(0===e.length)return this._element=i,t&&t(this),i;var l=fabric.util.createCanvasElement();return l.width=i.width,l.height=i.height,l.getContext("2d").drawImage(i,0,0,i.width,i.height),e.forEach(function(t){t&&(r?(n=c.scaleX0?90*Math.round((t-1)/90):90*Math.round(t/90)},straighten:function(){return this.setAngle(this._getAngleValueForStraighten()),this},fxStraighten:function(t){t=t||{};var e=function(){},i=t.onComplete||e,r=t.onChange||e,n=this;return fabric.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(t){n.setAngle(t),r()},onComplete:function(){n.setCoords(),i()},onStart:function(){n.set("active",!1)}}),this}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(t){return t.straighten(),this.renderAll(),this},fxStraightenObject:function(t){return t.fxStraighten({onChange:this.renderAll.bind(this)}),this}}),fabric.Image.filters=fabric.Image.filters||{},fabric.Image.filters.BaseFilter=fabric.util.createClass({type:"BaseFilter",initialize:function(t){t&&this.setOptions(t)},setOptions:function(t){for(var e in t)this[e]=t[e]},toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}}),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;e.Image.filters.Brightness=e.util.createClass(e.Image.filters.BaseFilter,{type:"Brightness",initialize:function(t){t=t||{},this.brightness=t.brightness||0},applyTo:function(t){for(var e=t.getContext("2d"),i=e.getImageData(0,0,t.width,t.height),r=i.data,n=this.brightness,s=0,o=r.length;sb||o<0||o>v||(h=4*(a*v+o),c=l[C*d+w],e+=p[h]*c,i+=p[h+1]*c,r+=p[h+2]*c,n+=p[h+3]*c);y[s]=e,y[s+1]=i,y[s+2]=r,y[s+3]=n+_*(255-n)}u.putImageData(m,0,0)},toObject:function(){return i(this.callSuper("toObject"),{opaque:this.opaque,matrix:this.matrix})}}),e.Image.filters.Convolute.fromObject=function(t){return new e.Image.filters.Convolute(t)}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;e.Image.filters.GradientTransparency=e.util.createClass(e.Image.filters.BaseFilter,{type:"GradientTransparency",initialize:function(t){t=t||{},this.threshold=t.threshold||100},applyTo:function(t){for(var e=t.getContext("2d"),i=e.getImageData(0,0,t.width,t.height),r=i.data,n=this.threshold,s=r.length,o=0,a=r.length;o-1?t.channel:0},applyTo:function(t){if(this.mask){var i,r=t.getContext("2d"),n=r.getImageData(0,0,t.width,t.height),s=n.data,o=this.mask.getElement(),a=e.util.createCanvasElement(),h=this.channel,c=n.width*n.height*4;a.width=t.width,a.height=t.height,a.getContext("2d").drawImage(o,0,0,t.width,t.height);var l=a.getContext("2d").getImageData(0,0,t.width,t.height),u=l.data;for(i=0;ic&&i>c&&r>c&&l(e-i)i&&(l=2,f=-1),a>n&&(u=2,d=-1),h=c.getImageData(0,0,i,n),t.width=o(s,i),t.height=o(a,n),c.putImageData(h,0,0);!g||!p;)i=v,n=b,s*ft)return 0;if(e*=Math.PI,s(e)<1e-16)return 1;var i=e/t;return h(e)*h(i)/e/i}}function f(t){var h,c,u,d,g,j,A,M,P,I,L;for(T.x=(t+.5)*y,k.x=r(T.x),h=0;h=e)){I=r(1e3*s(c-T.x)),O[I]||(O[I]={});for(var E=k.y-w;E<=k.y+w;E++)E<0||E>=o||(L=r(1e3*s(E-T.y)),O[I][L]||(O[I][L]=m(n(i(I*x,2)+i(L*S,2))/1e3)),u=O[I][L],u>0&&(d=4*(E*e+c),g+=u,j+=u*v[d],A+=u*v[d+1],M+=u*v[d+2],P+=u*v[d+3]))}d=4*(h*a+t),b[d]=j/g,b[d+1]=A/g,b[d+2]=M/g,b[d+3]=P/g}return++t1&&D<-1||(x=2*D*D*D-3*D*D+1,x>0&&(E=4*(L+A*e),k+=x*p[E+3],C+=x,p[E+3]<255&&(x=x*p[E+3]/250),w+=x*p[E],O+=x*p[E+1],T+=x*p[E+2],S+=x))}b[_]=w/S,b[_+1]=O/S,b[_+2]=T/S,b[_+3]=k/C}return v},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}}),e.Image.filters.Resize.fromObject=function(t){return new e.Image.filters.Resize(t)}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;e.Image.filters.ColorMatrix=e.util.createClass(e.Image.filters.BaseFilter,{type:"ColorMatrix",initialize:function(t){t||(t={}),this.matrix=t.matrix||[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0]},applyTo:function(t){var e,i,r,n,s,o=t.getContext("2d"),a=o.getImageData(0,0,t.width,t.height),h=a.data,c=h.length,l=this.matrix;for(e=0;e'},_render:function(t){this.clipTo&&e.util.clipContext(this,t),this._setOpacity(t),this._setShadow(t),this._setupCompositeOperation(t),this._renderTextBackground(t),this._setStrokeStyles(t),this._setFillStyles(t),this._renderText(t),this._renderTextDecoration(t),this.clipTo&&t.restore()},_renderText:function(t){this._renderTextFill(t),this._renderTextStroke(t)},_setTextStyles:function(t){t.textBaseline="alphabetic",t.font=this._getFontDeclaration()},_getTextHeight:function(){return this._getHeightOfSingleLine()+(this._textLines.length-1)*this._getHeightOfLine()},_getTextWidth:function(t){for(var e=this._getLineWidth(t,0),i=1,r=this._textLines.length;ie&&(e=n)}return e},_getNonTransformedDimensions:function(){ -return{x:this.width,y:this.height}},_renderChars:function(t,e,i,r,n){var s,o,a=t.slice(0,-4);if(this[a].toLive){var h=-this.width/2+this[a].offsetX||0,c=-this.height/2+this[a].offsetY||0;e.save(),e.translate(h,c),r-=h,n-=c}if(0!==this.charSpacing){var l=this._getWidthOfCharSpacing();i=i.split("");for(var u=0,f=i.length;u0?o:0}else e[t](i,r,n);this[a].toLive&&e.restore()},_renderTextLine:function(t,e,i,r,n,s){n-=this.fontSize*this._fontSizeFraction;var o=this._getLineWidth(e,s);if("justify"!==this.textAlign||this.width0?u/f:0,g=0,p=0,v=h.length;p0?n:0},_getLeftOffset:function(){return-this.width/2},_getTopOffset:function(){return-this.height/2},isEmptyStyles:function(){return!0},_renderTextCommon:function(t,e){for(var i=0,r=this._getLeftOffset(),n=this._getTopOffset(),s=0,o=this._textLines.length;s0&&(r=this._getLineLeftOffset(i),t.fillRect(this._getLeftOffset()+r,this._getTopOffset()+n,i,e/this.lineHeight)),n+=e;this._removeShadow(t)}},_getLineLeftOffset:function(t){return"center"===this.textAlign?(this.width-t)/2:"right"===this.textAlign?this.width-t:0},_clearCache:function(){this.__lineWidths=[],this.__lineHeights=[]},_shouldClearCache:function(){var t=!1;if(this._forceClearCache)return this._forceClearCache=!1,!0;for(var e in this._dimensionAffectingProps)this["__"+e]!==this[e]&&(this["__"+e]=this[e],t=!0);return t},_getLineWidth:function(t,e){if(this.__lineWidths[e])return this.__lineWidths[e]===-1?this.width:this.__lineWidths[e];var i,r,n=this._textLines[e];return i=""===n?0:this._measureLine(t,e),this.__lineWidths[e]=i,i&&"justify"===this.textAlign&&(r=n.split(/\s+/),r.length>1&&(this.__lineWidths[e]=-1)),i},_getWidthOfCharSpacing:function(){return 0!==this.charSpacing?this.fontSize*this.charSpacing/1e3:0},_measureLine:function(t,e){var i,r,n=this._textLines[e],s=t.measureText(n).width,o=0;return 0!==this.charSpacing&&(i=n.split("").length,o=(i-1)*this._getWidthOfCharSpacing()),r=s+o,r>0?r:0},_renderTextDecoration:function(t){function e(e){var n,s,o,a,h,c,l,u=0;for(n=0,s=r._textLines.length;n-1&&n.push(.85),this.textDecoration.indexOf("line-through")>-1&&n.push(.43),this.textDecoration.indexOf("overline")>-1&&n.push(-.12),n.length>0&&e(n)}},_getFontDeclaration:function(){return[e.isLikelyNode?this.fontWeight:this.fontStyle,e.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+"px",'"'+this.fontFamily+'"'].join(" ")},render:function(t,e){this.visible&&(t.save(),this._setTextStyles(t),this._shouldClearCache()&&this._initDimensions(t),this.drawSelectionBackground(t),e||this.transform(t),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.group&&"path-group"===this.group.type&&t.translate(this.left,this.top),this._render(t),t.restore())},_splitTextIntoLines:function(){return this.text.split(this._reNewline)},toObject:function(t){var e=i(this.callSuper("toObject",t),{text:this.text,fontSize:this.fontSize,fontWeight:this.fontWeight,fontFamily:this.fontFamily,fontStyle:this.fontStyle,lineHeight:this.lineHeight,textDecoration:this.textDecoration,textAlign:this.textAlign,textBackgroundColor:this.textBackgroundColor,charSpacing:this.charSpacing});return this.includeDefaultValues||this._removeDefaultValues(e),e},toSVG:function(t){this.ctx||(this.ctx=e.util.createCanvasElement().getContext("2d"));var i=this._createBaseSVGMarkup(),r=this._getSVGLeftTopOffsets(this.ctx),n=this._getSVGTextAndBg(r.textTop,r.textLeft);return this._wrapSVGTextAndBg(i,n),t?t(i.join("")):i.join("")},_getSVGLeftTopOffsets:function(t){var e=this._getHeightOfLine(t,0),i=-this.width/2,r=0;return{textLeft:i+(this.group&&"path-group"===this.group.type?this.left:0),textTop:r+(this.group&&"path-group"===this.group.type?-this.top:0),lineTop:e}},_wrapSVGTextAndBg:function(t,e){var i=!0,r=this.getSvgFilter(),n=""===r?"":' style="'+r+'"';t.push("\t\n",e.textBgRects.join(""),"\t\t\n',e.textSpans.join(""),"\t\t\n","\t\n")},_getSVGTextAndBg:function(t,e){var i=[],r=[],n=0;this._setSVGBg(r);for(var s=0,o=this._textLines.length;s",e.util.string.escapeXml(this._textLines[t]),"\n")},_setSVGTextLineJustifed:function(t,i,r,o){var a=e.util.createCanvasElement().getContext("2d");this._setTextStyles(a);var h,c,l=this._textLines[t],u=l.split(/\s+/),f=this._getWidthOfWords(a,u.join("")),d=this.width-f,g=u.length-1,p=g>0?d/g:0,v=this._getFillAttributes(this.fill);for(o+=this._getLineLeftOffset(this._getLineWidth(a,t)),t=0,c=u.length;t",e.util.string.escapeXml(h),"\n"),o+=this._getWidthOfWords(a,h)+p},_setSVGTextLineBg:function(t,e,i,r,o){t.push("\t\t\n')},_setSVGBg:function(t){this.backgroundColor&&t.push("\t\t\n')},_getFillAttributes:function(t){var i=t&&"string"==typeof t?new e.Color(t):"";return i&&i.getSource()&&1!==i.getAlpha()?'opacity="'+i.getAlpha()+'" fill="'+i.setAlpha(1).toRgb()+'"':'fill="'+t+'"'},_set:function(t,e){this.callSuper("_set",t,e),t in this._dimensionAffectingProps&&(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),e.Text.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("x y dx dy font-family font-style font-weight font-size text-decoration text-anchor".split(" ")),e.Text.DEFAULT_SVG_FONT_SIZE=16,e.Text.fromElement=function(t,i){if(!t)return null;var r=e.parseAttributes(t,e.Text.ATTRIBUTE_NAMES);i=e.util.object.extend(i?e.util.object.clone(i):{},r),i.top=i.top||0,i.left=i.left||0,"dx"in r&&(i.left+=r.dx),"dy"in r&&(i.top+=r.dy),"fontSize"in i||(i.fontSize=e.Text.DEFAULT_SVG_FONT_SIZE),i.originX||(i.originX="left");var n="";"textContent"in t?n=t.textContent:"firstChild"in t&&null!==t.firstChild&&"data"in t.firstChild&&null!==t.firstChild.data&&(n=t.firstChild.data),n=n.replace(/^\s+|\s+$|\n+/g,"").replace(/\s+/g," ");var s=new e.Text(n,i),o=s.getHeight()/s.height,a=(s.height+s.strokeWidth)*s.lineHeight-s.height,h=a*o,c=s.getHeight()+h,l=0;return"left"===s.originX&&(l=s.getWidth()/2),"right"===s.originX&&(l=-s.getWidth()/2),s.set({left:s.getLeft()+l,top:s.getTop()-c/2+s.fontSize*(.18+s._fontSizeFraction)/s.lineHeight}),s},e.Text.fromObject=function(t){return new e.Text(t.text,r(t))},e.util.createAccessors(e.Text)}("undefined"!=typeof exports?exports:this),function(){var t=fabric.util.object.clone;fabric.IText=fabric.util.createClass(fabric.Text,fabric.Observable,{type:"i-text",selectionStart:0,selectionEnd:0,selectionColor:"rgba(17,119,255,0.3)",isEditing:!1,editable:!0,editingBorderColor:"rgba(102,153,255,0.25)",cursorWidth:2,cursorColor:"#333",cursorDelay:1e3,cursorDuration:600,styles:null,caching:!0,_reSpace:/\s|\n/,_currentCursorOpacity:0,_selectionDirection:null,_abortCursorAnimation:!1,__widthOfSpace:[],initialize:function(t,e){this.styles=e?e.styles||{}:{},this.callSuper("initialize",t,e),this.initBehavior()},_clearCache:function(){this.callSuper("_clearCache"),this.__widthOfSpace=[]},isEmptyStyles:function(){if(!this.styles)return!0;var t=this.styles;for(var e in t)for(var i in t[e])for(var r in t[e][i])return!1;return!0},setSelectionStart:function(t){t=Math.max(t,0),this._updateAndFire("selectionStart",t)},setSelectionEnd:function(t){t=Math.min(t,this.text.length),this._updateAndFire("selectionEnd",t)},_updateAndFire:function(t,e){this[t]!==e&&(this._fireSelectionChanged(),this[t]=e),this._updateTextarea()},_fireSelectionChanged:function(){this.fire("selection:changed"),this.canvas&&this.canvas.fire("text:selection:changed",{target:this})},getSelectionStyles:function(t,e){if(2===arguments.length){for(var i=[],r=t;r0?a:0,lineLeft:r},this.cursorOffsetCache=i,this.cursorOffsetCache},renderCursor:function(t,e){var i=this.get2DCursorLocation(),r=i.lineIndex,n=i.charIndex,s=this.getCurrentCharFontSize(r,n),o=0===r&&0===n?this._getLineLeftOffset(this._getLineWidth(e,r)):t.leftOffset,a=this.scaleX*this.canvas.getZoom(),h=this.cursorWidth/a;e.fillStyle=this.getCurrentCharColor(r,n),e.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity,e.fillRect(t.left+o-h/2,t.top+t.topOffset,h,s)},renderSelection:function(t,e,i){i.fillStyle=this.selectionColor;for(var r=this.get2DCursorLocation(this.selectionStart),n=this.get2DCursorLocation(this.selectionEnd),s=r.lineIndex,o=n.lineIndex,a=s;a<=o;a++){var h=this._getLineLeftOffset(this._getLineWidth(i,a))||0,c=this._getHeightOfLine(this.ctx,a),l=0,u=0,f=this._textLines[a];if(a===s){for(var d=0,g=f.length;d=r.charIndex&&(a!==o||ds&&a1)&&(c/=this.lineHeight),i.fillRect(e.left+h,e.top+e.topOffset,u>0?u:0,c),e.topOffset+=l}},_renderChars:function(t,e,i,r,n,s,o){if(this.isEmptyStyles())return this._renderCharsFast(t,e,i,r,n);o=o||0;var a,h,c=this._getHeightOfLine(e,s),l="";e.save(),n-=c/this.lineHeight*this._fontSizeFraction;for(var u=o,f=i.length+o;u<=f;u++)a=a||this.getCurrentCharStyle(s,u),h=this.getCurrentCharStyle(s,u+1),(this._hasStyleChanged(a,h)||u===f)&&(this._renderChar(t,e,s,u-1,l,r,n,c),l="",a=h),l+=i[u-o];e.restore()},_renderCharsFast:function(t,e,i,r,n){"fillText"===t&&this.fill&&this.callSuper("_renderChars",t,e,i,r,n),"strokeText"===t&&(this.stroke&&this.strokeWidth>0||this.skipFillStrokeCheck)&&this.callSuper("_renderChars",t,e,i,r,n)},_renderChar:function(t,e,i,r,n,s,o,a){var h,c,l,u,f,d,g,p,v,b=this._getStyleDeclaration(i,r);if(b?(c=this._getHeightOfChar(e,n,i,r),u=b.stroke,l=b.fill,d=b.textDecoration):c=this.fontSize,u=(u||this.stroke)&&"strokeText"===t,l=(l||this.fill)&&"fillText"===t,b&&e.save(),h=this._applyCharStylesGetWidth(e,n,i,r,b||null),d=d||this.textDecoration,b&&b.textBackgroundColor&&this._removeShadow(e),0!==this.charSpacing){p=this._getWidthOfCharSpacing(),g=n.split(""),h=0;for(var m,y=0,_=g.length;y<_;y++)m=g[y],l&&e.fillText(m,s+h,o),u&&e.strokeText(m,s+h,o),v=e.measureText(m).width+p,h+=v>0?v:0}else l&&e.fillText(n,s,o),u&&e.strokeText(n,s,o);(d||""!==d)&&(f=this._fontSizeFraction*a/this.lineHeight,this._renderCharDecoration(e,d,s,o,f,h,c)),b&&e.restore(),e.translate(h,0)},_hasStyleChanged:function(t,e){return t.fill!==e.fill||t.fontSize!==e.fontSize||t.textBackgroundColor!==e.textBackgroundColor||t.textDecoration!==e.textDecoration||t.fontFamily!==e.fontFamily||t.fontWeight!==e.fontWeight||t.fontStyle!==e.fontStyle||t.stroke!==e.stroke||t.strokeWidth!==e.strokeWidth},_renderCharDecoration:function(t,e,i,r,n,s,o){if(e){var a,h,c=o/15,l={underline:r+o/10,"line-through":r-o*(this._fontSizeFraction+this._fontSizeMult-1)+c,overline:r-(this._fontSizeMult-this._fontSizeFraction)*o},u=["underline","line-through","overline"];for(a=0;a-1&&t.fillRect(i,l[h],s,c)}},_renderTextLine:function(t,e,i,r,n,s){this.isEmptyStyles()||(n+=this.fontSize*(this._fontSizeFraction+.03)),this.callSuper("_renderTextLine",t,e,i,r,n,s)},_renderTextDecoration:function(t){if(this.isEmptyStyles())return this.callSuper("_renderTextDecoration",t)},_renderTextLinesBackground:function(t){this.callSuper("_renderTextLinesBackground",t);for(var e,i,r,n,s,o,a=0,h=this._getLeftOffset(),c=this._getTopOffset(),l=0,u=this._textLines.length;l0?n:0},_getHeightOfChar:function(t,e,i){var r=this._getStyleDeclaration(e,i);return r&&r.fontSize?r.fontSize:this.fontSize},_getWidthOfCharsAt:function(t,e,i){var r,n,s=0;for(r=0;r0?i:0},_getWidthOfSpace:function(t,e){if(this.__widthOfSpace[e])return this.__widthOfSpace[e];var i=this._textLines[e],r=this._getWidthOfWords(t,i,e,0),n=this.width-r,s=i.length-i.replace(this._reSpacesAndTabs,"").length,o=Math.max(n/s,t.measureText(" ").width);return this.__widthOfSpace[e]=o,o},_getWidthOfWords:function(t,e,i,r){for(var n=0,s=0;sr&&(r=o)}return this.__lineHeights[e]=r*this.lineHeight*this._fontSizeMult,this.__lineHeights[e]},_getTextHeight:function(t){for(var e,i=0,r=0,n=this._textLines.length;r-1;)e++,i--;return t-e},findWordBoundaryRight:function(t){var e=0,i=t;if(this._reSpace.test(this.text.charAt(i)))for(;this._reSpace.test(this.text.charAt(i));)e++,i++;for(;/\S/.test(this.text.charAt(i))&&i-1;)e++,i--;return t-e},findLineBoundaryRight:function(t){for(var e=0,i=t;!/\n/.test(this.text.charAt(i))&&i0&&ithis.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=e):(this.selectionStart=e,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart===i&&this.selectionEnd===r||(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},_updateTextarea:function(){if(this.hiddenTextarea&&!this.inCompositionMode&&(this.cursorOffsetCache={},this.hiddenTextarea.value=this.text,this.hiddenTextarea.selectionStart=this.selectionStart,this.hiddenTextarea.selectionEnd=this.selectionEnd,this.selectionStart===this.selectionEnd)){var t=this._calcTextareaPosition();this.hiddenTextarea.style.left=t.left,this.hiddenTextarea.style.top=t.top,this.hiddenTextarea.style.fontSize=t.fontSize}},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var t=this.text.split(""),e=this._getCursorBoundaries(t,"cursor"),i=this.get2DCursorLocation(),r=i.lineIndex,n=i.charIndex,s=this.getCurrentCharFontSize(r,n),o=0===r&&0===n?this._getLineLeftOffset(this._getLineWidth(this.ctx,r)):e.leftOffset,a=this.calcTransformMatrix(),h={x:e.left+o,y:e.top+e.topOffset+s},c=this.canvas.upperCanvasEl,l=c.width-s,u=c.height-s;return h=fabric.util.transformPoint(h,a),h=fabric.util.transformPoint(h,this.canvas.viewportTransform),h.x<0&&(h.x=0),h.x>l&&(h.x=l),h.y<0&&(h.y=0),h.y>u&&(h.y=u),{left:h.x+"px",top:h.y+"px",fontSize:s}},_saveEditingProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,defaultCursor:this.canvas&&this.canvas.defaultCursor,moveCursor:this.canvas&&this.canvas.moveCursor}},_restoreEditingProps:function(){this._savedProps&&(this.hoverCursor=this._savedProps.overCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,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;return this.selected=!1,this.isEditing=!1,this.selectable=!0,this.selectionEnd=this.selectionStart,this.hiddenTextarea&&this.canvas&&this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea),this.hiddenTextarea=null,this.abortCursorAnimation(),this._restoreEditingProps(),this._currentCursorOpacity=0,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]},_removeCharsFromTo:function(t,e){for(;e!==t;)this._removeSingleCharAndStyle(t+1),e--;this.selectionStart=t,this.selectionEnd=t},_removeSingleCharAndStyle:function(t){var e="\n"===this.text[t-1],i=e?t:t-1;this.removeStyleObject(e,i),this.text=this.text.slice(0,t-1)+this.text.slice(t),this._textLines=this._splitTextIntoLines()},insertChars:function(t,e){var i;if(this.selectionEnd-this.selectionStart>1&&this._removeCharsFromTo(this.selectionStart,this.selectionEnd),!e&&this.isEmptyStyles())return void this.insertChar(t,!1);for(var r=0,n=t.length;r=i&&(s[parseInt(o,10)-i]=this.styles[e][o],delete this.styles[e][o]);this.styles[e+1]=s}this._forceClearCache=!0},insertCharStyleObject:function(e,i,r){var n=this.styles[e],s=t(n);0!==i||r||(i=1);for(var o in s){var a=parseInt(o,10);a>=i&&(n[a+1]=s[a],s[a-1]||delete n[a])}this.styles[e][i]=r||t(n[i-1]),this._forceClearCache=!0},insertStyleObjects:function(t,e,i){var r=this.get2DCursorLocation(),n=r.lineIndex,s=r.charIndex;this._getLineStyle(n)||this._setLineStyle(n,{}),"\n"===t?this.insertNewlineStyleObject(n,s,e):this.insertCharStyleObject(n,s,i)},shiftLineStyles:function(e,i){ -var r=t(this.styles);for(var n in this.styles){var s=parseInt(n,10);s>e&&(this.styles[s+i]=r[s],r[s-i]||delete this.styles[s])}},removeStyleObject:function(t,e){var i=this.get2DCursorLocation(e),r=i.lineIndex,n=i.charIndex;this._removeStyleObject(t,i,r,n)},_getTextOnPreviousLine:function(t){return this._textLines[t-1]},_removeStyleObject:function(e,i,r,n){if(e){var s=this._getTextOnPreviousLine(i.lineIndex),o=s?s.length:0;this.styles[r-1]||(this.styles[r-1]={});for(n in this.styles[r])this.styles[r-1][parseInt(n,10)+o]=this.styles[r][n];this.shiftLineStyles(i.lineIndex,-1)}else{var a=this.styles[r];a&&delete a[n];var h=t(a);for(var c in h){var l=parseInt(c,10);l>=n&&0!==l&&(a[l-1]=h[l],delete a[l])}}},insertNewline:function(){this.insertChars("\n")}})}(),fabric.util.object.extend(fabric.IText.prototype,{initDoubleClickSimulation:function(){this.__lastClickTime=+new Date,this.__lastLastClickTime=+new Date,this.__lastPointer={},this.on("mousedown",this.onMouseDown.bind(this))},onMouseDown:function(t){this.__newClickTime=+new Date;var e=this.canvas.getPointer(t.e);this.isTripleClick(e)?(this.fire("tripleclick",t),this._stopEvent(t.e)):this.isDoubleClick(e)&&(this.fire("dblclick",t),this._stopEvent(t.e)),this.__lastLastClickTime=this.__lastClickTime,this.__lastClickTime=this.__newClickTime,this.__lastPointer=e,this.__lastIsEditing=this.isEditing,this.__lastSelected=this.selected},isDoubleClick:function(t){return this.__newClickTime-this.__lastClickTime<500&&this.__lastPointer.x===t.x&&this.__lastPointer.y===t.y&&this.__lastIsEditing},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.initSelectedHandler(),this.initMousedownHandler(),this.initMouseupHandler(),this.initClicks()},initClicks:function(){this.on("dblclick",function(t){this.selectWord(this.getSelectionStartFromPointer(t.e))}),this.on("tripleclick",function(t){this.selectLine(this.getSelectionStartFromPointer(t.e))})},initMousedownHandler:function(){this.on("mousedown",function(t){if(this.editable){var e=this.canvas.getPointer(t.e);this.__mousedownX=e.x,this.__mousedownY=e.y,this.__isMousedown=!0,this.selected&&this.setCursorByClick(t.e),this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection())}})},_isObjectMoved:function(t){var e=this.canvas.getPointer(t);return this.__mousedownX!==e.x||this.__mousedownY!==e.y},initMouseupHandler:function(){this.on("mouseup",function(t){this.__isMousedown=!1,this.editable&&!this._isObjectMoved(t.e)&&(this.__lastSelected&&!this.__corner&&(this.enterEditing(t.e),this.selectionStart===this.selectionEnd?this.initDelayedCursor(!0):this.renderCursorOrSelection()),this.selected=!0)})},setCursorByClick:function(t){var e=this.getSelectionStartFromPointer(t);t.shiftKey?es?0:1,h=r+a;return this.flipX&&(h=n-h),h>this.text.length&&(h=this.text.length),h}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off");var t=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+t.top+"; left: "+t.left+"; opacity: 0; width: 0px; height: 0px; z-index: -999;",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.cut.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:{8:"removeChars",9:"exitEditing",27:"exitEditing",13:"insertNewline",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorRight",36:"moveCursorLeft",37:"moveCursorLeft",38:"moveCursorUp",39:"moveCursorRight",40:"moveCursorDown",46:"forwardDelete"},_ctrlKeysMapUp:{67:"copy",88:"cut"},_ctrlKeysMapDown:{65:"selectAll"},onClick:function(){this.hiddenTextarea&&this.hiddenTextarea.focus()},onKeyDown:function(t){if(this.isEditing){if(t.keyCode in this._keysMap)this[this._keysMap[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(),this.canvas&&this.canvas.renderAll()}},onKeyUp:function(t){return!this.isEditing||this._copyDone?void(this._copyDone=!1):void(t.keyCode in this._ctrlKeysMapUp&&(t.ctrlKey||t.metaKey)&&(this[this._ctrlKeysMapUp[t.keyCode]](t),t.stopImmediatePropagation(),t.preventDefault(),this.canvas&&this.canvas.renderAll()))},onInput:function(t){if(this.isEditing&&!this.inCompositionMode){var e,i,r,n=this.selectionStart||0,s=this.selectionEnd||0,o=this.text.length,a=this.hiddenTextarea.value.length;a>o?(r="left"===this._selectionDirection?s:n,e=a-o,i=this.hiddenTextarea.value.slice(r,r+e)):(e=a-o+s-n,i=this.hiddenTextarea.value.slice(n,n+e)),this.insertChars(i),t.stopPropagation()}},onCompositionStart:function(){this.inCompositionMode=!0,this.prevCompositionLength=0,this.compositionStart=this.selectionStart},onCompositionEnd:function(){this.inCompositionMode=!1},onCompositionUpdate:function(t){var e=t.data;this.selectionStart=this.compositionStart,this.selectionEnd=this.selectionEnd===this.selectionStart?this.compositionStart+this.prevCompositionLength:this.selectionEnd,this.insertChars(e,!1),this.prevCompositionLength=e.length},forwardDelete:function(t){if(this.selectionStart===this.selectionEnd){if(this.selectionStart===this.text.length)return;this.moveCursorRight(t)}this.removeChars(t)},copy:function(t){if(this.selectionStart!==this.selectionEnd){var e=this.getSelectedText(),i=this._getClipboardData(t);i&&i.setData("text",e),fabric.copiedText=e,fabric.copiedTextStyle=this.getSelectionStyles(this.selectionStart,this.selectionEnd),t.stopImmediatePropagation(),t.preventDefault(),this._copyDone=!0}},paste:function(t){var e=null,i=this._getClipboardData(t),r=!0;i?(e=i.getData("text").replace(/\r/g,""),fabric.copiedTextStyle&&fabric.copiedText===e||(r=!1)):e=fabric.copiedText,e&&this.insertChars(e,r),t.stopImmediatePropagation(),t.preventDefault()},cut:function(t){this.selectionStart!==this.selectionEnd&&(this.copy(t),this.removeChars(t))},_getClipboardData:function(t){return t&&t.clipboardData||fabric.window.clipboardData},getDownCursorOffset:function(t,e){var i,r,n=e?this.selectionEnd:this.selectionStart,s=this.get2DCursorLocation(n),o=s.lineIndex,a=this._textLines[o].slice(0,s.charIndex),h=this._textLines[o].slice(s.charIndex),c=this._textLines[o+1]||"";if(o===this._textLines.length-1||t.metaKey||34===t.keyCode)return this.text.length-n;var l=this._getLineWidth(this.ctx,o);r=this._getLineLeftOffset(l);for(var u=r,f=0,d=a.length;fi){r=!0;var d=a-f,g=a,p=Math.abs(d-i),v=Math.abs(g-i);h=v=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorUpOrDown("Down",t)},moveCursorDownWithoutShift:function(t){return this._selectionDirection="right",this.selectionEnd=this.selectionEnd+t,this.selectionStart=this.selectionEnd,0!==t},swapSelectionPoints:function(){var t=this.selectionEnd;this.selectionEnd=this.selectionStart,this.selectionStart=t},moveCursorDownWithShift:function(t){return this.selectionEnd===this.selectionStart&&(this._selectionDirection="right"),"right"===this._selectionDirection?this.selectionEnd+=t:this.selectionStart+=t,this.selectionEndthis.text.length&&(this.selectionEnd=this.text.length),0!==t},getUpCursorOffset:function(t,e){var i=e?this.selectionEnd:this.selectionStart,r=this.get2DCursorLocation(i),n=r.lineIndex;if(0===n||t.metaKey||33===t.keyCode)return i;for(var s,o=this._textLines[n].slice(0,r.charIndex),a=this._textLines[n-1]||"",h=this._getLineWidth(this.ctx,r.lineIndex),c=this._getLineLeftOffset(h),l=c,u=0,f=o.length;ui){r=!0;var d=a-f,g=a,p=Math.abs(d-i),v=Math.abs(g-i);h=v=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorLeftOrRight("Right",t)},_moveCursorLeftOrRight:function(t,e){var i="moveCursor"+t+"With";this._currentCursorOpacity=1,i+=e.shiftKey?"Shift":"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){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(t):this._removeCharsFromTo(this.selectionStart,this.selectionEnd),this.setSelectionEnd(this.selectionStart),this._removeExtraneousStyles(),this.canvas&&this.canvas.renderAll(),this.setCoords(),this.fire("changed"),this.canvas&&this.canvas.fire("text:changed",{target:this})},_removeCharsNearCursor:function(t){if(0!==this.selectionStart)if(t.metaKey){var e=this.findLineBoundaryLeft(this.selectionStart);this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)}else if(t.altKey){var i=this.findWordBoundaryLeft(this.selectionStart);this._removeCharsFromTo(i,this.selectionStart),this.setSelectionStart(i)}else this._removeSingleCharAndStyle(this.selectionStart),this.setSelectionStart(this.selectionStart-1)}}),function(){var t=fabric.util.toFixed,e=fabric.Object.NUM_FRACTION_DIGITS;fabric.util.object.extend(fabric.IText.prototype,{_setSVGTextLineText:function(t,e,i,r,n,s){this._getLineStyle(t)?this._setSVGTextLineChars(t,e,i,r,s):fabric.Text.prototype._setSVGTextLineText.call(this,t,e,i,r,n)},_setSVGTextLineChars:function(t,e,i,r,n){for(var s=this._textLines[t],o=0,a=this._getLineLeftOffset(this._getLineWidth(this.ctx,t))-this.width/2,h=this._getSVGLineTopOffset(t),c=this._getHeightOfLine(this.ctx,t),l=0,u=s.length;l\n'].join("")},_createTextCharSpan:function(i,r,n,s,o){var a=this.getSvgStyles.call(fabric.util.object.extend({visible:!0,fill:this.fill,stroke:this.stroke,type:"text",getSvgFilter:fabric.Object.prototype.getSvgFilter},r));return['\t\t\t',fabric.util.string.escapeXml(i),"\n"].join("")}})}(),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.clone;e.Textbox=e.util.createClass(e.IText,e.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:0,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,initialize:function(t,i){this.ctx=e.util.createCanvasElement().getContext("2d"),this.callSuper("initialize",t,i),this.setControlsVisibility(e.Textbox.getTextboxControlVisibility()),this._dimensionAffectingProps.width=!0},_initDimensions:function(t){this.__skipDimension||(t||(t=e.util.createCanvasElement().getContext("2d"),this._setTextStyles(t)),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(t))},_generateStyleMap:function(){for(var t=0,e=0,i=0,r={},n=0;n=this.width&&!d?(n.push(s),s="",r=l,d=!0):r+=g,d||(s+=c),s+=a,u=this._measureText(t,c,i,h),h++,d=!1,l>f&&(f=l);return p&&n.push(s),f>this.dynamicMinWidth&&(this.dynamicMinWidth=f-g),n},_splitTextIntoLines:function(){var t=this.textAlign;this.ctx.save(),this._setTextStyles(this.ctx),this.textAlign="left";var e=this._wrapText(this.ctx,this.text);return this.textAlign=t,this.ctx.restore(),this._textLines=e,this._styleMap=this._generateStyleMap(),e},setOnGroup:function(t,e){"scaleX"===t&&(this.set("scaleX",Math.abs(1/e)),this.set("width",this.get("width")*e/("undefined"==typeof this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=e)},get2DCursorLocation:function(t){"undefined"==typeof t&&(t=this.selectionStart);for(var e=this._textLines.length,i=0,r=0;r=h.getMinWidth()?(h.set("width",c),!0):void 0},fabric.Group.prototype._refreshControlsVisibility=function(){if("undefined"!=typeof fabric.Textbox)for(var t=this._objects.length;t--;)if(this._objects[t]instanceof fabric.Textbox)return void this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility())};var e=fabric.util.object.clone;fabric.util.object.extend(fabric.Textbox.prototype,{_removeExtraneousStyles:function(){for(var t in this._styleMap)this._textLines[t]||delete this.styles[this._styleMap[t].line]},insertCharStyleObject:function(t,e,i){var r=this._styleMap[t];t=r.line,e=r.offset+e,fabric.IText.prototype.insertCharStyleObject.apply(this,[t,e,i])},insertNewlineStyleObject:function(t,e,i){var r=this._styleMap[t];t=r.line,e=r.offset+e,fabric.IText.prototype.insertNewlineStyleObject.apply(this,[t,e,i])},shiftLineStyles:function(t,i){var r=e(this.styles),n=this._styleMap[t];t=n.line;for(var s in this.styles){var o=parseInt(s,10);o>t&&(this.styles[o+i]=r[o],r[o-i]||delete this.styles[o])}},_getTextOnPreviousLine:function(t){for(var e=this._textLines[t-1];this._styleMap[t-2]&&this._styleMap[t-2].line===this._styleMap[t-1].line;)e=this._textLines[t-2]+e,t--;return e},removeStyleObject:function(t,e){var i=this.get2DCursorLocation(e),r=this._styleMap[i.lineIndex],n=r.line,s=r.offset+i.charIndex;this._removeStyleObject(t,i,n,s)}})}(),function(){var t=fabric.IText.prototype._getNewSelectionStartFromOffset;fabric.IText.prototype._getNewSelectionStartFromOffset=function(e,i,r,n,s){n=t.call(this,e,i,r,n,s);for(var o=0,a=0,h=0;h=n));h++)"\n"!==this.text[o+a]&&" "!==this.text[o+a]||a++;return n-h+a}}(),function(){function request(t,e,i){var r=URL.parse(t);r.port||(r.port=0===r.protocol.indexOf("https:")?443:80);var n=0===r.protocol.indexOf("https:")?HTTPS:HTTP,s=n.request({hostname:r.hostname,port:r.port,path:r.path,method:"GET"},function(t){var r="";e&&t.setEncoding(e),t.on("end",function(){i(r)}),t.on("data",function(e){200===t.statusCode&&(r+=e)})});s.on("error",function(t){t.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+r.hostname+":"+r.port):fabric.log(t.message),i(null)}),s.end()}function requestFs(t,e){var i=require("fs");i.readFile(t,function(t,i){if(t)throw fabric.log(t),t;e(i)})}if("undefined"==typeof document||"undefined"==typeof window){var DOMParser=require("xmldom").DOMParser,URL=require("url"),HTTP=require("http"),HTTPS=require("https"),Canvas=require("canvas"),Image=require("canvas").Image;fabric.util.loadImage=function(t,e,i){function r(r){r?(n.src=new Buffer(r,"binary"),n._src=t,e&&e.call(i,n)):(n=null,e&&e.call(i,null,!0))}var n=new Image;t&&(t instanceof Buffer||0===t.indexOf("data"))?(n.src=n._src=t,e&&e.call(i,n)):t&&0!==t.indexOf("http")?requestFs(t,r):t?request(t,"binary",r):e&&e.call(i,t)},fabric.loadSVGFromURL=function(t,e,i){t=t.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim(),0!==t.indexOf("http")?requestFs(t,function(t){fabric.loadSVGFromString(t.toString(),e,i)}):request(t,"",function(t){fabric.loadSVGFromString(t,e,i)})},fabric.loadSVGFromString=function(t,e,i){var r=(new DOMParser).parseFromString(t);fabric.parseSVGDocument(r.documentElement,function(t,i){e&&e(t,i)},i)},fabric.util.getScript=function(url,callback){request(url,"",function(body){eval(body),callback&&callback()})},fabric.createCanvasForNode=function(t,e,i,r){r=r||i;var n=fabric.document.createElement("canvas"),s=new Canvas(t||600,e||600,r),o=new Canvas(t||600,e||600,r);n.style={},n.width=s.width,n.height=s.height;var a=fabric.Canvas||fabric.StaticCanvas,h=new a(n,i);return h.contextContainer=s.getContext("2d"),h.nodeCanvas=s,h.contextCache=o.getContext("2d"),h.nodeCacheCanvas=o,h.Font=Canvas.Font,h},fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(t){return this.nodeCanvas.createJPEGStream(t)};var origSetWidth=fabric.StaticCanvas.prototype.setWidth;fabric.StaticCanvas.prototype.setWidth=function(t,e){return origSetWidth.call(this,t,e),this.nodeCanvas.width=t,this},fabric.Canvas&&(fabric.Canvas.prototype.setWidth=fabric.StaticCanvas.prototype.setWidth);var origSetHeight=fabric.StaticCanvas.prototype.setHeight;fabric.StaticCanvas.prototype.setHeight=function(t,e){return origSetHeight.call(this,t,e),this.nodeCanvas.height=t,this},fabric.Canvas&&(fabric.Canvas.prototype.setHeight=fabric.StaticCanvas.prototype.setHeight)}}(); \ No newline at end of file +var fabric=fabric||{version:"1.6.5"};"undefined"!=typeof exports&&(exports.fabric=fabric),"undefined"!=typeof document&&"undefined"!=typeof window?(fabric.document=document,fabric.window=window,window.fabric=fabric):(fabric.document=require("jsdom").jsdom(""),fabric.document.createWindow?fabric.window=fabric.document.createWindow():fabric.window=fabric.document.parentWindow),fabric.isTouchSupported="ontouchstart"in fabric.document.documentElement,fabric.isLikelyNode="undefined"!=typeof Buffer&&"undefined"==typeof window,fabric.SHARED_ATTRIBUTES=["display","transform","fill","fill-opacity","fill-rule","opacity","stroke","stroke-dasharray","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","id"],fabric.DPI=96,fabric.reNum="(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:e[-+]?\\d+)?)",fabric.fontPaths={},fabric.charWidthsCache={},fabric.devicePixelRatio=fabric.window.devicePixelRatio||fabric.window.webkitDevicePixelRatio||fabric.window.mozDevicePixelRatio||1,function(){function t(t,e){if(this.__eventListeners[t]){var i=this.__eventListeners[t];e?i[i.indexOf(e)]=!1:fabric.util.array.fill(i,!1)}}function e(t,e){if(this.__eventListeners||(this.__eventListeners={}),1===arguments.length)for(var i in t)this.on(i,t[i]);else this.__eventListeners[t]||(this.__eventListeners[t]=[]),this.__eventListeners[t].push(e);return this}function i(e,i){if(this.__eventListeners){if(0===arguments.length)for(e in this.__eventListeners)t.call(this,e);else if(1===arguments.length&&"object"==typeof arguments[0])for(var r in e)t.call(this,r,e[r]);else t.call(this,e,i);return this}}function r(t,e){if(this.__eventListeners){var i=this.__eventListeners[t];if(i){for(var r=0,n=i.length;r-1},complexity:function(){return this.getObjects().reduce(function(t,e){return t+=e.complexity?e.complexity():0},0)}},function(t){var e=Math.sqrt,i=Math.atan2,r=Math.pow,n=Math.abs,s=Math.PI/180;fabric.util={removeFromArray:function(t,e){var i=t.indexOf(e);return i!==-1&&t.splice(i,1),t},getRandomInt:function(t,e){return Math.floor(Math.random()*(e-t+1))+t},degreesToRadians:function(t){return t*s},radiansToDegrees:function(t){return t/s},rotatePoint:function(t,e,i){t.subtractEquals(e);var r=fabric.util.rotateVector(t,i);return new fabric.Point(r.x,r.y).addEquals(e)},rotateVector:function(t,e){var i=Math.sin(e),r=Math.cos(e),n=t.x*r-t.y*i,s=t.x*i+t.y*r;return{x:n,y:s}},transformPoint:function(t,e,i){return i?new fabric.Point(e[0]*t.x+e[2]*t.y,e[1]*t.x+e[3]*t.y):new fabric.Point(e[0]*t.x+e[2]*t.y+e[4],e[1]*t.x+e[3]*t.y+e[5])},makeBoundingBoxFromPoints:function(t){var e=[t[0].x,t[1].x,t[2].x,t[3].x],i=fabric.util.array.min(e),r=fabric.util.array.max(e),n=Math.abs(i-r),s=[t[0].y,t[1].y,t[2].y,t[3].y],o=fabric.util.array.min(s),a=fabric.util.array.max(s),h=Math.abs(o-a);return{left:i,top:o,width:n,height:h}},invertTransform:function(t){var e=1/(t[0]*t[3]-t[1]*t[2]),i=[e*t[3],-e*t[1],-e*t[2],e*t[0]],r=fabric.util.transformPoint({x:t[4],y:t[5]},i,!0);return i[4]=-r.x,i[5]=-r.y,i},toFixed:function(t,e){return parseFloat(Number(t).toFixed(e))},parseUnit:function(t,e){var i=/\D{0,2}$/.exec(t),r=parseFloat(t);switch(e||(e=fabric.Text.DEFAULT_SVG_FONT_SIZE),i[0]){case"mm":return r*fabric.DPI/25.4;case"cm":return r*fabric.DPI/2.54;case"in":return r*fabric.DPI;case"pt":return r*fabric.DPI/72;case"pc":return r*fabric.DPI/72*12;case"em":return r*e;default:return r}},falseFunction:function(){return!1},getKlass:function(t,e){return t=fabric.util.string.camelize(t.charAt(0).toUpperCase()+t.slice(1)),fabric.util.resolveNamespace(e)[t]},resolveNamespace:function(e){if(!e)return fabric;var i,r=e.split("."),n=r.length,s=t||fabric.window;for(i=0;ir;)r+=a[d++%f],r>l&&(r=l),t[g?"lineTo":"moveTo"](r,0),g=!g;t.restore()},createCanvasElement:function(t){return t||(t=fabric.document.createElement("canvas")),t.getContext||"undefined"==typeof G_vmlCanvasManager||G_vmlCanvasManager.initElement(t),t},createImage:function(){return fabric.isLikelyNode?new(require("canvas").Image):fabric.document.createElement("img")},createAccessors:function(t){var e,i,r,n,s,o=t.prototype;for(e=o.stateProperties.length;e--;)i=o.stateProperties[e],r=i.charAt(0).toUpperCase()+i.slice(1),n="set"+r,s="get"+r,o[s]||(o[s]=function(t){return new Function('return this.get("'+t+'")')}(i)),o[n]||(o[n]=function(t){return new Function("value",'return this.set("'+t+'", value)')}(i))},clipContext:function(t,e){e.save(),e.beginPath(),t.clipTo(e),e.clip()},multiplyTransformMatrices:function(t,e,i){return[t[0]*e[0]+t[2]*e[1],t[1]*e[0]+t[3]*e[1],t[0]*e[2]+t[2]*e[3],t[1]*e[2]+t[3]*e[3],i?0:t[0]*e[4]+t[2]*e[5]+t[4],i?0:t[1]*e[4]+t[3]*e[5]+t[5]]},qrDecompose:function(t){var n=i(t[1],t[0]),o=r(t[0],2)+r(t[1],2),a=e(o),h=(t[0]*t[3]-t[2]*t[1])/a,c=i(t[0]*t[2]+t[1]*t[3],o);return{angle:n/s,scaleX:a,scaleY:h,skewX:c/s,skewY:0,translateX:t[4],translateY:t[5]}},customTransformMatrix:function(t,e,i){var r=[1,0,n(Math.tan(i*s)),1],o=[n(t),0,0,n(e)];return fabric.util.multiplyTransformMatrices(o,r,!0)},resetObjectTransform:function(t){t.scaleX=1,t.scaleY=1,t.skewX=0,t.skewY=0,t.flipX=!1,t.flipY=!1,t.setAngle(0)},getFunctionBody:function(t){return(String(t).match(/function[^{]*\{([\s\S]*)\}/)||{})[1]},isTransparent:function(t,e,i,r){r>0&&(e>r?e-=r:e=0,i>r?i-=r:i=0);var n,s,o=!0,a=t.getImageData(e,i,2*r||1,2*r||1),h=a.data.length;for(n=3;n0?D-=2*f:1===c&&D<0&&(D+=2*f);for(var E=Math.ceil(Math.abs(D/f*2)),L=[],I=D/E,R=8/3*Math.sin(I/4)*Math.sin(I/4)/Math.sin(I/2),F=P+I,B=0;B=n?s-n:2*Math.PI-(n-s)}function r(t,e,i,r,n,s,h,c){var l=a.call(arguments);if(o[l])return o[l];var u,f,d,g,p,v,b,m,y=Math.sqrt,_=Math.min,x=Math.max,S=Math.abs,C=[],w=[[],[]];f=6*t-12*i+6*n,u=-3*t+9*i-9*n+3*h,d=3*i-3*t;for(var O=0;O<2;++O)if(O>0&&(f=6*e-12*r+6*s,u=-3*e+9*r-9*s+3*c,d=3*r-3*e),S(u)<1e-12){if(S(f)<1e-12)continue;g=-d/f,0=e})}function i(t,e){return n(t,e,function(t,e){return t>>0;if(0===i)return-1;var r=0;if(arguments.length>0&&(r=Number(arguments[1]),r!==r?r=0:0!==r&&r!==Number.POSITIVE_INFINITY&&r!==Number.NEGATIVE_INFINITY&&(r=(r>0||-1)*Math.floor(Math.abs(r)))),r>=i)return-1;for(var n=r>=0?r:Math.max(i-Math.abs(r),0);n>>0;i>>0;r>>0;i>>0;i>>0;n>>0,r=0;if(arguments.length>1)e=arguments[1];else for(;;){if(r in this){e=this[r++];break}if(++r>=i)throw new TypeError}for(;r/g,">")}String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^[\s\xA0]+/,"").replace(/[\s\xA0]+$/,"")}),fabric.util.string={camelize:t,capitalize:e,escapeXml:i}}(),function(){var t=Array.prototype.slice,e=Function.prototype.apply,i=function(){};Function.prototype.bind||(Function.prototype.bind=function(r){var n,s=this,o=t.call(arguments,1);return n=o.length?function(){return e.call(s,this instanceof i?this:r,o.concat(t.call(arguments)))}:function(){return e.call(s,this instanceof i?this:r,arguments)},i.prototype=this.prototype,n.prototype=new i,n})}(),function(){function t(){}function e(t){var e=this.constructor.superclass.prototype[t];return arguments.length>1?e.apply(this,r.call(arguments,1)):e.call(this)}function i(){function i(){this.initialize.apply(this,arguments)}var s=null,a=r.call(arguments,0);"function"==typeof a[0]&&(s=a.shift()),i.superclass=s,i.subclasses=[],s&&(t.prototype=s.prototype,i.prototype=new t,s.subclasses.push(i));for(var h=0,c=a.length;h-1?t.prototype[r]=function(t){return function(){var r=this.constructor.superclass;this.constructor.superclass=i;var n=e[t].apply(this,arguments);if(this.constructor.superclass=r,"initialize"!==t)return n}}(r):t.prototype[r]=e[r],s&&(e.toString!==Object.prototype.toString&&(t.prototype.toString=e.toString),e.valueOf!==Object.prototype.valueOf&&(t.prototype.valueOf=e.valueOf))};fabric.util.createClass=i}(),function(){function t(t){var e,i,r=Array.prototype.slice.call(arguments,1),n=r.length;for(i=0;i-1?s(t,e.match(/opacity:\s*(\d?\.?\d*)/)[1]):t;for(var r in e)if("opacity"===r)s(t,e[r]);else{var n="float"===r||"cssFloat"===r?"undefined"==typeof i.styleFloat?"cssFloat":"styleFloat":r;i[n]=e[r]}return t}var e=fabric.document.createElement("div"),i="string"==typeof e.style.opacity,r="string"==typeof e.style.filter,n=/alpha\s*\(\s*opacity\s*=\s*([^\)]+)\)/,s=function(t){return t};i?s=function(t,e){return t.style.opacity=e,t}:r&&(s=function(t,e){var i=t.style;return t.currentStyle&&!t.currentStyle.hasLayout&&(i.zoom=1),n.test(i.filter)?(e=e>=.9999?"":"alpha(opacity="+100*e+")",i.filter=i.filter.replace(n,e)):i.filter+=" alpha(opacity="+100*e+")",t}),fabric.util.setStyle=t}(),function(){function t(t){return"string"==typeof t?fabric.document.getElementById(t):t}function e(t,e){var i=fabric.document.createElement(t);for(var r in e)"class"===r?i.className=e[r]:"for"===r?i.htmlFor=e[r]:i.setAttribute(r,e[r]);return i}function i(t,e){t&&(" "+t.className+" ").indexOf(" "+e+" ")===-1&&(t.className+=(t.className?" ":"")+e)}function r(t,i,r){return"string"==typeof i&&(i=e(i,r)),t.parentNode&&t.parentNode.replaceChild(i,t),i.appendChild(t),i}function n(t){for(var e=0,i=0,r=fabric.document.documentElement,n=fabric.document.body||{scrollLeft:0,scrollTop:0};t&&(t.parentNode||t.host)&&(t=t.parentNode||t.host,t===fabric.document?(e=n.scrollLeft||r.scrollLeft||0,i=n.scrollTop||r.scrollTop||0):(e+=t.scrollLeft||0,i+=t.scrollTop||0),1!==t.nodeType||"fixed"!==fabric.util.getElementStyle(t,"position")););return{left:e,top:i}}function s(t){var e,i,r=t&&t.ownerDocument,s={left:0,top:0},o={left:0,top:0},a={borderLeftWidth:"left",borderTopWidth:"top",paddingLeft:"left",paddingTop:"top"};if(!r)return o;for(var h in a)o[a[h]]+=parseInt(c(t,h),10)||0;return e=r.documentElement,"undefined"!=typeof t.getBoundingClientRect&&(s=t.getBoundingClientRect()),i=n(t),{left:s.left+i.left-(e.clientLeft||0)+o.left,top:s.top+i.top-(e.clientTop||0)+o.top}}var o,a=Array.prototype.slice,h=function(t){return a.call(t,0)};try{o=h(fabric.document.childNodes)instanceof Array}catch(t){}o||(h=function(t){for(var e=new Array(t.length),i=t.length;i--;)e[i]=t[i];return e});var c;c=fabric.document.defaultView&&fabric.document.defaultView.getComputedStyle?function(t,e){var i=fabric.document.defaultView.getComputedStyle(t,null);return i?i[e]:void 0}:function(t,e){var i=t.style[e];return!i&&t.currentStyle&&(i=t.currentStyle[e]),i},function(){function t(t){return"undefined"!=typeof t.onselectstart&&(t.onselectstart=fabric.util.falseFunction),r?t.style[r]="none":"string"==typeof t.unselectable&&(t.unselectable="on"),t}function e(t){return"undefined"!=typeof t.onselectstart&&(t.onselectstart=null),r?t.style[r]="":"string"==typeof t.unselectable&&(t.unselectable=""),t}var i=fabric.document.documentElement.style,r="userSelect"in i?"userSelect":"MozUserSelect"in i?"MozUserSelect":"WebkitUserSelect"in i?"WebkitUserSelect":"KhtmlUserSelect"in i?"KhtmlUserSelect":"";fabric.util.makeElementUnselectable=t,fabric.util.makeElementSelectable=e}(),function(){function t(t,e){var i=fabric.document.getElementsByTagName("head")[0],r=fabric.document.createElement("script"),n=!0;r.onload=r.onreadystatechange=function(t){if(n){if("string"==typeof this.readyState&&"loaded"!==this.readyState&&"complete"!==this.readyState)return;n=!1,e(t||fabric.window.event),r=r.onload=r.onreadystatechange=null}},r.src=t,i.appendChild(r)}fabric.util.getScript=t}(),fabric.util.getById=t,fabric.util.toArray=h,fabric.util.makeElement=e,fabric.util.addClass=i,fabric.util.wrapElement=r,fabric.util.getScrollLeftTop=n,fabric.util.getElementOffset=s,fabric.util.getElementStyle=c}(),function(){function t(t,e){return t+(/\?/.test(t)?"&":"?")+e}function e(){}function i(i,n){n||(n={});var s=n.method?n.method.toUpperCase():"GET",o=n.onComplete||function(){},a=r(),h=n.body||n.parameters;return a.onreadystatechange=function(){4===a.readyState&&(o(a),a.onreadystatechange=e)},"GET"===s&&(h=null,"string"==typeof n.parameters&&(i=t(i,n.parameters))),a.open(s,i,!0),"POST"!==s&&"PUT"!==s||a.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),a.send(h),a}var r=function(){for(var t=[function(){return new ActiveXObject("Microsoft.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP")},function(){return new ActiveXObject("Msxml2.XMLHTTP.3.0")},function(){return new XMLHttpRequest}],e=t.length;e--;)try{var i=t[e]();if(i)return t[e]}catch(t){}}();fabric.util.request=i}(),fabric.log=function(){},fabric.warn=function(){},"undefined"!=typeof console&&["log","warn"].forEach(function(t){"undefined"!=typeof console[t]&&"function"==typeof console[t].apply&&(fabric[t]=function(){return console[t].apply(console,arguments)})}),function(){function t(t){e(function(i){t||(t={});var r,n=i||+new Date,s=t.duration||500,o=n+s,a=t.onChange||function(){},h=t.abort||function(){return!1},c=t.easing||function(t,e,i,r){return-i*Math.cos(t/r*(Math.PI/2))+i+e},l="startValue"in t?t.startValue:0,u="endValue"in t?t.endValue:100,f=t.byValue||u-l;t.onStart&&t.onStart(),function i(u){r=u||+new Date;var d=r>o?s:r-n;return h()?void(t.onComplete&&t.onComplete()):(a(c(d,l,f,s)),r>o?void(t.onComplete&&t.onComplete()):void e(i))}(n)})}function e(){return i.apply(fabric.window,arguments)}var i=fabric.window.requestAnimationFrame||fabric.window.webkitRequestAnimationFrame||fabric.window.mozRequestAnimationFrame||fabric.window.oRequestAnimationFrame||fabric.window.msRequestAnimationFrame||function(t){fabric.window.setTimeout(t,1e3/60)};fabric.util.animate=t,fabric.util.requestAnimFrame=e}(),function(){function t(t,e,i,r){return ta?a:o),1===o&&1===a&&0===h&&0===c&&0===f&&0===d)return y;if((f||d)&&(_=" translate("+x(f)+" "+x(d)+") "),r=_+" matrix("+o+" 0 0 "+a+" "+h*o+" "+c*a+") ","svg"===t.nodeName){for(n=t.ownerDocument.createElement("g");t.firstChild;)n.appendChild(t.firstChild);t.appendChild(n)}else n=t,r=n.getAttribute("transform")+r;return n.setAttribute("transform",r),y}function g(t){var e=t.objects,i=t.options;return e=e.map(function(t){return v[m(t.type)].fromObject(t)}),{objects:e,options:i}}function p(t,e,i){e[i]&&e[i].toSVG&&t.push('\t\n','\t\t\n\t\n')}var v=t.fabric||(t.fabric={}),b=v.util.object.extend,m=v.util.string.capitalize,y=v.util.object.clone,_=v.util.toFixed,x=v.util.parseUnit,S=v.util.multiplyTransformMatrices,C=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i,w=/^(symbol|image|marker|pattern|view|svg)$/i,O=/^(?:pattern|defs|symbol|metadata)$/i,T=/^(symbol|g|a|svg)$/i,k={cx:"left",x:"left",r:"radius",cy:"top",y:"top",display:"visible",visibility:"visible",transform:"transformMatrix","fill-opacity":"fillOpacity","fill-rule":"fillRule","font-family":"fontFamily","font-size":"fontSize","font-style":"fontStyle","font-weight":"fontWeight","stroke-dasharray":"strokeDashArray","stroke-linecap":"strokeLineCap","stroke-linejoin":"strokeLineJoin","stroke-miterlimit":"strokeMiterLimit","stroke-opacity":"strokeOpacity","stroke-width":"strokeWidth","text-decoration":"textDecoration","text-anchor":"originX"},j={stroke:"strokeOpacity",fill:"fillOpacity"};v.cssRules={},v.gradientDefs={},v.parseTransformAttribute=function(){function t(t,e){var i=e[0],r=3===e.length?e[1]:0,n=3===e.length?e[2]:0;t[0]=Math.cos(i),t[1]=Math.sin(i),t[2]=-Math.sin(i),t[3]=Math.cos(i),t[4]=r-(t[0]*r+t[2]*n),t[5]=n-(t[1]*r+t[3]*n)}function e(t,e){var i=e[0],r=2===e.length?e[1]:e[0];t[0]=i,t[3]=r}function i(t,e){t[2]=Math.tan(v.util.degreesToRadians(e[0])); +}function r(t,e){t[1]=Math.tan(v.util.degreesToRadians(e[0]))}function n(t,e){t[4]=e[0],2===e.length&&(t[5]=e[1])}var s=[1,0,0,1,0,0],o=v.reNum,a="(?:\\s+,?\\s*|,\\s*)",h="(?:(skewX)\\s*\\(\\s*("+o+")\\s*\\))",c="(?:(skewY)\\s*\\(\\s*("+o+")\\s*\\))",l="(?:(rotate)\\s*\\(\\s*("+o+")(?:"+a+"("+o+")"+a+"("+o+"))?\\s*\\))",u="(?:(scale)\\s*\\(\\s*("+o+")(?:"+a+"("+o+"))?\\s*\\))",f="(?:(translate)\\s*\\(\\s*("+o+")(?:"+a+"("+o+"))?\\s*\\))",d="(?:(matrix)\\s*\\(\\s*("+o+")"+a+"("+o+")"+a+"("+o+")"+a+"("+o+")"+a+"("+o+")"+a+"("+o+")\\s*\\))",g="(?:"+d+"|"+f+"|"+u+"|"+l+"|"+h+"|"+c+")",p="(?:"+g+"(?:"+a+"*"+g+")*)",b="^\\s*(?:"+p+"?)\\s*$",m=new RegExp(b),y=new RegExp(g,"g");return function(o){var a=s.concat(),h=[];if(!o||o&&!m.test(o))return a;o.replace(y,function(o){var c=new RegExp(g).exec(o).filter(function(t){return!!t}),l=c[1],u=c.slice(2).map(parseFloat);switch(l){case"translate":n(a,u);break;case"rotate":u[0]=v.util.degreesToRadians(u[0]),t(a,u);break;case"scale":e(a,u);break;case"skewX":i(a,u);break;case"skewY":r(a,u);break;case"matrix":a=u}h.push(a.concat()),a=s.concat()});for(var c=h[0];h.length>1;)h.shift(),c=v.util.multiplyTransformMatrices(c,h[0]);return c}}();var A=new RegExp("^\\s*("+v.reNum+"+)\\s*,?\\s*("+v.reNum+"+)\\s*,?\\s*("+v.reNum+"+)\\s*,?\\s*("+v.reNum+"+)\\s*$");v.parseSVGDocument=function(){function t(t,e){for(;t&&(t=t.parentNode);)if(t.nodeName&&e.test(t.nodeName.replace("svg:",""))&&!t.getAttribute("instantiated_by_use"))return!0;return!1}return function(e,i,r){if(e){f(e);var n=new Date,s=v.Object.__uid++,o=d(e),a=v.util.toArray(e.getElementsByTagName("*"));if(o.svgUid=s,0===a.length&&v.isLikelyNode){a=e.selectNodes('//*[name(.)!="svg"]');for(var h=[],c=0,l=a.length;c/i,""))),n&&n.documentElement||e&&e(null),v.parseSVGDocument(n.documentElement,function(i,r){M.set(t,{objects:v.util.array.invoke(i,"toObject"),options:r}),e&&e(i,r)},i)}t=t.replace(/^\n\s*/,"").trim(),M.has(t,function(i){i?M.get(t,function(t){var i=g(t);e(i.objects,i.options)}):new v.util.request(t,{method:"get",onComplete:r})})},loadSVGFromString:function(t,e,i){t=t.trim();var r;if("undefined"!=typeof DOMParser){var n=new DOMParser;n&&n.parseFromString&&(r=n.parseFromString(t,"text/xml"))}else v.window.ActiveXObject&&(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(t.replace(//i,"")));v.parseSVGDocument(r.documentElement,function(t,i){e(t,i)},i)},createSVGFontFacesMarkup:function(t){for(var e,i,r,n,s,o,a,h="",c={},l=v.fontPaths,u=0,f=t.length;u',"","\n"].join("")),h},createSVGRefElementsMarkup:function(t){var e=[];return p(e,t,"backgroundColor"),p(e,t,"overlayColor"),e.join("")}})}("undefined"!=typeof exports?exports:this),fabric.ElementsParser=function(t,e,i,r){this.elements=t,this.callback=e,this.options=i,this.reviver=r,this.svgUid=i&&i.svgUid||0},fabric.ElementsParser.prototype.parse=function(){this.instances=new Array(this.elements.length),this.numElements=this.elements.length,this.createObjects()},fabric.ElementsParser.prototype.createObjects=function(){for(var t=0,e=this.elements.length;tt.x&&this.y>t.y},gte:function(t){return this.x>=t.x&&this.y>=t.y},lerp:function(t,i){return"undefined"==typeof i&&(i=.5),i=Math.max(Math.min(1,i),0),new e(this.x+(t.x-this.x)*i,this.y+(t.y-this.y)*i)},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 e(Math.min(this.x,t.x),Math.min(this.y,t.y))},max:function(t){return new e(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 e(this.x,this.y)}}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";function e(t){this.status=t,this.points=[]}var i=t.fabric||(t.fabric={});return i.Intersection?void i.warn("fabric.Intersection is already defined"):(i.Intersection=e,i.Intersection.prototype={constructor:e,appendPoint:function(t){return this.points.push(t),this},appendPoints:function(t){return this.points=this.points.concat(t),this}},i.Intersection.intersectLineLine=function(t,r,n,s){var o,a=(s.x-n.x)*(t.y-n.y)-(s.y-n.y)*(t.x-n.x),h=(r.x-t.x)*(t.y-n.y)-(r.y-t.y)*(t.x-n.x),c=(s.y-n.y)*(r.x-t.x)-(s.x-n.x)*(r.y-t.y);if(0!==c){var l=a/c,u=h/c;0<=l&&l<=1&&0<=u&&u<=1?(o=new e("Intersection"),o.appendPoint(new i.Point(t.x+l*(r.x-t.x),t.y+l*(r.y-t.y)))):o=new e}else o=new e(0===a||0===h?"Coincident":"Parallel");return o},i.Intersection.intersectLinePolygon=function(t,i,r){for(var n,s,o,a=new e,h=r.length,c=0;c0&&(a.status="Intersection"),a},i.Intersection.intersectPolygonPolygon=function(t,i){for(var r=new e,n=t.length,s=0;s0&&(r.status="Intersection"),r},void(i.Intersection.intersectPolygonRectangle=function(t,r,n){var s=r.min(n),o=r.max(n),a=new i.Point(o.x,s.y),h=new i.Point(s.x,o.y),c=e.intersectLinePolygon(s,a,t),l=e.intersectLinePolygon(a,o,t),u=e.intersectLinePolygon(o,h,t),f=e.intersectLinePolygon(h,s,t),d=new e;return d.appendPoints(c.points),d.appendPoints(l.points),d.appendPoints(u.points),d.appendPoints(f.points),d.points.length>0&&(d.status="Intersection"),d}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";function e(t){t?this._tryParsingColor(t):this.setSource([0,0,0,1])}function i(t,e,i){return i<0&&(i+=1),i>1&&(i-=1),i<1/6?t+6*(e-t)*i:i<.5?e:i<2/3?t+(e-t)*(2/3-i)*6:t}var r=t.fabric||(t.fabric={});return r.Color?void r.warn("fabric.Color is already defined."):(r.Color=e,r.Color.prototype={_tryParsingColor:function(t){var i;t in e.colorNameMap&&(t=e.colorNameMap[t]),"transparent"===t&&(i=[255,255,255,0]),i||(i=e.sourceFromHex(t)),i||(i=e.sourceFromRgb(t)),i||(i=e.sourceFromHsl(t)),i||(i=[0,0,0,1]),i&&this.setSource(i)},_rgbToHsl:function(t,e,i){t/=255,e/=255,i/=255;var n,s,o,a=r.util.array.max([t,e,i]),h=r.util.array.min([t,e,i]);if(o=(a+h)/2,a===h)n=s=0;else{var c=a-h;switch(s=o>.5?c/(2-a-h):c/(a+h),a){case t:n=(e-i)/c+(e1?1:s,n){var o=n.split(/\s*;\s*/);""===o[o.length-1]&&o.pop();for(var a=o.length;a--;){var h=o[a].split(/\s*:\s*/),c=h[0].trim(),l=h[1].trim();"stop-color"===c?e=l:"stop-opacity"===c&&(r=l)}}return e||(e=t.getAttribute("stop-color")||"rgb(0,0,0)"),r||(r=t.getAttribute("stop-opacity")),e=new fabric.Color(e),i=e.getAlpha(),r=isNaN(parseFloat(r))?1:parseFloat(r),r*=i,{offset:s,color:e.toRgb(),opacity:r}}function e(t){return{x1:t.getAttribute("x1")||0,y1:t.getAttribute("y1")||0,x2:t.getAttribute("x2")||"100%",y2:t.getAttribute("y2")||0}}function i(t){return{x1:t.getAttribute("fx")||t.getAttribute("cx")||"50%",y1:t.getAttribute("fy")||t.getAttribute("cy")||"50%",r1:0,x2:t.getAttribute("cx")||"50%",y2:t.getAttribute("cy")||"50%",r2:t.getAttribute("r")||"50%"}}function r(t,e,i){var r,n=0,s=1,o="";for(var a in e)"Infinity"===e[a]?e[a]=1:"-Infinity"===e[a]&&(e[a]=0),r=parseFloat(e[a],10),s="string"==typeof e[a]&&/^\d+%$/.test(e[a])?.01:1,"x1"===a||"x2"===a||"r2"===a?(s*="objectBoundingBox"===i?t.width:1,n="objectBoundingBox"===i?t.left||0:0):"y1"!==a&&"y2"!==a||(s*="objectBoundingBox"===i?t.height:1,n="objectBoundingBox"===i?t.top||0:0),e[a]=r*s+n;if("ellipse"===t.type&&null!==e.r2&&"objectBoundingBox"===i&&t.rx!==t.ry){var h=t.ry/t.rx;o=" scale(1, "+h+")",e.y1&&(e.y1/=h),e.y2&&(e.y2/=h)}return o}fabric.Gradient=fabric.util.createClass({offsetX:0,offsetY:0,initialize:function(t){t||(t={});var e={};this.id=fabric.Object.__uid++,this.type=t.type||"linear",e={x1:t.coords.x1||0,y1:t.coords.y1||0,x2:t.coords.x2||0,y2:t.coords.y2||0},"radial"===this.type&&(e.r1=t.coords.r1||0,e.r2=t.coords.r2||0),this.coords=e,this.colorStops=t.colorStops.slice(),t.gradientTransform&&(this.gradientTransform=t.gradientTransform),this.offsetX=t.offsetX||this.offsetX,this.offsetY=t.offsetY||this.offsetY},addColorStop:function(t){for(var e in t){var i=new fabric.Color(t[e]);this.colorStops.push({offset:e,color:i.toRgb(),opacity:i.getAlpha()})}return this},toObject:function(){return{type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY,gradientTransform:this.gradientTransform?this.gradientTransform.concat():this.gradientTransform}},toSVG:function(t){var e,i,r=fabric.util.object.clone(this.coords);if(this.colorStops.sort(function(t,e){return t.offset-e.offset}),!t.group||"path-group"!==t.group.type)for(var n in r)"x1"===n||"x2"===n||"r2"===n?r[n]+=this.offsetX-t.width/2:"y1"!==n&&"y2"!==n||(r[n]+=this.offsetY-t.height/2);i='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"',this.gradientTransform&&(i+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" '),"linear"===this.type?e=["\n']:"radial"===this.type&&(e=["\n']);for(var s=0;s\n');return e.push("linear"===this.type?"\n":"\n"),e.join("")},toLive:function(t,e){var i,r,n=fabric.util.object.clone(this.coords);if(this.type){if(e.group&&"path-group"===e.group.type)for(r in n)"x1"===r||"x2"===r?n[r]+=-this.offsetX+e.width/2:"y1"!==r&&"y2"!==r||(n[r]+=-this.offsetY+e.height/2);"linear"===this.type?i=t.createLinearGradient(n.x1,n.y1,n.x2,n.y2):"radial"===this.type&&(i=t.createRadialGradient(n.x1,n.y1,n.r1,n.x2,n.y2,n.r2));for(var s=0,o=this.colorStops.length;s\n\n\n'},toLive:function(t){var e="function"==typeof this.source?this.source():this.source;if(!e)return"";if("undefined"!=typeof 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 e=t.fabric||(t.fabric={}),i=e.util.toFixed;return e.Shadow?void e.warn("fabric.Shadow is already defined."):(e.Shadow=e.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(t){"string"==typeof t&&(t=this._parseShadow(t));for(var i in t)this[i]=t[i];this.id=e.Object.__uid++},_parseShadow:function(t){var i=t.trim(),r=e.Shadow.reOffsetsAndBlur.exec(i)||[],n=i.replace(e.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)";return{color:n.trim(),offsetX:parseInt(r[1],10)||0,offsetY:parseInt(r[2],10)||0,blur:parseInt(r[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(t){var r=40,n=40,s=e.Object.NUM_FRACTION_DIGITS,o=e.util.rotateVector({x:this.offsetX,y:this.offsetY},e.util.degreesToRadians(-t.angle)),a=20;return t.width&&t.height&&(r=100*i((Math.abs(o.x)+this.blur)/t.width,s)+a,n=100*i((Math.abs(o.y)+this.blur)/t.height,s)+a),t.flipX&&(o.x*=-1),t.flipY&&(o.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};var t={},i=e.Shadow.prototype;return["color","blur","offsetX","offsetY","affectStroke"].forEach(function(e){this[e]!==i[e]&&(t[e]=this[e])},this),t}}),void(e.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/))}("undefined"!=typeof exports?exports:this),function(){"use strict";if(fabric.StaticCanvas)return void fabric.warn("fabric.StaticCanvas is already defined.");var t=fabric.util.object.extend,e=fabric.util.getElementOffset,i=fabric.util.removeFromArray,r=fabric.util.toFixed,n=new Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass({initialize:function(t,e){e||(e={}),this._initStatic(t,e)},backgroundColor:"",backgroundImage:null,overlayColor:"",overlayImage:null,includeDefaultValues:!0,stateful:!0,renderOnAddRemove:!0,clipTo:null,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,viewportTransform:[1,0,0,1,0,0],backgroundVpt:!0,overlayVpt:!0,onBeforeScaleRotate:function(){},enableRetinaScaling:!0,_initStatic:function(t,e){var i=fabric.StaticCanvas.prototype.renderAll.bind(this);this._objects=[],this._createLowerCanvas(t),this._initOptions(e),this._setImageSmoothing(),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(){this._isRetinaScaling()&&(this.lowerCanvasEl.setAttribute("width",this.width*fabric.devicePixelRatio),this.lowerCanvasEl.setAttribute("height",this.height*fabric.devicePixelRatio),this.contextContainer.scale(fabric.devicePixelRatio,fabric.devicePixelRatio))},calcOffset:function(){return this._offset=e(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)},_setImageSmoothing:function(){var t=this.getContext();t.imageSmoothingEnabled=t.imageSmoothingEnabled||t.webkitImageSmoothingEnabled||t.mozImageSmoothingEnabled||t.msImageSmoothingEnabled||t.oImageSmoothingEnabled,t.imageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(t,e,i,r){return"string"==typeof e?fabric.util.loadImage(e,function(e){e&&(this[t]=new fabric.Image(e,r)),i&&i(e)},this,r&&r.crossOrigin):(r&&e.setOptions(r),this[t]=e,i&&i(e)),this},__setBgOverlayColor:function(t,e,i){if(e&&e.source){var r=this;fabric.util.loadImage(e.source,function(n){r[t]=new fabric.Pattern({source:n,repeat:e.repeat,offsetX:e.offsetX,offsetY:e.offsetY}),i&&i()})}else this[t]=e,i&&i();return this},_createCanvasElement:function(t){var e=fabric.util.createCanvasElement(t);if(e.style||(e.style={}),!e)throw n;if("undefined"==typeof e.getContext)throw n;return e},_initOptions:function(t){for(var e in t)this[e]=t[e];this.width=this.width||parseInt(this.lowerCanvasEl.width,10)||0,this.height=this.height||parseInt(this.lowerCanvasEl.height,10)||0,this.lowerCanvasEl.style&&(this.lowerCanvasEl.width=this.width,this.lowerCanvasEl.height=this.height,this.lowerCanvasEl.style.width=this.width+"px",this.lowerCanvasEl.style.height=this.height+"px",this.viewportTransform=this.viewportTransform.slice())},_createLowerCanvas:function(t){this.lowerCanvasEl=fabric.util.getById(t)||this._createCanvasElement(t),fabric.util.addClass(this.lowerCanvasEl,"lower-canvas"),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;e=e||{};for(var r in t)i=t[r],e.cssOnly||(this._setBackstoreDimension(r,t[r]),i+="px"),e.backstoreOnly||this._setCssDimension(r,i);return this._initRetinaScaling(),this._setImageSmoothing(),this.calcOffset(),e.cssOnly||this.renderAll(),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 Math.sqrt(this.viewportTransform[0]*this.viewportTransform[3])},setViewportTransform:function(t){var e,i=this._activeGroup;this.viewportTransform=t;for(var r=0,n=this._objects.length;r"),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,n=e.width||this.width,s=e.height||this.height,o='viewBox="0 0 '+this.width+" "+this.height+'" ',a=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?o='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,o='viewBox="'+r(-i[4]/i[0],a)+" "+r(-i[5]/i[3],a)+" "+r(this.width/i[0],a)+" "+r(this.height/i[3],a)+'" '),t.push("\n',"Created with Fabric.js ",fabric.version,"\n","",fabric.createSVGFontFacesMarkup(this.getObjects()),fabric.createSVGRefElementsMarkup(this),"\n")},_setSVGObjects:function(t,e){for(var i,r=0,n=this.getObjects(),s=n.length;r\n"):this[e]&&"overlayColor"===e&&t.push('\n")},sendToBack:function(t){if(!t)return this;var e,r,n,s=this._activeGroup;if(t===s)for(n=s._objects,e=n.length;e--;)r=n[e],i(this._objects,r),this._objects.unshift(r);else i(this._objects,t),this._objects.unshift(t);return this.renderAll&&this.renderAll()},bringToFront:function(t){if(!t)return this;var e,r,n,s=this._activeGroup;if(t===s)for(n=s._objects,e=0;e=0;--n){var s=t.intersectsWithObject(this._objects[n])||t.isContainedWithinObject(this._objects[n])||this._objects[n].isContainedWithinObject(t);if(s){r=n;break}}}else r=e-1;return r},bringForward:function(t,e){if(!t)return this;var r,n,s,o,a,h=this._activeGroup;if(t===h)for(a=h._objects,r=a.length;r--;)n=a[r],s=this._objects.indexOf(n),s!==this._objects.length-1&&(o=s+1,i(this._objects,n),this._objects.splice(o,0,n));else s=this._objects.indexOf(t),s!==this._objects.length-1&&(o=this._findNewUpperIndex(t,s,e),i(this._objects,t),this._objects.splice(o,0,t));return this.renderAll&&this.renderAll(),this},_findNewUpperIndex:function(t,e,i){var r;if(i){r=e;for(var n=e+1;n"}}),t(fabric.StaticCanvas.prototype,fabric.Observable),t(fabric.StaticCanvas.prototype,fabric.Collection),t(fabric.StaticCanvas.prototype,fabric.DataURLExporter),t(fabric.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(t){var e=fabric.util.createCanvasElement();if(!e||!e.getContext)return null;var i=e.getContext("2d");if(!i)return null;switch(t){case"getImageData":return"undefined"!=typeof i.getImageData;case"setLineDash":return"undefined"!=typeof i.setLineDash;case"toDataURL":return"undefined"!=typeof e.toDataURL;case"toDataURLWithQuality":try{return e.toDataURL("image/jpeg",0),!0}catch(t){}return!1;default:return null}}}),fabric.StaticCanvas.prototype.toJSON=fabric.StaticCanvas.prototype.toObject}(),fabric.BaseBrush=fabric.util.createClass({color:"rgb(0, 0, 0)",width:1,shadow:null,strokeLineCap:"round",strokeLineJoin:"round",strokeDashArray:null,setShadow:function(t){return this.shadow=new fabric.Shadow(t),this},_setBrushStyles:function(){var t=this.canvas.contextTop;t.strokeStyle=this.color,t.lineWidth=this.width,t.lineCap=this.strokeLineCap,t.lineJoin=this.strokeLineJoin,this.strokeDashArray&&fabric.StaticCanvas.supports("setLineDash")&&t.setLineDash(this.strokeDashArray)},_setShadow:function(){if(this.shadow){var t=this.canvas.contextTop;t.shadowColor=this.shadow.color,t.shadowBlur=this.shadow.blur,t.shadowOffsetX=this.shadow.offsetX,t.shadowOffsetY=this.shadow.offsetY}},_resetShadow:function(){var t=this.canvas.contextTop;t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0}}),function(){fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{initialize:function(t){this.canvas=t,this._points=[]},onMouseDown:function(t){this._prepareForDrawing(t),this._captureDrawingPath(t),this._render()},onMouseMove:function(t){this._captureDrawingPath(t),this.canvas.clearContext(this.canvas.contextTop),this._render()},onMouseUp:function(){this._finalizeAndAddPath()},_prepareForDrawing:function(t){var e=new fabric.Point(t.x,t.y);this._reset(),this._addPoint(e),this.canvas.contextTop.moveTo(e.x,e.y)},_addPoint:function(t){this._points.push(t)},_reset:function(){this._points.length=0,this._setBrushStyles(),this._setShadow()},_captureDrawingPath:function(t){var e=new fabric.Point(t.x,t.y);this._addPoint(e)},_render:function(){var t=this.canvas.contextTop,e=this.canvas.viewportTransform,i=this._points[0],r=this._points[1];t.save(),t.transform(e[0],e[1],e[2],e[3],e[4],e[5]),t.beginPath(),2===this._points.length&&i.x===r.x&&i.y===r.y&&(i.x-=.5,r.x+=.5),t.moveTo(i.x,i.y);for(var n=1,s=this._points.length;n0?1:-1,"y"===i&&(s=e.target.skewY,o="top",a="bottom",r="originY"),n[-1]=o,n[1]=a,e.target.flipX&&(c*=-1),e.target.flipY&&(c*=-1),0===s?(e.skewSign=-h*t*c,e[r]=n[-t]):(s=s>0?1:-1,e.skewSign=s,e[r]=n[s*h*c])},_skewObject:function(t,e,i){var r=this._currentTransform,n=r.target,s=!1,o=n.get("lockSkewingX"),a=n.get("lockSkewingY");if(o&&"x"===i||a&&"y"===i)return!1;var h,c,l=n.getCenterPoint(),u=n.toLocalPoint(new fabric.Point(t,e),"center","center")[i],f=n.toLocalPoint(new fabric.Point(r.lastX,r.lastY),"center","center")[i],d=n._getTransformedDimensions();return this._changeSkewTransformOrigin(u-f,r,i),h=n.toLocalPoint(new fabric.Point(t,e),r.originX,r.originY)[i],c=n.translateToOriginPoint(l,r.originX,r.originY),s=this._setObjectSkew(h,r,i,d),r.lastX=t,r.lastY=e,n.setPositionByOrigin(c,r.originX,r.originY),s},_setObjectSkew:function(t,e,i,r){var n,s,o,a,h,c,l,u,f,d=e.target,g=!1,p=e.skewSign;return"x"===i?(a="y",h="Y",c="X",u=0,f=d.skewY):(a="x",h="X",c="Y",u=d.skewX,f=0),o=d._getTransformedDimensions(u,f),l=2*Math.abs(t)-o[i],l<=2?n=0:(n=p*Math.atan(l/d["scale"+c]/(o[a]/d["scale"+h])),n=fabric.util.radiansToDegrees(n)),g=d["skew"+c]!==n,d.set("skew"+c,n),0!==d["skew"+h]&&(s=d._getTransformedDimensions(),n=r[a]/s[a]*d["scale"+h],d.set("scale"+h,n)),g},_scaleObject:function(t,e,i){var r=this._currentTransform,n=r.target,s=n.get("lockScalingX"),o=n.get("lockScalingY"),a=n.get("lockScalingFlip");if(s&&o)return!1;var h=n.translateToOriginPoint(n.getCenterPoint(),r.originX,r.originY),c=n.toLocalPoint(new fabric.Point(t,e),r.originX,r.originY),l=n._getTransformedDimensions(),u=!1;return this._setLocalMouse(c,r),u=this._setObjectScale(c,r,s,o,i,a,l),n.setPositionByOrigin(h,r.originX,r.originY),u},_setObjectScale:function(t,e,i,r,n,s,o){var a,h,c,l,u=e.target,f=!1,d=!1,g=!1;return c=t.x*u.scaleX/o.x,l=t.y*u.scaleY/o.y,a=u.scaleX!==c,h=u.scaleY!==l,s&&c<=0&&ci.padding?t.x<0?t.x+=i.padding:t.x-=i.padding:t.x=0,n(t.y)>i.padding?t.y<0?t.y+=i.padding:t.y-=i.padding:t.y=0},_rotateObject:function(t,e){var n=this._currentTransform;if(n.target.get("lockRotation"))return!1;var s=r(n.ey-n.top,n.ex-n.left),o=r(e-n.top,t-n.left),a=i(o-s+n.theta);return a<0&&(a=360+a),n.target.angle=a%360,!0},setCursor:function(t){this.upperCanvasEl.style.cursor=t},_resetObjectTransform:function(t){t.scaleX=1,t.scaleY=1,t.skewX=0,t.skewY=0,t.setAngle(0)},_drawSelection:function(t){var e=this._groupSelector,i=e.left,r=e.top,a=n(i),h=n(r);if(this.selectionColor&&(t.fillStyle=this.selectionColor,t.fillRect(e.ex-(i>0?0:-i),e.ey-(r>0?0:-r),a,h)),this.selectionLineWidth&&this.selectionBorderColor)if(t.lineWidth=this.selectionLineWidth,t.strokeStyle=this.selectionBorderColor,this.selectionDashArray.length>1&&!s){var c=e.ex+o-(i>0?0:a),l=e.ey+o-(r>0?0:h);t.beginPath(),fabric.util.drawDashedLine(t,c,l,c+a,l,this.selectionDashArray),fabric.util.drawDashedLine(t,c,l+h-1,c+a,l+h-1,this.selectionDashArray),fabric.util.drawDashedLine(t,c,l,c,l+h,this.selectionDashArray),fabric.util.drawDashedLine(t,c+a-1,l,c+a-1,l+h,this.selectionDashArray),t.closePath(),t.stroke()}else fabric.Object.prototype._setLineDash.call(this,t,this.selectionDashArray),t.strokeRect(e.ex+o-(i>0?0:a),e.ey+o-(r>0?0:h),a,h)},findTarget:function(t,e){if(!this.skipTargetFind){var i,r=!0,n=this.getPointer(t,r),s=this.getActiveGroup(),o=this.getActiveObject();if(s&&!e&&this._checkTarget(n,s))return this._fireOverOutEvents(s,t),s;if(o&&o._findTargetCorner(n))return this._fireOverOutEvents(o,t),o;if(o&&this._checkTarget(n,o)){if(!this.preserveObjectStacking)return this._fireOverOutEvents(o,t),o;i=o}this.targets=[];var a=this._searchPossibleTargets(this._objects,n);return t[this.altSelectionKey]&&a&&i&&a!==i&&(a=i),this._fireOverOutEvents(a,t),a}},_fireOverOutEvents:function(t,e){t?this._hoveredTarget!==t&&(this._hoveredTarget&&(this.fire("mouse:out",{target:this._hoveredTarget,e:e}),this._hoveredTarget.fire("mouseout")),this.fire("mouse:over",{target:t,e:e}),t.fire("mouseover"),this._hoveredTarget=t):this._hoveredTarget&&(this.fire("mouse:out",{target:this._hoveredTarget,e:e}),this._hoveredTarget.fire("mouseout"),this._hoveredTarget=null)},_checkTarget:function(t,e){if(e&&e.visible&&e.evented&&this.containsPoint(null,e,t)){if(!this.perPixelTargetFind&&!e.perPixelTargetFind||e.isEditing)return!0;var i=this.isTargetTransparent(e,t.x,t.y);if(!i)return!0}},_searchPossibleTargets:function(t,e){for(var i,r,n,s=t.length;s--;)if(this._checkTarget(e,t[s])){i=t[s],"group"===i.type&&i.subTargetCheck&&(r=this._normalizePointer(i,e),n=this._searchPossibleTargets(i._objects,r),n&&this.targets.push(n));break}return i},restorePointerVpt:function(t){return fabric.util.transformPoint(t,fabric.util.invertTransform(this.viewportTransform))},getPointer:function(e,i,r){r||(r=this.upperCanvasEl);var n,s=t(e),o=r.getBoundingClientRect(),a=o.width||0,h=o.height||0;return a&&h||("top"in o&&"bottom"in o&&(h=Math.abs(o.top-o.bottom)),"right"in o&&"left"in o&&(a=Math.abs(o.right-o.left))),this.calcOffset(),s.x=s.x-this._offset.left,s.y=s.y-this._offset.top,i||(s=this.restorePointerVpt(s)),n=0===a||0===h?{width:1,height:1}:{width:r.width/a,height:r.height/h},{x:s.x*n.width,y:s.y*n.height}},_createUpperCanvas:function(){var t=this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/,"");this.upperCanvasEl=this._createCanvasElement(),fabric.util.addClass(this.upperCanvasEl,"upper-canvas "+t),this.wrapperEl.appendChild(this.upperCanvasEl),this._copyCanvasStyle(this.lowerCanvasEl,this.upperCanvasEl),this._applyCanvasStyle(this.upperCanvasEl),this.contextTop=this.upperCanvasEl.getContext("2d")},_createCacheCanvas:function(){this.cacheCanvasEl=this._createCanvasElement(),this.cacheCanvasEl.setAttribute("width",this.width),this.cacheCanvasEl.setAttribute("height",this.height),this.contextCache=this.cacheCanvasEl.getContext("2d")},_initWrapperElement:function(){this.wrapperEl=fabric.util.wrapElement(this.lowerCanvasEl,"div",{class:this.containerClass}),fabric.util.setStyle(this.wrapperEl,{width:this.getWidth()+"px",height:this.getHeight()+"px",position:"relative"}),fabric.util.makeElementUnselectable(this.wrapperEl)},_applyCanvasStyle:function(t){var e=this.getWidth()||t.width,i=this.getHeight()||t.height;fabric.util.setStyle(t,{position:"absolute",width:e+"px",height:i+"px",left:0,top:0}),t.width=e,t.height=i,fabric.util.makeElementUnselectable(t)},_copyCanvasStyle:function(t,e){e.style.cssText=t.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl},_setActiveObject:function(t){this._activeObject&&this._activeObject.set("active",!1),this._activeObject=t,t.set("active",!0)},setActiveObject:function(t,e){return this._setActiveObject(t),this.renderAll(),this.fire("object:selected",{target:t,e:e}),t.fire("selected",{e:e}),this},getActiveObject:function(){return this._activeObject},_onObjectRemoved:function(t){this.getActiveObject()===t&&(this.fire("before:selection:cleared",{target:t}),this._discardActiveObject(),this.fire("selection:cleared",{target:t}),t.fire("deselected")),this.callSuper("_onObjectRemoved",t)},_discardActiveObject:function(){this._activeObject&&this._activeObject.set("active",!1),this._activeObject=null},discardActiveObject:function(t){var e=this._activeObject;return this.fire("before:selection:cleared",{target:e,e:t}),this._discardActiveObject(),this.fire("selection:cleared",{e:t}),e&&e.fire("deselected",{e:t}),this},_setActiveGroup:function(t){this._activeGroup=t,t&&t.set("active",!0)},setActiveGroup:function(t,e){return this._setActiveGroup(t),t&&(this.fire("object:selected",{target:t,e:e}),t.fire("selected",{e:e})),this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var t=this.getActiveGroup();t&&t.destroy(),this.setActiveGroup(null)},discardActiveGroup:function(t){var e=this.getActiveGroup();return this.fire("before:selection:cleared",{e:t,target:e}),this._discardActiveGroup(),this.fire("selection:cleared",{e:t}),this},deactivateAll:function(){for(var t=this.getObjects(),e=0,i=t.length;e1)){var r=this._groupSelector;r?(i=this.getPointer(t,!0),r.left=i.x-r.ex,r.top=i.y-r.ey,this.renderTop()):this._currentTransform?this._transformObject(t):(e=this.findTarget(t),this._setCursorFromEvent(t,e)),this._handleEvent(t,"move",e?e:null)}},__onMouseWheel:function(t){this.fire("mouse:wheel",{e:t})},_transformObject:function(t){var e=this.getPointer(t),i=this._currentTransform;i.reset=!1,i.target.isMoving=!0,this._beforeScaleTransform(t,i),this._performTransformAction(t,i,e),i.actionPerformed&&this.renderAll()},_performTransformAction:function(t,e,i){var r=i.x,n=i.y,s=e.target,o=e.action,a=!1;"rotate"===o?(a=this._rotateObject(r,n))&&this._fire("rotating",s,t):"scale"===o?(a=this._onScale(t,e,r,n))&&this._fire("scaling",s,t):"scaleX"===o?(a=this._scaleObject(r,n,"x"))&&this._fire("scaling",s,t):"scaleY"===o?(a=this._scaleObject(r,n,"y"))&&this._fire("scaling",s,t):"skewX"===o?(a=this._skewObject(r,n,"x"))&&this._fire("skewing",s,t):"skewY"===o?(a=this._skewObject(r,n,"y"))&&this._fire("skewing",s,t):(a=this._translateObject(r,n),a&&(this._fire("moving",s,t),this.setCursor(s.moveCursor||this.moveCursor))),e.actionPerformed=a},_fire:function(t,e,i){this.fire("object:"+t,{target:e,e:i}),e.fire(t,{e:i})},_beforeScaleTransform:function(t,e){if("scale"===e.action||"scaleX"===e.action||"scaleY"===e.action){var i=this._shouldCenterTransform(e.target);(i&&("center"!==e.originX||"center"!==e.originY)||!i&&"center"===e.originX&&"center"===e.originY)&&(this._resetCurrentTransform(),e.reset=!0)}},_onScale:function(t,e,i,r){return!t[this.uniScaleKey]&&!this.uniScaleTransform||e.target.get("lockUniScaling")?(e.reset||"scale"!==e.currentAction||this._resetCurrentTransform(),e.currentAction="scaleEqually",this._scaleObject(i,r,"equally")):(e.currentAction="scale",this._scaleObject(i,r))},_setCursorFromEvent:function(t,e){if(!e)return this.setCursor(this.defaultCursor),!1;var i=e.hoverCursor||this.hoverCursor;if(e.selectable){var r=this.getActiveGroup(),n=e._findTargetCorner&&(!r||!r.contains(e))&&e._findTargetCorner(this.getPointer(t,!0));n?this._setCornerCursor(n,e,t):this.setCursor(i)}else this.setCursor(i);return!0},_setCornerCursor:function(e,i,r){if(e in t)this.setCursor(this._getRotatedCornerCursor(e,i,r));else{if("mtr"!==e||!i.hasRotatingPoint)return this.setCursor(this.defaultCursor),!1;this.setCursor(this.rotationCursor)}},_getRotatedCornerCursor:function(e,i,r){var n=Math.round(i.getAngle()%360/45);return n<0&&(n+=8),n+=t[e],r[this.altActionKey]&&t[e]%2===0&&(n+=2),n%=8,this.cursorMap[n]}})}(),function(){var t=Math.min,e=Math.max;fabric.util.object.extend(fabric.Canvas.prototype,{_shouldGroup:function(t,e){var i=this.getActiveObject();return t[this.selectionKey]&&e&&e.selectable&&(this.getActiveGroup()||i&&i!==e)&&this.selection},_handleGrouping:function(t,e){var i=this.getActiveGroup();(e!==i||(e=this.findTarget(t,!0)))&&(i?this._updateActiveGroup(e,t):this._createActiveGroup(e,t),this._activeGroup&&this._activeGroup.saveCoords())},_updateActiveGroup:function(t,e){var i=this.getActiveGroup();if(i.contains(t)){if(i.removeWithUpdate(t),t.set("active",!1),1===i.size())return this.discardActiveGroup(e),void this.setActiveObject(i.item(0))}else i.addWithUpdate(t);this.fire("selection:created",{target:i,e:e}),i.set("active",!0)},_createActiveGroup:function(t,e){if(this._activeObject&&t!==this._activeObject){var i=this._createGroup(t);i.addWithUpdate(),this.setActiveGroup(i),this._activeObject=null,this.fire("selection:created",{target:i,e:e})}t.set("active",!0)},_createGroup:function(t){var e=this.getObjects(),i=e.indexOf(this._activeObject)1&&(e=new fabric.Group(e.reverse(),{canvas:this}),e.addWithUpdate(),this.setActiveGroup(e,t),e.saveCoords(),this.fire("selection:created",{target:e}),this.renderAll())},_collectObjects:function(){for(var i,r=[],n=this._groupSelector.ex,s=this._groupSelector.ey,o=n+this._groupSelector.left,a=s+this._groupSelector.top,h=new fabric.Point(t(n,o),t(s,a)),c=new fabric.Point(e(n,o),e(s,a)),l=n===o&&s===a,u=this._objects.length;u--&&(i=this._objects[u],!(i&&i.selectable&&i.visible&&(i.intersectsWithRect(h,c)||i.isContainedWithinRect(h,c)||i.containsPoint(h)||i.containsPoint(c))&&(i.set("active",!0),r.push(i),l))););return r},_maybeGroupObjects:function(t){this.selection&&this._groupSelector&&this._groupSelectedObjects(t);var e=this.getActiveGroup();e&&(e.setObjectsCoords().setCoords(),e.isMoving=!1,this.setCursor(this.defaultCursor)),this._groupSelector=null,this._currentTransform=null}})}(),function(){var t=fabric.StaticCanvas.supports("toDataURLWithQuality");fabric.util.object.extend(fabric.StaticCanvas.prototype,{toDataURL:function(t){t||(t={});var e=t.format||"png",i=t.quality||1,r=t.multiplier||1,n={left:t.left||0,top:t.top||0,width:t.width||0,height:t.height||0};return this.__toDataURLWithMultiplier(e,i,n,r)},__toDataURLWithMultiplier:function(t,e,i,r){var n=this.getWidth(),s=this.getHeight(),o=(i.width||this.getWidth())*r,a=(i.width||this.getHeight())*r,h=this.getZoom(),c=h*r,l=this.viewportTransform,u=(l[4]-i.left)*r,f=(l[5]-i.top)*r,d=[c,0,0,c,u,f],g=this.interactive;this.viewportTransform=d,this.interactive&&(this.interactive=!1),n!==o||s!==a?this.setDimensions({width:o,height:a}):this.renderAll();var p=this.__toDataURL(t,e,i);return g&&(this.interactive=g),this.viewportTransform=l,this.setDimensions({width:n,height:s}),p},__toDataURL:function(e,i){var r=this.contextContainer.canvas;"jpg"===e&&(e="jpeg");var n=t?r.toDataURL("image/"+e,i):r.toDataURL("image/"+e);return n},toDataURLWithMultiplier:function(t,e,i){return this.toDataURL({format:t,multiplier:e,quality:i})}})}(),fabric.util.object.extend(fabric.StaticCanvas.prototype,{loadFromDatalessJSON:function(t,e,i){return this.loadFromJSON(t,e,i)},loadFromJSON:function(t,e,i){if(t){var r="string"==typeof t?JSON.parse(t):fabric.util.object.clone(t);this.clear();var n=this;return this._enlivenObjects(r.objects,function(){n._setBgOverlay(r,function(){delete r.objects,delete r.backgroundImage,delete r.overlayImage,delete r.background,delete r.overlay;for(var t in r)n[t]=r[t];e&&e()})},i),this}},_setBgOverlay:function(t,e){var i=this,r={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(!(t.backgroundImage||t.overlayImage||t.background||t.overlay))return void(e&&e());var n=function(){r.backgroundImage&&r.overlayImage&&r.backgroundColor&&r.overlayColor&&(i.renderAll(),e&&e())};this.__setBgOverlay("backgroundImage",t.backgroundImage,r,n),this.__setBgOverlay("overlayImage",t.overlayImage,r,n),this.__setBgOverlay("backgroundColor",t.background,r,n),this.__setBgOverlay("overlayColor",t.overlay,r,n),n()},__setBgOverlay:function(t,e,i,r){var n=this;return e?void("backgroundImage"===t||"overlayImage"===t?fabric.Image.fromObject(e,function(e){n[t]=e,i[t]=!0,r&&r()}):this["set"+fabric.util.string.capitalize(t,!0)](e,function(){i[t]=!0,r&&r()})):void(i[t]=!0)},_enlivenObjects:function(t,e,i){var r=this;if(!t||0===t.length)return void(e&&e());var n=this.renderOnAddRemove;this.renderOnAddRemove=!1,fabric.util.enlivenObjects(t,function(t){t.forEach(function(t,e){r.insertAt(t,e)}),r.renderOnAddRemove=n,e&&e()},null,i)},_toDataURL:function(t,e){this.clone(function(i){e(i.toDataURL(t))})},_toDataURLWithMultiplier:function(t,e,i){this.clone(function(r){i(r.toDataURLWithMultiplier(t,e))})},clone:function(t,e){var i=JSON.stringify(this.toJSON(e));this.cloneWithoutData(function(e){e.loadFromJSON(i,function(){t&&t(e)})})},cloneWithoutData:function(t){var e=fabric.document.createElement("canvas");e.width=this.getWidth(),e.height=this.getHeight();var i=new fabric.Canvas(e);i.clipTo=this.clipTo,this.backgroundImage?(i.setBackgroundImage(this.backgroundImage.src,function(){i.renderAll(),t&&t(i)}),i.backgroundImageOpacity=this.backgroundImageOpacity,i.backgroundImageStretch=this.backgroundImageStretch):t&&t(i)}}),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend,r=e.util.toFixed,n=e.util.string.capitalize,s=e.util.degreesToRadians,o=e.StaticCanvas.supports("setLineDash");e.Object||(e.Object=e.util.createClass({type:"object",originX:"left",originY:"top",top:0,left:0,width:0,height:0,scaleX:1,scaleY:1,flipX:!1,flipY:!1,opacity:1,angle:0,skewX:0,skewY:0,cornerSize:13,transparentCorners:!0,hoverCursor:null,moveCursor:null,padding:0,borderColor:"rgba(102,153,255,0.75)",borderDashArray:null,cornerColor:"rgba(102,153,255,0.5)",cornerStrokeColor:null,cornerStyle:"rect",cornerDashArray:null,centeredScaling:!1,centeredRotation:!0,fill:"rgb(0,0,0)",fillRule:"nonzero",globalCompositeOperation:"source-over",backgroundColor:"",selectionBackgroundColor:"",stroke:null,strokeWidth:1,strokeDashArray:null,strokeLineCap:"butt",strokeLineJoin:"miter",strokeMiterLimit:10,shadow:null,borderOpacityWhenMoving:.4,borderScaleFactor:1,transformMatrix:null,minScaleLimit:.01,selectable:!0,evented:!0,visible:!0,hasControls:!0,hasBorders:!0,hasRotatingPoint:!0,rotatingPointOffset:40,perPixelTargetFind:!1,includeDefaultValues:!0,clipTo:null,lockMovementX:!1,lockMovementY:!1,lockRotation:!1,lockScalingX:!1,lockScalingY:!1,lockUniScaling:!1,lockSkewingX:!1,lockSkewingY:!1,lockScalingFlip:!1,excludeFromExport:!1,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor skewX skewY".split(" "),initialize:function(t){t&&this.setOptions(t)},_initGradient:function(t){!t.fill||!t.fill.colorStops||t.fill instanceof e.Gradient||this.set("fill",new e.Gradient(t.fill)),!t.stroke||!t.stroke.colorStops||t.stroke instanceof e.Gradient||this.set("stroke",new e.Gradient(t.stroke))},_initPattern:function(t){!t.fill||!t.fill.source||t.fill instanceof e.Pattern||this.set("fill",new e.Pattern(t.fill)),!t.stroke||!t.stroke.source||t.stroke instanceof e.Pattern||this.set("stroke",new e.Pattern(t.stroke))},_initClipping:function(t){if(t.clipTo&&"string"==typeof t.clipTo){var i=e.util.getFunctionBody(t.clipTo);"undefined"!=typeof i&&(this.clipTo=new Function("ctx",i))}},setOptions:function(t){for(var e in t)this.set(e,t[e]);this._initGradient(t),this._initPattern(t),this._initClipping(t)},transform:function(t,e){this.group&&!this.group._transformDone&&this.group===this.canvas._activeGroup&&this.group.transform(t);var i=e?this._getLeftTopCoords():this.getCenterPoint();t.translate(i.x,i.y),t.rotate(s(this.angle)),t.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1)),t.transform(1,0,Math.tan(s(this.skewX)),1,0,0),t.transform(1,Math.tan(s(this.skewY)),0,1,0,0)},toObject:function(t){var i=e.Object.NUM_FRACTION_DIGITS,n={type:this.type,originX:this.originX,originY:this.originY,left:r(this.left,i),top:r(this.top,i),width:r(this.width,i),height:r(this.height,i),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject?this.stroke.toObject():this.stroke,strokeWidth:r(this.strokeWidth,i),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:r(this.strokeMiterLimit,i),scaleX:r(this.scaleX,i),scaleY:r(this.scaleY,i),angle:r(this.getAngle(),i),flipX:this.flipX,flipY:this.flipY,opacity:r(this.opacity,i),shadow:this.shadow&&this.shadow.toObject?this.shadow.toObject():this.shadow,visible:this.visible,clipTo:this.clipTo&&String(this.clipTo),backgroundColor:this.backgroundColor,fillRule:this.fillRule,globalCompositeOperation:this.globalCompositeOperation,transformMatrix:this.transformMatrix?this.transformMatrix.concat():this.transformMatrix,skewX:r(this.skewX,i),skewY:r(this.skewY,i)};return this.includeDefaultValues||(n=this._removeDefaultValues(n)),e.util.populateWithProperties(this,n,t),n},toDatalessObject:function(t){return this.toObject(t)},_removeDefaultValues:function(t){var i=e.util.getKlass(t.type).prototype,r=i.stateProperties;return r.forEach(function(e){t[e]===i[e]&&delete t[e];var r="[object Array]"===Object.prototype.toString.call(t[e])&&"[object Array]"===Object.prototype.toString.call(i[e]);r&&0===t[e].length&&0===i[e].length&&delete t[e]}),t},toString:function(){return"#"},get:function(t){return this[t]},getObjectScaling:function(){var t=this.scaleX,e=this.scaleY;if(this.group){var i=this.group.getObjectScaling();t*=i.scaleX,e*=i.scaleY}return{scaleX:t,scaleY:e}},_setObject:function(t){for(var e in t)this._set(e,t[e])},set:function(t,e){return"object"==typeof t?this._setObject(t):"function"==typeof e&&"clipTo"!==t?this._set(t,e(this.get(t))):this._set(t,e),this},_set:function(t,i){var r="scaleX"===t||"scaleY"===t;return r&&(i=this._constrainScale(i)),"scaleX"===t&&i<0?(this.flipX=!this.flipX,i*=-1):"scaleY"===t&&i<0?(this.flipY=!this.flipY,i*=-1):"shadow"!==t||!i||i instanceof e.Shadow||(i=new e.Shadow(i)),this[t]=i,"width"!==t&&"height"!==t||(this.minScaleLimit=Math.min(.1,1/Math.max(this.width,this.height))),this},setOnGroup:function(){},toggle:function(t){var e=this.get(t);return"boolean"==typeof e&&this.set(t,!e),this},setSourcePath:function(t){return this.sourcePath=t,this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:[1,0,0,1,0,0]},render:function(t,i){0===this.width&&0===this.height||!this.visible||(t.save(),this._setupCompositeOperation(t),this.drawSelectionBackground(t),i||this.transform(t),this._setOpacity(t),this._setShadow(t),this._renderBackground(t),this._setStrokeStyles(t),this._setFillStyles(t),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.clipTo&&e.util.clipContext(this,t),this._render(t,i),this.clipTo&&t.restore(),t.restore())},_renderBackground:function(t){this.backgroundColor&&(t.fillStyle=this.backgroundColor,t.fillRect(-this.width/2,-this.height/2,this.width,this.height),this._removeShadow(t))},_setOpacity:function(t){this.group&&this.group._setOpacity(t),t.globalAlpha*=this.opacity},_setStrokeStyles:function(t){this.stroke&&(t.lineWidth=this.strokeWidth,t.lineCap=this.strokeLineCap,t.lineJoin=this.strokeLineJoin,t.miterLimit=this.strokeMiterLimit,t.strokeStyle=this.stroke.toLive?this.stroke.toLive(t,this):this.stroke)},_setFillStyles:function(t){this.fill&&(t.fillStyle=this.fill.toLive?this.fill.toLive(t,this):this.fill)},_setLineDash:function(t,e,i){e&&(1&e.length&&e.push.apply(e,e),o?t.setLineDash(e):i&&i(t))},_renderControls:function(t,i){if(!(!this.active||i||this.group&&this.group!==this.canvas.getActiveGroup())){var r,n=this.getViewportTransform(),o=this.calcTransformMatrix();o=e.util.multiplyTransformMatrices(n,o),r=e.util.qrDecompose(o),t.save(),t.translate(r.translateX,r.translateY),t.lineWidth=1*this.borderScaleFactor,t.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,this.group&&this.group===this.canvas.getActiveGroup()?(t.rotate(s(r.angle)),this.drawBordersInGroup(t,r)):(t.rotate(s(this.angle)),this.drawBorders(t)),this.drawControls(t),t.restore()}},_setShadow:function(t){if(this.shadow){var i=this.canvas&&this.canvas.viewportTransform[0]||1,r=this.canvas&&this.canvas.viewportTransform[3]||1,n=this.getObjectScaling();this.canvas&&this.canvas._isRetinaScaling()&&(i*=e.devicePixelRatio,r*=e.devicePixelRatio),t.shadowColor=this.shadow.color,t.shadowBlur=this.shadow.blur*(i+r)*(n.scaleX+n.scaleY)/4,t.shadowOffsetX=this.shadow.offsetX*i*n.scaleX,t.shadowOffsetY=this.shadow.offsetY*r*n.scaleY}},_removeShadow:function(t){this.shadow&&(t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0)},_renderFill:function(t){if(this.fill){if(t.save(),this.fill.gradientTransform){var e=this.fill.gradientTransform;t.transform.apply(t,e)}this.fill.toLive&&t.translate(-this.width/2+this.fill.offsetX||0,-this.height/2+this.fill.offsetY||0),"evenodd"===this.fillRule?t.fill("evenodd"):t.fill(),t.restore()}},_renderStroke:function(t){if(this.stroke&&0!==this.strokeWidth){if(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(t),t.save(),this._setLineDash(t,this.strokeDashArray,this._renderDashedStroke),this.stroke.gradientTransform){var e=this.stroke.gradientTransform;t.transform.apply(t,e)}this.stroke.toLive&&t.translate(-this.width/2+this.stroke.offsetX||0,-this.height/2+this.stroke.offsetY||0),t.stroke(),t.restore()}},clone:function(t,i){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(i),t):new e.Object(this.toObject(i))},cloneAsImage:function(t,i){var r=this.toDataURL(i);return e.util.loadImage(r,function(i){t&&t(new e.Image(i))}),this},toDataURL:function(t){t||(t={});var i=e.util.createCanvasElement(),r=this.getBoundingRect();i.width=r.width,i.height=r.height,e.util.wrapElement(i,"div");var n=new e.StaticCanvas(i,{enableRetinaScaling:t.enableRetinaScaling});"jpg"===t.format&&(t.format="jpeg"),"jpeg"===t.format&&(n.backgroundColor="#fff");var s={active:this.get("active"),left:this.getLeft(),top:this.getTop()};this.set("active",!1),this.setPositionByOrigin(new e.Point(n.getWidth()/2,n.getHeight()/2),"center","center");var o=this.canvas;n.add(this);var a=n.toDataURL(t);return this.set(s).setCoords(),this.canvas=o,n.dispose(),n=null,a},isType:function(t){return this.type===t},complexity:function(){return 0},toJSON:function(t){return this.toObject(t)},setGradient:function(t,i){i||(i={});var r={colorStops:[]};r.type=i.type||(i.r1||i.r2?"radial":"linear"),r.coords={x1:i.x1,y1:i.y1,x2:i.x2,y2:i.y2},(i.r1||i.r2)&&(r.coords.r1=i.r1,r.coords.r2=i.r2),i.gradientTransform&&(r.gradientTransform=i.gradientTransform);for(var n in i.colorStops){var s=new e.Color(i.colorStops[n]);r.colorStops.push({offset:n,color:s.toRgb(),opacity:s.getAlpha()})}return this.set(t,e.Gradient.forObject(this,r))},setPatternFill:function(t){return this.set("fill",new e.Pattern(t))},setShadow:function(t){return this.set("shadow",t?new e.Shadow(t):null)},setColor:function(t){return this.set("fill",t),this},setAngle:function(t){var e=("center"!==this.originX||"center"!==this.originY)&&this.centeredRotation;return e&&this._setOriginToCenter(),this.set("angle",t),e&&this._resetOrigin(),this},centerH:function(){return this.canvas&&this.canvas.centerObjectH(this),this},viewportCenterH:function(){return this.canvas&&this.canvas.viewportCenterObjectH(this),this},centerV:function(){return this.canvas&&this.canvas.centerObjectV(this),this},viewportCenterV:function(){return this.canvas&&this.canvas.viewportCenterObjectV(this),this},center:function(){return this.canvas&&this.canvas.centerObject(this),this},viewportCenter:function(){return this.canvas&&this.canvas.viewportCenterObject(this),this},remove:function(){return this.canvas&&this.canvas.remove(this),this},getLocalPointer:function(t,i){i=i||this.canvas.getPointer(t);var r=new e.Point(i.x,i.y),n=this._getLeftTopCoords();return this.angle&&(r=e.util.rotatePoint(r,n,e.util.degreesToRadians(-this.angle))),{x:r.x-n.x,y:r.y-n.y}},_setupCompositeOperation:function(t){this.globalCompositeOperation&&(t.globalCompositeOperation=this.globalCompositeOperation)}}),e.util.createAccessors(e.Object),e.Object.prototype.rotate=e.Object.prototype.setAngle,i(e.Object.prototype,e.Observable),e.Object.NUM_FRACTION_DIGITS=2,e.Object.__uid=0)}("undefined"!=typeof exports?exports:this),function(){var t=fabric.util.degreesToRadians,e={left:-.5,center:0,right:.5},i={top:-.5,center:0,bottom:.5};fabric.util.object.extend(fabric.Object.prototype,{translateToGivenOrigin:function(t,r,n,s,o){var a,h,c,l=t.x,u=t.y;return"string"==typeof r?r=e[r]:r-=.5,"string"==typeof s?s=e[s]:s-=.5,a=s-r,"string"==typeof n?n=i[n]:n-=.5,"string"==typeof o?o=i[o]:o-=.5,h=o-n,(a||h)&&(c=this._getTransformedDimensions(),l=t.x+a*c.x,u=t.y+h*c.y),new fabric.Point(l,u)},translateToCenterPoint:function(e,i,r){var n=this.translateToGivenOrigin(e,i,r,"center","center");return this.angle?fabric.util.rotatePoint(n,e,t(this.angle)):n},translateToOriginPoint:function(e,i,r){var n=this.translateToGivenOrigin(e,"center","center",i,r);return this.angle?fabric.util.rotatePoint(n,e,t(this.angle)):n},getCenterPoint:function(){var t=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(t,this.originX,this.originY)},getPointByOrigin:function(t,e){var i=this.getCenterPoint();return this.translateToOriginPoint(i,t,e)},toLocalPoint:function(e,i,r){var n,s,o=this.getCenterPoint();return n="undefined"!=typeof i&&"undefined"!=typeof r?this.translateToGivenOrigin(o,"center","center",i,r):new fabric.Point(this.left,this.top),s=new fabric.Point(e.x,e.y),this.angle&&(s=fabric.util.rotatePoint(s,o,-t(this.angle))),s.subtractEquals(n)},setPositionByOrigin:function(t,e,i){var r=this.translateToCenterPoint(t,e,i),n=this.translateToOriginPoint(r,this.originX,this.originY);this.set("left",n.x),this.set("top",n.y)},adjustPosition:function(i){var r,n,s=t(this.angle),o=this.getWidth(),a=Math.cos(s)*o,h=Math.sin(s)*o;r="string"==typeof this.originX?e[this.originX]:this.originX-.5,n="string"==typeof i?e[i]:i-.5,this.left+=a*(n-r),this.top+=h*(n-r),this.setCoords(),this.originX=i},_setOriginToCenter:function(){this._originalOriginX=this.originX,this._originalOriginY=this.originY;var t=this.getCenterPoint();this.originX="center",this.originY="center",this.left=t.x,this.top=t.y},_resetOrigin:function(){var t=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX,this._originalOriginY);this.originX=this._originalOriginX,this.originY=this._originalOriginY,this.left=t.x,this.top=t.y,this._originalOriginX=null,this._originalOriginY=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),"left","top")}})}(),function(){function t(t){return[new fabric.Point(t.tl.x,t.tl.y),new fabric.Point(t.tr.x,t.tr.y),new fabric.Point(t.br.x,t.br.y),new fabric.Point(t.bl.x,t.bl.y)]}var e=fabric.util.degreesToRadians,i=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,intersectsWithRect:function(e,i){var r=t(this.oCoords),n=fabric.Intersection.intersectPolygonRectangle(r,e,i);return"Intersection"===n.status},intersectsWithObject:function(e){var i=fabric.Intersection.intersectPolygonPolygon(t(this.oCoords),t(e.oCoords));return"Intersection"===i.status||e.isContainedWithinObject(this)||this.isContainedWithinObject(e)},isContainedWithinObject:function(e){for(var i=t(this.oCoords),r=0;r<4;r++)if(!e.containsPoint(i[r]))return!1;return!0},isContainedWithinRect:function(t,e){var i=this.getBoundingRect();return i.left>=t.x&&i.left+i.width<=e.x&&i.top>=t.y&&i.top+i.height<=e.y},containsPoint:function(t){this.oCoords||this.setCoords();var e=this._getImageLines(this.oCoords),i=this._findCrossPoints(t,e);return 0!==i&&i%2===1},_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,o,a,h=0;for(var c in e)if(a=e[c],!(a.o.y=t.y&&a.d.y>=t.y||(a.o.x===a.d.x&&a.o.x>=t.x?o=a.o.x:(i=0,r=(a.d.y-a.o.y)/(a.d.x-a.o.x),n=t.y-i*t.x,s=a.o.y-r*a.o.x,o=-(n-s)/(i-r)),o>=t.x&&(h+=1),2!==h)))break;return h},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(){return this.oCoords||this.setCoords(),fabric.util.makeBoundingBoxFromPoints([this.oCoords.tl,this.oCoords.tr,this.oCoords.br,this.oCoords.bl])},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(t){return Math.abs(t)0?Math.atan(s/n):0,c=n/Math.cos(h)/2,l=Math.cos(h+t)*c,u=Math.sin(h+t)*c,f=fabric.util.transformPoint(this.getCenterPoint(),i),d=new fabric.Point(f.x-l,f.y-u),g=new fabric.Point(d.x+n*a,d.y+n*o),p=new fabric.Point(d.x-s*o,d.y+s*a),v=new fabric.Point(f.x+l,f.y+u),b=new fabric.Point((d.x+p.x)/2,(d.y+p.y)/2),m=new fabric.Point((g.x+d.x)/2,(g.y+d.y)/2),y=new fabric.Point((v.x+g.x)/2,(v.y+g.y)/2),_=new fabric.Point((v.x+p.x)/2,(v.y+p.y)/2),x=new fabric.Point(m.x+o*this.rotatingPointOffset,m.y-a*this.rotatingPointOffset);return this.oCoords={tl:d,tr:g,br:v,bl:p,ml:b,mt:m,mr:y,mb:_,mtr:x},this._setCornerCoords&&this._setCornerCoords(),this},_calcRotateMatrix:function(){if(this.angle){var t=e(this.angle),i=Math.cos(t),r=Math.sin(t);return[i,r,-r,i,0,0]}return[1,0,0,1,0,0]},calcTransformMatrix:function(){var t=this.getCenterPoint(),e=[1,0,0,1,t.x,t.y],r=this._calcRotateMatrix(),n=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0),s=this.group?this.group.calcTransformMatrix():[1,0,0,1,0,0]; +return s=i(s,e),s=i(s,r),s=i(s,n)},_calcDimensionsTransformMatrix:function(t,r,n){var s=[1,0,Math.tan(e(t)),1],o=[1,Math.tan(e(r)),0,1],a=this.scaleX*(n&&this.flipX?-1:1),h=this.scaleY*(n&&this.flipY?-1:1),c=[a,0,0,h],l=i(c,s,!0);return i(l,o,!0)}})}(),fabric.util.object.extend(fabric.Object.prototype,{sendToBack:function(){return this.group?fabric.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this),this},bringToFront:function(){return this.group?fabric.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this),this},sendBackwards:function(t){return this.group?fabric.StaticCanvas.prototype.sendBackwards.call(this.group,this,t):this.canvas.sendBackwards(this,t),this},bringForward:function(t){return this.group?fabric.StaticCanvas.prototype.bringForward.call(this.group,this,t):this.canvas.bringForward(this,t),this},moveTo:function(t){return this.group?fabric.StaticCanvas.prototype.moveTo.call(this.group,this,t):this.canvas.moveTo(this,t),this}}),function(){function t(t,e){if(e){if(e.toLive)return t+": url(#SVGID_"+e.id+"); ";var i=new fabric.Color(e),r=t+": "+i.toRgb()+"; ",n=i.getAlpha();return 1!==n&&(r+=t+"-opacity: "+n.toString()+"; "),r}return t+": none; "}fabric.util.object.extend(fabric.Object.prototype,{getSvgStyles:function(e){var i=this.fillRule,r=this.strokeWidth?this.strokeWidth:"0",n=this.strokeDashArray?this.strokeDashArray.join(" "):"none",s=this.strokeLineCap?this.strokeLineCap:"butt",o=this.strokeLineJoin?this.strokeLineJoin:"miter",a=this.strokeMiterLimit?this.strokeMiterLimit:"4",h="undefined"!=typeof this.opacity?this.opacity:"1",c=this.visible?"":" visibility: hidden;",l=e?"":this.getSvgFilter(),u=t("fill",this.fill),f=t("stroke",this.stroke);return[f,"stroke-width: ",r,"; ","stroke-dasharray: ",n,"; ","stroke-linecap: ",s,"; ","stroke-linejoin: ",o,"; ","stroke-miterlimit: ",a,"; ",u,"fill-rule: ",i,"; ","opacity: ",h,";",l,c].join("")},getSvgFilter:function(){return this.shadow?"filter: url(#SVGID_"+this.shadow.id+");":""},getSvgId:function(){return this.id?'id="'+this.id+'" ':""},getSvgTransform:function(){if(this.group&&"path-group"===this.group.type)return"";var t=fabric.util.toFixed,e=this.getAngle(),i=this.getSkewX()%360,r=this.getSkewY()%360,n=this.getCenterPoint(),s=fabric.Object.NUM_FRACTION_DIGITS,o="path-group"===this.type?"":"translate("+t(n.x,s)+" "+t(n.y,s)+")",a=0!==e?" rotate("+t(e,s)+")":"",h=1===this.scaleX&&1===this.scaleY?"":" scale("+t(this.scaleX,s)+" "+t(this.scaleY,s)+")",c=0!==i?" skewX("+t(i,s)+")":"",l=0!==r?" skewY("+t(r,s)+")":"",u="path-group"===this.type?this.width:0,f=this.flipX?" matrix(-1 0 0 1 "+u+" 0) ":"",d="path-group"===this.type?this.height:0,g=this.flipY?" matrix(1 0 0 -1 0 "+d+")":"";return[o,a,h,f,g,c,l].join("")},getSvgTransformMatrix:function(){return this.transformMatrix?" matrix("+this.transformMatrix.join(" ")+") ":""},_createBaseSVGMarkup:function(){var t=[];return this.fill&&this.fill.toLive&&t.push(this.fill.toSVG(this,!1)),this.stroke&&this.stroke.toLive&&t.push(this.stroke.toSVG(this,!1)),this.shadow&&t.push(this.shadow.toSVG(this)),t}})}(),function(){function t(t,e,r){var n={},s=!0;r.forEach(function(e){n[e]=t[e]}),i(t[e],n,s)}function e(t,i){if(t instanceof Array){if(t.length!==i.length)return!1;var r=i.concat().sort(),n=t.concat().sort();return!n.some(function(t,i){return!e(r[i],t)})}if(t instanceof Object){for(var s in t)if(!e(t[s],i[s]))return!1;return!0}return t===i}var i=fabric.util.object.extend;fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(){return!e(this.originalState,this)},saveState:function(e){return t(this,"originalState",this.stateProperties),e&&e.stateProperties&&t(this,"originalState",e.stateProperties),this},setupState:function(t){return this.originalState={},this.saveState(t),this}})}(),function(){var t=fabric.util.degreesToRadians,e=function(){return"undefined"!=typeof G_vmlCanvasManager};fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(t){if(!this.hasControls||!this.active)return!1;var e,i,r=t.x,n=t.y;this.__corner=0;for(var s in this.oCoords)if(this.isControlVisible(s)&&("mtr"!==s||this.hasRotatingPoint)&&(!this.get("lockUniScaling")||"mt"!==s&&"mr"!==s&&"mb"!==s&&"ml"!==s)&&(i=this._getImageLines(this.oCoords[s].corner),e=this._findCrossPoints({x:r,y:n},i),0!==e&&e%2===1))return this.__corner=s,s;return!1},_setCornerCoords:function(){var e,i,r=this.oCoords,n=t(45-this.angle),s=.707106*this.cornerSize,o=s*Math.cos(n),a=s*Math.sin(n);for(var h in r)e=r[h].x,i=r[h].y,r[h].corner={tl:{x:e-a,y:i-o},tr:{x:e+o,y:i-a},bl:{x:e-o,y:i+a},br:{x:e+a,y:i+o}}},_getNonTransformedDimensions:function(){var t=this.strokeWidth,e=this.width,i=this.height,r=!0,n=!0;return"line"===this.type&&"butt"===this.strokeLineCap&&(n=e,r=i),n&&(i+=i<0?-t:t),r&&(e+=e<0?-t:t),{x:e,y:i}},_getTransformedDimensions:function(t,e){"undefined"==typeof t&&(t=this.skewX),"undefined"==typeof e&&(e=this.skewY);var i,r,n=this._getNonTransformedDimensions(),s=n.x/2,o=n.y/2,a=[{x:-s,y:-o},{x:s,y:-o},{x:-s,y:o},{x:s,y:o}],h=this._calcDimensionsTransformMatrix(t,e,!1);for(i=0;i\n'),t?t(e.join("")):e.join("")},complexity:function(){return 1}}),i.Line.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),i.Line.fromElement=function(t,e){var n=i.parseAttributes(t,i.Line.ATTRIBUTE_NAMES),s=[n.x1||0,n.y1||0,n.x2||0,n.y2||0];return new i.Line(s,r(n,e))},void(i.Line.fromObject=function(t,e){var r=[t.x1,t.y1,t.x2,t.y2],n=new i.Line(r,t);return e&&e(n),n}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";function e(t){return"radius"in t&&t.radius>=0}var i=t.fabric||(t.fabric={}),r=Math.PI,n=i.util.object.extend;return i.Circle?void i.warn("fabric.Circle is already defined."):(i.Circle=i.util.createClass(i.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*r,initialize:function(t){t=t||{},this.callSuper("initialize",t),this.set("radius",t.radius||0),this.startAngle=t.startAngle||this.startAngle,this.endAngle=t.endAngle||this.endAngle},_set:function(t,e){return this.callSuper("_set",t,e),"radius"===t&&this.setRadius(e),this},toObject:function(t){return n(this.callSuper("toObject",t),{radius:this.get("radius"),startAngle:this.startAngle,endAngle:this.endAngle})},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=0,n=0,s=(this.endAngle-this.startAngle)%(2*r);if(0===s)this.group&&"path-group"===this.group.type&&(i=this.left+this.radius,n=this.top+this.radius),e.push("\n');else{var o=Math.cos(this.startAngle)*this.radius,a=Math.sin(this.startAngle)*this.radius,h=Math.cos(this.endAngle)*this.radius,c=Math.sin(this.endAngle)*this.radius,l=s>r?"1":"0";e.push('\n')}return t?t(e.join("")):e.join("")},_render:function(t,e){t.beginPath(),t.arc(e?this.left+this.radius:0,e?this.top+this.radius:0,this.radius,this.startAngle,this.endAngle,!1),this._renderFill(t),this._renderStroke(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)},complexity:function(){return 1}}),i.Circle.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),i.Circle.fromElement=function(t,r){r||(r={});var s=i.parseAttributes(t,i.Circle.ATTRIBUTE_NAMES);if(!e(s))throw new Error("value of `r` attribute is required and can not be negative");s.left=s.left||0,s.top=s.top||0;var o=new i.Circle(n(s,r));return o.left-=o.radius,o.top-=o.radius,o},void(i.Circle.fromObject=function(t,e){var r=new i.Circle(t);return e&&e(r),r}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={});return e.Triangle?void e.warn("fabric.Triangle is already defined"):(e.Triangle=e.util.createClass(e.Object,{type:"triangle",initialize:function(t){t=t||{},this.callSuper("initialize",t),this.set("width",t.width||100).set("height",t.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._renderFill(t),this._renderStroke(t)},_renderDashedStroke:function(t){var i=this.width/2,r=this.height/2;t.beginPath(),e.util.drawDashedLine(t,-i,r,0,-r,this.strokeDashArray),e.util.drawDashedLine(t,0,-r,i,r,this.strokeDashArray),e.util.drawDashedLine(t,i,r,-i,r,this.strokeDashArray),t.closePath()},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=this.width/2,r=this.height/2,n=[-i+" "+r,"0 "+-r,i+" "+r].join(",");return e.push("'),t?t(e.join("")):e.join("")},complexity:function(){return 1}}),void(e.Triangle.fromObject=function(t,i){var r=new e.Triangle(t);return i&&i(r),r}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=2*Math.PI,r=e.util.object.extend;return e.Ellipse?void e.warn("fabric.Ellipse is already defined."):(e.Ellipse=e.util.createClass(e.Object,{type:"ellipse",rx:0,ry:0,initialize:function(t){t=t||{},this.callSuper("initialize",t),this.set("rx",t.rx||0),this.set("ry",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 r(this.callSuper("toObject",t),{rx:this.get("rx"),ry:this.get("ry")})},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=0,r=0;return this.group&&"path-group"===this.group.type&&(i=this.left+this.rx,r=this.top+this.ry),e.push("\n'),t?t(e.join("")):e.join("")},_render:function(t,e){t.beginPath(),t.save(),t.transform(1,0,0,this.ry/this.rx,0,0),t.arc(e?this.left+this.rx:0,e?(this.top+this.ry)*this.rx/this.ry:0,this.rx,0,i,!1),t.restore(),this._renderFill(t),this._renderStroke(t)},complexity:function(){return 1}}),e.Ellipse.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("cx cy rx ry".split(" ")),e.Ellipse.fromElement=function(t,i){i||(i={});var n=e.parseAttributes(t,e.Ellipse.ATTRIBUTE_NAMES);n.left=n.left||0,n.top=n.top||0;var s=new e.Ellipse(r(n,i));return s.top-=s.ry,s.left-=s.rx,s},void(e.Ellipse.fromObject=function(t,i){var r=new e.Ellipse(t);return i&&i(r),r}))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;if(e.Rect)return void e.warn("fabric.Rect is already defined");var r=e.Object.prototype.stateProperties.concat();r.push("rx","ry","x","y"),e.Rect=e.util.createClass(e.Object,{stateProperties:r,type:"rect",rx:0,ry:0,strokeDashArray:null,initialize:function(t){t=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,e){if(1===this.width&&1===this.height)return void t.fillRect(-.5,-.5,1,1);var i=this.rx?Math.min(this.rx,this.width/2):0,r=this.ry?Math.min(this.ry,this.height/2):0,n=this.width,s=this.height,o=e?this.left:-this.width/2,a=e?this.top:-this.height/2,h=0!==i||0!==r,c=.4477152502;t.beginPath(),t.moveTo(o+i,a),t.lineTo(o+n-i,a),h&&t.bezierCurveTo(o+n-c*i,a,o+n,a+c*r,o+n,a+r),t.lineTo(o+n,a+s-r),h&&t.bezierCurveTo(o+n,a+s-c*r,o+n-c*i,a+s,o+n-i,a+s),t.lineTo(o+i,a+s),h&&t.bezierCurveTo(o+c*i,a+s,o,a+s-c*r,o,a+s-r),t.lineTo(o,a+r),h&&t.bezierCurveTo(o,a+c*r,o+c*i,a,o+i,a),t.closePath(),this._renderFill(t),this._renderStroke(t)},_renderDashedStroke:function(t){var i=-this.width/2,r=-this.height/2,n=this.width,s=this.height;t.beginPath(),e.util.drawDashedLine(t,i,r,i+n,r,this.strokeDashArray),e.util.drawDashedLine(t,i+n,r,i+n,r+s,this.strokeDashArray),e.util.drawDashedLine(t,i+n,r+s,i,r+s,this.strokeDashArray),e.util.drawDashedLine(t,i,r+s,i,r,this.strokeDashArray),t.closePath()},toObject:function(t){var e=i(this.callSuper("toObject",t),{rx:this.get("rx")||0,ry:this.get("ry")||0});return this.includeDefaultValues||this._removeDefaultValues(e),e},toSVG:function(t){var e=this._createBaseSVGMarkup(),i=this.left,r=this.top;return this.group&&"path-group"===this.group.type||(i=-this.width/2,r=-this.height/2),e.push("\n'),t?t(e.join("")):e.join("")},complexity:function(){return 1}}),e.Rect.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),e.Rect.fromElement=function(t,r){if(!t)return null;r=r||{};var n=e.parseAttributes(t,e.Rect.ATTRIBUTE_NAMES);n.left=n.left||0,n.top=n.top||0;var s=new e.Rect(i(r?e.util.object.clone(r):{},n));return s.visible=s.visible&&s.width>0&&s.height>0,s},e.Rect.fromObject=function(t,i){var r=new e.Rect(t);return i&&i(r),r}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={});return e.Polyline?void e.warn("fabric.Polyline is already defined"):(e.Polyline=e.util.createClass(e.Object,{type:"polyline",points:null,minX:0,minY:0,initialize:function(t,i){return e.Polygon.prototype.initialize.call(this,t,i)},_calcDimensions:function(){return e.Polygon.prototype._calcDimensions.call(this)},toObject:function(t){return e.Polygon.prototype.toObject.call(this,t)},toSVG:function(t){return e.Polygon.prototype.toSVG.call(this,t)},_render:function(t,i){e.Polygon.prototype.commonRender.call(this,t,i)&&(this._renderFill(t),this._renderStroke(t))},_renderDashedStroke:function(t){var i,r;t.beginPath();for(var n=0,s=this.points.length;n\n'),t?t(r.join("")):r.join("")},_render:function(t,e){this.commonRender(t,e)&&(this._renderFill(t),(this.stroke||this.strokeDashArray)&&(t.closePath(),this._renderStroke(t)))},commonRender:function(t,e){var i,r=this.points.length;if(!r||isNaN(this.points[r-1].y))return!1;e||t.translate(-this.pathOffset.x,-this.pathOffset.y),t.beginPath(),t.moveTo(this.points[0].x,this.points[0].y);for(var n=0;n"},toObject:function(t){var e=n(this.callSuper("toObject",t),{path:this.path.map(function(t){return t.slice()}),pathOffset:this.pathOffset});return this.sourcePath&&(e.sourcePath=this.sourcePath),this.transformMatrix&&(e.transformMatrix=this.transformMatrix),e},toDatalessObject:function(t){var e=this.toObject(t);return this.sourcePath&&(e.path=this.sourcePath),delete e.sourcePath,e},toSVG:function(t){for(var e=[],i=this._createBaseSVGMarkup(),r="",n=0,s=this.path.length;n\n"),t?t(i.join("")):i.join("")},complexity:function(){return this.path.length},_parsePath:function(){for(var t,e,i,r,n,s=[],o=[],c=/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/gi,l=0,u=this.path.length;lp)for(var b=1,m=n.length;b\n");for(var s=0,o=e.length;s\n"),t?t(n.join("")):n.join("")},toString:function(){return"#"},isSameColor:function(){var t=this.getObjects()[0].get("fill")||"";return"string"==typeof t&&(t=t.toLowerCase(),this.getObjects().every(function(e){var i=e.get("fill")||"";return"string"==typeof i&&i.toLowerCase()===t}))},complexity:function(){return this.paths.reduce(function(t,e){return t+(e&&e.complexity?e.complexity():0)},0)},getObjects:function(){return this.paths}}),e.PathGroup.fromObject=function(t,i){"string"==typeof t.paths?e.loadSVGFromURL(t.paths,function(r){var n=t.paths;delete t.paths;var s=e.util.groupSVGElements(r,t,n);i(s)}):e.util.enlivenObjects(t.paths,function(r){delete t.paths,i(new e.PathGroup(r,t))})},void(e.PathGroup.async=!0))}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend,r=e.util.array.min,n=e.util.array.max,s=e.util.array.invoke;if(!e.Group){var o={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};e.Group=e.util.createClass(e.Object,e.Collection,{type:"group",strokeWidth:0,subTargetCheck:!1,initialize:function(t,e,i){e=e||{},this._objects=[],i&&this.callSuper("initialize",e),this._objects=t||[];for(var r=this._objects.length;r--;)this._objects[r].group=this;this.originalState={},e.originX&&(this.originX=e.originX),e.originY&&(this.originY=e.originY),i?this._updateObjectsCoords(!0):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",e)),this.setCoords(),this.saveCoords()},_updateObjectsCoords:function(t){for(var e=this._objects.length;e--;)this._updateObjectCoords(this._objects[e],t)},_updateObjectCoords:function(t,e){if(t.__origHasControls=t.hasControls,t.hasControls=!1,!e){var i=t.getLeft(),r=t.getTop(),n=this.getCenterPoint();t.set({originalLeft:i,originalTop:r,left:i-n.x,top:r-n.y}),t.setCoords()}},toString:function(){return"#"},addWithUpdate:function(t){return this._restoreObjectsState(),e.util.resetObjectTransform(this),t&&(this._objects.push(t),t.group=this,t._set("canvas",this.canvas)),this.forEachObject(this._setObjectActive,this),this._calcBounds(),this._updateObjectsCoords(),this},_setObjectActive:function(t){t.set("active",!0),t.group=this},removeWithUpdate:function(t){return this._restoreObjectsState(),e.util.resetObjectTransform(this),this.forEachObject(this._setObjectActive,this),this.remove(t),this._calcBounds(),this._updateObjectsCoords(),this},_onObjectAdded:function(t){t.group=this,t._set("canvas",this.canvas)},_onObjectRemoved:function(t){delete t.group,t.set("active",!1)},delegatedProperties:{fill:!0,stroke:!0,strokeWidth:!0,fontFamily:!0,fontWeight:!0,fontSize:!0,fontStyle:!0,lineHeight:!0,textDecoration:!0,textAlign:!0,backgroundColor:!0},_set:function(t,e){var i=this._objects.length;if(this.delegatedProperties[t]||"canvas"===t)for(;i--;)this._objects[i].set(t,e);else for(;i--;)this._objects[i].setOnGroup(t,e);this.callSuper("_set",t,e)},toObject:function(t){return i(this.callSuper("toObject",t),{objects:s(this._objects,"toObject",t)})},render:function(t){if(this.visible){t.save(),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.transform(t),this._setShadow(t),this.clipTo&&e.util.clipContext(this,t),this._transformDone=!0;for(var i=0,r=this._objects.length;i\n');for(var i=0,r=this._objects.length;i\n"),t?t(e.join("")):e.join("")},get:function(t){if(t in o){if(this[t])return this[t];for(var e=0,i=this._objects.length;e\n',"\n"),this.stroke||this.strokeDashArray){var o=this.fill;this.fill=null,e.push("\n'),this.fill=o}return e.push("\n"),t?t(e.join("")):e.join("")},getSrc:function(t){var e=t?this._element:this._originalElement;return e?fabric.isLikelyNode?e._src:e.src:this.src||""},setSrc:function(t,e,i){fabric.util.loadImage(t,function(t){return this.setElement(t,e,i)},this,i&&i.crossOrigin)},toString:function(){return'#'},applyFilters:function(t,e,i,r){if(e=e||this.filters,i=i||this._originalElement){var n,s,o=fabric.util.createImage(),a=this.canvas?this.canvas.getRetinaScaling():fabric.devicePixelRatio,h=this.minimumScaleTrigger/a,c=this;if(0===e.length)return this._element=i,t&&t(this),i;var l=fabric.util.createCanvasElement();return l.width=i.width,l.height=i.height,l.getContext("2d").drawImage(i,0,0,i.width,i.height),e.forEach(function(t){t&&(r?(n=c.scaleX0?90*Math.round((t-1)/90):90*Math.round(t/90)},straighten:function(){return this.setAngle(this._getAngleValueForStraighten()),this},fxStraighten:function(t){t=t||{};var e=function(){},i=t.onComplete||e,r=t.onChange||e,n=this;return fabric.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(t){n.setAngle(t),r()},onComplete:function(){n.setCoords(),i()},onStart:function(){n.set("active",!1)}}),this}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(t){return t.straighten(),this.renderAll(),this},fxStraightenObject:function(t){return t.fxStraighten({onChange:this.renderAll.bind(this)}),this}}),fabric.Image.filters=fabric.Image.filters||{},fabric.Image.filters.BaseFilter=fabric.util.createClass({type:"BaseFilter",initialize:function(t){t&&this.setOptions(t)},setOptions:function(t){for(var e in t)this[e]=t[e]},toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}}),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend,r=e.Image.filters,n=e.util.createClass;r.Brightness=n(r.BaseFilter,{type:"Brightness",initialize:function(t){t=t||{},this.brightness=t.brightness||0},applyTo:function(t){for(var e=t.getContext("2d"),i=e.getImageData(0,0,t.width,t.height),r=i.data,n=this.brightness,s=0,o=r.length;sb||o<0||o>v||(h=4*(a*v+o),c=l[C*d+w],e+=p[h]*c,i+=p[h+1]*c,r+=p[h+2]*c,n+=p[h+3]*c);y[s]=e,y[s+1]=i,y[s+2]=r,y[s+3]=n+_*(255-n)}u.putImageData(m,0,0)},toObject:function(){return i(this.callSuper("toObject"),{opaque:this.opaque,matrix:this.matrix})}}),e.Image.filters.Convolute.fromObject=function(t){return new e.Image.filters.Convolute(t)}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend,r=e.Image.filters,n=e.util.createClass;r.GradientTransparency=n(r.BaseFilter,{type:"GradientTransparency",initialize:function(t){t=t||{},this.threshold=t.threshold||100},applyTo:function(t){for(var e=t.getContext("2d"),i=e.getImageData(0,0,t.width,t.height),r=i.data,n=this.threshold,s=r.length,o=0,a=r.length;o-1?t.channel:0},applyTo:function(t){if(this.mask){var i,r=t.getContext("2d"),n=r.getImageData(0,0,t.width,t.height),s=n.data,o=this.mask.getElement(),a=e.util.createCanvasElement(),h=this.channel,c=n.width*n.height*4;a.width=t.width,a.height=t.height,a.getContext("2d").drawImage(o,0,0,t.width,t.height);var l=a.getContext("2d").getImageData(0,0,t.width,t.height),u=l.data;for(i=0;ic&&i>c&&r>c&&l(e-i)i&&(l=2,f=-1),a>n&&(u=2,d=-1),h=c.getImageData(0,0,i,n),t.width=o(s,i),t.height=o(a,n),c.putImageData(h,0,0);!g||!p;)i=v,n=b,s*ft)return 0;if(e*=Math.PI,s(e)<1e-16)return 1;var i=e/t;return h(e)*h(i)/e/i}}function f(t){var h,c,u,d,g,j,A,M,P,D,E;for(T.x=(t+.5)*y,k.x=r(T.x),h=0;h=e)){D=r(1e3*s(c-T.x)),O[D]||(O[D]={});for(var L=k.y-w;L<=k.y+w;L++)L<0||L>=o||(E=r(1e3*s(L-T.y)),O[D][E]||(O[D][E]=m(n(i(D*x,2)+i(E*S,2))/1e3)),u=O[D][E],u>0&&(d=4*(L*e+c),g+=u,j+=u*v[d],A+=u*v[d+1],M+=u*v[d+2],P+=u*v[d+3]))}d=4*(h*a+t),b[d]=j/g,b[d+1]=A/g,b[d+2]=M/g,b[d+3]=P/g}return++t1&&I<-1||(x=2*I*I*I-3*I*I+1,x>0&&(L=4*(E+A*e),k+=x*p[L+3],C+=x,p[L+3]<255&&(x=x*p[L+3]/250),w+=x*p[L],O+=x*p[L+1],T+=x*p[L+2],S+=x))}b[_]=w/S,b[_+1]=O/S,b[_+2]=T/S,b[_+3]=k/C}return v},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}}),e.Image.filters.Resize.fromObject=function(t){return new e.Image.filters.Resize(t)}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend,r=e.Image.filters,n=e.util.createClass;r.ColorMatrix=n(r.BaseFilter,{type:"ColorMatrix",initialize:function(t){t||(t={}),this.matrix=t.matrix||[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0]},applyTo:function(t){var e,i,r,n,s,o=t.getContext("2d"),a=o.getImageData(0,0,t.width,t.height),h=a.data,c=h.length,l=this.matrix;for(e=0;e'},_render:function(t){this.clipTo&&e.util.clipContext(this,t),this._setOpacity(t),this._setShadow(t),this._setupCompositeOperation(t),this._renderTextBackground(t),this._setStrokeStyles(t),this._setFillStyles(t),this._renderText(t),this._renderTextDecoration(t),this.clipTo&&t.restore()},_renderText:function(t){this._renderTextFill(t),this._renderTextStroke(t)},_setTextStyles:function(t){t.textBaseline="alphabetic",t.font=this._getFontDeclaration()},_getTextHeight:function(){return this._getHeightOfSingleLine()+(this._textLines.length-1)*this._getHeightOfLine()},_getTextWidth:function(t){for(var e=this._getLineWidth(t,0),i=1,r=this._textLines.length;ie&&(e=n)}return e},_getNonTransformedDimensions:function(){return{x:this.width,y:this.height}},_renderChars:function(t,e,i,r,n){var s,o,a=t.slice(0,-4);if(this[a].toLive){var h=-this.width/2+this[a].offsetX||0,c=-this.height/2+this[a].offsetY||0;e.save(),e.translate(h,c),r-=h,n-=c}if(0!==this.charSpacing){var l=this._getWidthOfCharSpacing();i=i.split("");for(var u=0,f=i.length;u0?o:0}else e[t](i,r,n);this[a].toLive&&e.restore()},_renderTextLine:function(t,e,i,r,n,s){n-=this.fontSize*this._fontSizeFraction;var o=this._getLineWidth(e,s);if("justify"!==this.textAlign||this.width0?u/f:0,g=0,p=0,v=h.length;p0?n:0},_getLeftOffset:function(){return-this.width/2},_getTopOffset:function(){return-this.height/2},isEmptyStyles:function(){return!0},_renderTextCommon:function(t,e){for(var i=0,r=this._getLeftOffset(),n=this._getTopOffset(),s=0,o=this._textLines.length;s0&&(r=this._getLineLeftOffset(i),t.fillRect(this._getLeftOffset()+r,this._getTopOffset()+n,i,e/this.lineHeight)),n+=e;this._removeShadow(t)}},_getLineLeftOffset:function(t){return"center"===this.textAlign?(this.width-t)/2:"right"===this.textAlign?this.width-t:0},_clearCache:function(){this.__lineWidths=[],this.__lineHeights=[]},_shouldClearCache:function(){var t=!1;if(this._forceClearCache)return this._forceClearCache=!1,!0;for(var e in this._dimensionAffectingProps)this["__"+e]!==this[e]&&(this["__"+e]=this[e],t=!0);return t},_getLineWidth:function(t,e){if(this.__lineWidths[e])return this.__lineWidths[e]===-1?this.width:this.__lineWidths[e];var i,r,n=this._textLines[e];return i=""===n?0:this._measureLine(t,e),this.__lineWidths[e]=i,i&&"justify"===this.textAlign&&(r=n.split(/\s+/),r.length>1&&(this.__lineWidths[e]=-1)),i},_getWidthOfCharSpacing:function(){return 0!==this.charSpacing?this.fontSize*this.charSpacing/1e3:0},_measureLine:function(t,e){var i,r,n=this._textLines[e],s=t.measureText(n).width,o=0;return 0!==this.charSpacing&&(i=n.split("").length,o=(i-1)*this._getWidthOfCharSpacing()),r=s+o,r>0?r:0},_renderTextDecoration:function(t){function e(e){var n,s,o,a,h,c,l,u=0;for(n=0,s=r._textLines.length;n-1&&n.push(.85),this.textDecoration.indexOf("line-through")>-1&&n.push(.43),this.textDecoration.indexOf("overline")>-1&&n.push(-.12),n.length>0&&e(n)}},_getFontDeclaration:function(){return[e.isLikelyNode?this.fontWeight:this.fontStyle,e.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+"px",e.isLikelyNode?'"'+this.fontFamily+'"':this.fontFamily].join(" ")},render:function(t,e){this.visible&&(t.save(),this._setTextStyles(t),this._shouldClearCache()&&this._initDimensions(t),this.drawSelectionBackground(t),e||this.transform(t),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.group&&"path-group"===this.group.type&&t.translate(this.left,this.top),this._render(t),t.restore())},_splitTextIntoLines:function(){return this.text.split(this._reNewline)},toObject:function(t){var e=i(this.callSuper("toObject",t),{text:this.text,fontSize:this.fontSize,fontWeight:this.fontWeight,fontFamily:this.fontFamily,fontStyle:this.fontStyle,lineHeight:this.lineHeight,textDecoration:this.textDecoration,textAlign:this.textAlign,textBackgroundColor:this.textBackgroundColor,charSpacing:this.charSpacing});return this.includeDefaultValues||this._removeDefaultValues(e),e},toSVG:function(t){this.ctx||(this.ctx=e.util.createCanvasElement().getContext("2d"));var i=this._createBaseSVGMarkup(),r=this._getSVGLeftTopOffsets(this.ctx),n=this._getSVGTextAndBg(r.textTop,r.textLeft);return this._wrapSVGTextAndBg(i,n),t?t(i.join("")):i.join("")},_getSVGLeftTopOffsets:function(t){var e=this._getHeightOfLine(t,0),i=-this.width/2,r=0;return{textLeft:i+(this.group&&"path-group"===this.group.type?this.left:0),textTop:r+(this.group&&"path-group"===this.group.type?-this.top:0),lineTop:e}},_wrapSVGTextAndBg:function(t,e){var i=!0,r=this.getSvgFilter(),n=""===r?"":' style="'+r+'"';t.push("\t\n",e.textBgRects.join(""),"\t\t\n',e.textSpans.join(""),"\t\t\n","\t\n")},_getSVGTextAndBg:function(t,e){var i=[],r=[],n=0;this._setSVGBg(r);for(var s=0,o=this._textLines.length;s",e.util.string.escapeXml(this._textLines[t]),"\n")},_setSVGTextLineJustifed:function(t,i,r,o){var a=e.util.createCanvasElement().getContext("2d");this._setTextStyles(a);var h,c,l=this._textLines[t],u=l.split(/\s+/),f=this._getWidthOfWords(a,u.join("")),d=this.width-f,g=u.length-1,p=g>0?d/g:0,v=this._getFillAttributes(this.fill);for(o+=this._getLineLeftOffset(this._getLineWidth(a,t)),t=0,c=u.length;t",e.util.string.escapeXml(h),"\n"),o+=this._getWidthOfWords(a,h)+p},_setSVGTextLineBg:function(t,e,i,r,o){t.push("\t\t\n')},_setSVGBg:function(t){this.backgroundColor&&t.push("\t\t\n')},_getFillAttributes:function(t){var i=t&&"string"==typeof t?new e.Color(t):"";return i&&i.getSource()&&1!==i.getAlpha()?'opacity="'+i.getAlpha()+'" fill="'+i.setAlpha(1).toRgb()+'"':'fill="'+t+'"'},_set:function(t,e){this.callSuper("_set",t,e),t in this._dimensionAffectingProps&&(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),e.Text.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("x y dx dy font-family font-style font-weight font-size text-decoration text-anchor".split(" ")),e.Text.DEFAULT_SVG_FONT_SIZE=16,e.Text.fromElement=function(t,i){if(!t)return null;var r=e.parseAttributes(t,e.Text.ATTRIBUTE_NAMES);i=e.util.object.extend(i?e.util.object.clone(i):{},r),i.top=i.top||0,i.left=i.left||0,"dx"in r&&(i.left+=r.dx),"dy"in r&&(i.top+=r.dy),"fontSize"in i||(i.fontSize=e.Text.DEFAULT_SVG_FONT_SIZE),i.originX||(i.originX="left");var n="";"textContent"in t?n=t.textContent:"firstChild"in t&&null!==t.firstChild&&"data"in t.firstChild&&null!==t.firstChild.data&&(n=t.firstChild.data),n=n.replace(/^\s+|\s+$|\n+/g,"").replace(/\s+/g," ");var s=new e.Text(n,i),o=s.getHeight()/s.height,a=(s.height+s.strokeWidth)*s.lineHeight-s.height,h=a*o,c=s.getHeight()+h,l=0;return"left"===s.originX&&(l=s.getWidth()/2),"right"===s.originX&&(l=-s.getWidth()/2),s.set({left:s.getLeft()+l,top:s.getTop()-c/2+s.fontSize*(.18+s._fontSizeFraction)/s.lineHeight}),s},e.Text.fromObject=function(t,i){var n=new e.Text(t.text,r(t));return i&&i(n),n},e.util.createAccessors(e.Text)}("undefined"!=typeof exports?exports:this),function(){var t=fabric.util.object.clone;fabric.IText=fabric.util.createClass(fabric.Text,fabric.Observable,{type:"i-text",selectionStart:0,selectionEnd:0,selectionColor:"rgba(17,119,255,0.3)",isEditing:!1,editable:!0,editingBorderColor:"rgba(102,153,255,0.25)",cursorWidth:2,cursorColor:"#333",cursorDelay:1e3,cursorDuration:600,styles:null,caching:!0,_reSpace:/\s|\n/,_currentCursorOpacity:0,_selectionDirection:null,_abortCursorAnimation:!1,__widthOfSpace:[],initialize:function(t,e){this.styles=e?e.styles||{}:{},this.callSuper("initialize",t,e),this.initBehavior()},_clearCache:function(){this.callSuper("_clearCache"),this.__widthOfSpace=[]},isEmptyStyles:function(){if(!this.styles)return!0;var t=this.styles;for(var e in t)for(var i in t[e])for(var r in t[e][i])return!1;return!0},setSelectionStart:function(t){t=Math.max(t,0),this._updateAndFire("selectionStart",t)},setSelectionEnd:function(t){t=Math.min(t,this.text.length),this._updateAndFire("selectionEnd",t)},_updateAndFire:function(t,e){this[t]!==e&&(this._fireSelectionChanged(),this[t]=e),this._updateTextarea()},_fireSelectionChanged:function(){this.fire("selection:changed"),this.canvas&&this.canvas.fire("text:selection:changed",{target:this})},getSelectionStyles:function(t,e){if(2===arguments.length){for(var i=[],r=t;r0?a:0,lineLeft:r},this.cursorOffsetCache=i,this.cursorOffsetCache},renderCursor:function(t,e){var i=this.get2DCursorLocation(),r=i.lineIndex,n=i.charIndex,s=this.getCurrentCharFontSize(r,n),o=0===r&&0===n?this._getLineLeftOffset(this._getLineWidth(e,r)):t.leftOffset,a=this.scaleX*this.canvas.getZoom(),h=this.cursorWidth/a;e.fillStyle=this.getCurrentCharColor(r,n),e.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity,e.fillRect(t.left+o-h/2,t.top+t.topOffset,h,s)},renderSelection:function(t,e,i){i.fillStyle=this.selectionColor;for(var r=this.get2DCursorLocation(this.selectionStart),n=this.get2DCursorLocation(this.selectionEnd),s=r.lineIndex,o=n.lineIndex,a=s;a<=o;a++){var h=this._getLineLeftOffset(this._getLineWidth(i,a))||0,c=this._getHeightOfLine(this.ctx,a),l=0,u=0,f=this._textLines[a];if(a===s){for(var d=0,g=f.length;d=r.charIndex&&(a!==o||ds&&a1)&&(c/=this.lineHeight),i.fillRect(e.left+h,e.top+e.topOffset,u>0?u:0,c),e.topOffset+=l}},_renderChars:function(t,e,i,r,n,s,o){if(this.isEmptyStyles())return this._renderCharsFast(t,e,i,r,n);o=o||0;var a,h,c=this._getHeightOfLine(e,s),l="";e.save(),n-=c/this.lineHeight*this._fontSizeFraction;for(var u=o,f=i.length+o;u<=f;u++)a=a||this.getCurrentCharStyle(s,u),h=this.getCurrentCharStyle(s,u+1),(this._hasStyleChanged(a,h)||u===f)&&(this._renderChar(t,e,s,u-1,l,r,n,c),l="",a=h),l+=i[u-o];e.restore()},_renderCharsFast:function(t,e,i,r,n){"fillText"===t&&this.fill&&this.callSuper("_renderChars",t,e,i,r,n),"strokeText"===t&&(this.stroke&&this.strokeWidth>0||this.skipFillStrokeCheck)&&this.callSuper("_renderChars",t,e,i,r,n)},_renderChar:function(t,e,i,r,n,s,o,a){var h,c,l,u,f,d,g,p,v,b=this._getStyleDeclaration(i,r);if(b?(c=this._getHeightOfChar(e,n,i,r),u=b.stroke,l=b.fill,d=b.textDecoration):c=this.fontSize,u=(u||this.stroke)&&"strokeText"===t,l=(l||this.fill)&&"fillText"===t,b&&e.save(),h=this._applyCharStylesGetWidth(e,n,i,r,b||null),d=d||this.textDecoration,b&&b.textBackgroundColor&&this._removeShadow(e),0!==this.charSpacing){p=this._getWidthOfCharSpacing(),g=n.split(""),h=0;for(var m,y=0,_=g.length;y<_;y++)m=g[y],l&&e.fillText(m,s+h,o),u&&e.strokeText(m,s+h,o),v=e.measureText(m).width+p,h+=v>0?v:0}else l&&e.fillText(n,s,o),u&&e.strokeText(n,s,o);(d||""!==d)&&(f=this._fontSizeFraction*a/this.lineHeight,this._renderCharDecoration(e,d,s,o,f,h,c)),b&&e.restore(),e.translate(h,0)},_hasStyleChanged:function(t,e){return t.fill!==e.fill||t.fontSize!==e.fontSize||t.textBackgroundColor!==e.textBackgroundColor||t.textDecoration!==e.textDecoration||t.fontFamily!==e.fontFamily||t.fontWeight!==e.fontWeight||t.fontStyle!==e.fontStyle||t.stroke!==e.stroke||t.strokeWidth!==e.strokeWidth},_renderCharDecoration:function(t,e,i,r,n,s,o){if(e){var a,h,c=o/15,l={underline:r+o/10,"line-through":r-o*(this._fontSizeFraction+this._fontSizeMult-1)+c,overline:r-(this._fontSizeMult-this._fontSizeFraction)*o},u=["underline","line-through","overline"];for(a=0;a-1&&t.fillRect(i,l[h],s,c)}},_renderTextLine:function(t,e,i,r,n,s){this.isEmptyStyles()||(n+=this.fontSize*(this._fontSizeFraction+.03)),this.callSuper("_renderTextLine",t,e,i,r,n,s)},_renderTextDecoration:function(t){if(this.isEmptyStyles())return this.callSuper("_renderTextDecoration",t)},_renderTextLinesBackground:function(t){this.callSuper("_renderTextLinesBackground",t);for(var e,i,r,n,s,o,a=0,h=this._getLeftOffset(),c=this._getTopOffset(),l=0,u=this._textLines.length;l0?n:0},_getHeightOfChar:function(t,e,i){var r=this._getStyleDeclaration(e,i);return r&&r.fontSize?r.fontSize:this.fontSize},_getWidthOfCharsAt:function(t,e,i){var r,n,s=0;for(r=0;r0?i:0},_getWidthOfSpace:function(t,e){if(this.__widthOfSpace[e])return this.__widthOfSpace[e];var i=this._textLines[e],r=this._getWidthOfWords(t,i,e,0),n=this.width-r,s=i.length-i.replace(this._reSpacesAndTabs,"").length,o=Math.max(n/s,t.measureText(" ").width);return this.__widthOfSpace[e]=o,o},_getWidthOfWords:function(t,e,i,r){for(var n=0,s=0;sr&&(r=o)}return this.__lineHeights[e]=r*this.lineHeight*this._fontSizeMult,this.__lineHeights[e]},_getTextHeight:function(t){for(var e,i=0,r=0,n=this._textLines.length;r-1;)e++,i--;return t-e},findWordBoundaryRight:function(t){var e=0,i=t;if(this._reSpace.test(this.text.charAt(i)))for(;this._reSpace.test(this.text.charAt(i));)e++,i++;for(;/\S/.test(this.text.charAt(i))&&i-1;)e++,i--;return t-e},findLineBoundaryRight:function(t){for(var e=0,i=t;!/\n/.test(this.text.charAt(i))&&i0&&ithis.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=e):(this.selectionStart=e,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart===i&&this.selectionEnd===r||(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},_updateTextarea:function(){if(this.hiddenTextarea&&!this.inCompositionMode&&(this.cursorOffsetCache={},this.hiddenTextarea.value=this.text,this.hiddenTextarea.selectionStart=this.selectionStart,this.hiddenTextarea.selectionEnd=this.selectionEnd,this.selectionStart===this.selectionEnd)){var t=this._calcTextareaPosition();this.hiddenTextarea.style.left=t.left,this.hiddenTextarea.style.top=t.top,this.hiddenTextarea.style.fontSize=t.fontSize}},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var t=this.text.split(""),e=this._getCursorBoundaries(t,"cursor"),i=this.get2DCursorLocation(),r=i.lineIndex,n=i.charIndex,s=this.getCurrentCharFontSize(r,n),o=0===r&&0===n?this._getLineLeftOffset(this._getLineWidth(this.ctx,r)):e.leftOffset,a=this.calcTransformMatrix(),h={x:e.left+o,y:e.top+e.topOffset+s},c=this.canvas.upperCanvasEl,l=c.width-s,u=c.height-s;return h=fabric.util.transformPoint(h,a),h=fabric.util.transformPoint(h,this.canvas.viewportTransform),h.x<0&&(h.x=0),h.x>l&&(h.x=l),h.y<0&&(h.y=0),h.y>u&&(h.y=u),h.x+=this.canvas._offset.left,h.y+=this.canvas._offset.top,{left:h.x+"px",top:h.y+"px",fontSize:s}},_saveEditingProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,defaultCursor:this.canvas&&this.canvas.defaultCursor,moveCursor:this.canvas&&this.canvas.moveCursor}},_restoreEditingProps:function(){this._savedProps&&(this.hoverCursor=this._savedProps.overCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,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;return this.selected=!1,this.isEditing=!1,this.selectable=!0,this.selectionEnd=this.selectionStart,this.hiddenTextarea&&this.canvas&&this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea),this.hiddenTextarea=null,this.abortCursorAnimation(),this._restoreEditingProps(),this._currentCursorOpacity=0,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]},_removeCharsFromTo:function(t,e){for(;e!==t;)this._removeSingleCharAndStyle(t+1),e--;this.selectionStart=t,this.selectionEnd=t},_removeSingleCharAndStyle:function(t){var e="\n"===this.text[t-1],i=e?t:t-1;this.removeStyleObject(e,i),this.text=this.text.slice(0,t-1)+this.text.slice(t),this._textLines=this._splitTextIntoLines()},insertChars:function(t,e){var i;if(this.selectionEnd-this.selectionStart>1&&this._removeCharsFromTo(this.selectionStart,this.selectionEnd),!e&&this.isEmptyStyles())return void this.insertChar(t,!1);for(var r=0,n=t.length;r=i&&(s[parseInt(o,10)-i]=this.styles[e][o],delete this.styles[e][o]);this.styles[e+1]=s}this._forceClearCache=!0},insertCharStyleObject:function(e,i,r){var n=this.styles[e],s=t(n);0!==i||r||(i=1);for(var o in s){var a=parseInt(o,10);a>=i&&(n[a+1]=s[a],s[a-1]||delete n[a])}this.styles[e][i]=r||t(n[i-1]),this._forceClearCache=!0},insertStyleObjects:function(t,e,i){var r=this.get2DCursorLocation(),n=r.lineIndex,s=r.charIndex;this._getLineStyle(n)||this._setLineStyle(n,{}),"\n"===t?this.insertNewlineStyleObject(n,s,e):this.insertCharStyleObject(n,s,i)},shiftLineStyles:function(e,i){var r=t(this.styles);for(var n in this.styles){var s=parseInt(n,10);s>e&&(this.styles[s+i]=r[s],r[s-i]||delete this.styles[s])}},removeStyleObject:function(t,e){var i=this.get2DCursorLocation(e),r=i.lineIndex,n=i.charIndex;this._removeStyleObject(t,i,r,n)},_getTextOnPreviousLine:function(t){return this._textLines[t-1]},_removeStyleObject:function(e,i,r,n){if(e){var s=this._getTextOnPreviousLine(i.lineIndex),o=s?s.length:0;this.styles[r-1]||(this.styles[r-1]={});for(n in this.styles[r])this.styles[r-1][parseInt(n,10)+o]=this.styles[r][n];this.shiftLineStyles(i.lineIndex,-1)}else{var a=this.styles[r];a&&delete a[n];var h=t(a);for(var c in h){var l=parseInt(c,10);l>=n&&0!==l&&(a[l-1]=h[l],delete a[l])}}},insertNewline:function(){this.insertChars("\n")},setSelectionStartEndWithShift:function(t,e,i){i<=t?(e===t?this._selectionDirection="left":"right"===this._selectionDirection&&(this._selectionDirection="left",this.selectionEnd=t),this.selectionStart=i):i>t&&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.bind(this))},onMouseDown:function(t){this.__newClickTime=+new Date;var e=this.canvas.getPointer(t.e);this.isTripleClick(e)?(this.fire("tripleclick",t),this._stopEvent(t.e)):this.isDoubleClick(e)&&(this.fire("dblclick",t),this._stopEvent(t.e)),this.__lastLastClickTime=this.__lastClickTime,this.__lastClickTime=this.__newClickTime,this.__lastPointer=e,this.__lastIsEditing=this.isEditing,this.__lastSelected=this.selected},isDoubleClick:function(t){return this.__newClickTime-this.__lastClickTime<500&&this.__lastPointer.x===t.x&&this.__lastPointer.y===t.y&&this.__lastIsEditing},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.initSelectedHandler(),this.initMousedownHandler(),this.initMouseupHandler(),this.initClicks()},initClicks:function(){this.on("dblclick",function(t){this.selectWord(this.getSelectionStartFromPointer(t.e))}),this.on("tripleclick",function(t){this.selectLine(this.getSelectionStartFromPointer(t.e))})},initMousedownHandler:function(){this.on("mousedown",function(t){if(this.editable){var e=this.canvas.getPointer(t.e);this.__mousedownX=e.x,this.__mousedownY=e.y,this.__isMousedown=!0,this.selected&&this.setCursorByClick(t.e),this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection())}})},_isObjectMoved:function(t){var e=this.canvas.getPointer(t);return this.__mousedownX!==e.x||this.__mousedownY!==e.y},initMouseupHandler:function(){this.on("mouseup",function(t){this.__isMousedown=!1,this.editable&&!this._isObjectMoved(t.e)&&(this.__lastSelected&&!this.__corner&&(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._fireSelectionChanged(),this._updateTextarea()},getSelectionStartFromPointer:function(t){for(var e,i,r=this.getLocalPointer(t),n=0,s=0,o=0,a=0,h=0,c=this._textLines.length;hs?0:1,h=r+a;return this.flipX&&(h=n-h),h>this.text.length&&(h=this.text.length),h}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off");var t=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+t.top+"; left: "+t.left+"; opacity: 0; width: 0px; height: 0px; z-index: -999;",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.cut.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:{8:"removeChars",9:"exitEditing",27:"exitEditing",13:"insertNewline",33:"moveCursorUp",34:"moveCursorDown",35:"moveCursorRight",36:"moveCursorLeft",37:"moveCursorLeft",38:"moveCursorUp",39:"moveCursorRight",40:"moveCursorDown",46:"forwardDelete"},_ctrlKeysMapUp:{67:"copy",88:"cut"},_ctrlKeysMapDown:{65:"selectAll"},onClick:function(){this.hiddenTextarea&&this.hiddenTextarea.focus()},onKeyDown:function(t){if(this.isEditing){if(t.keyCode in this._keysMap)this[this._keysMap[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(),this.canvas&&this.canvas.renderAll()}},onKeyUp:function(t){return!this.isEditing||this._copyDone?void(this._copyDone=!1):void(t.keyCode in this._ctrlKeysMapUp&&(t.ctrlKey||t.metaKey)&&(this[this._ctrlKeysMapUp[t.keyCode]](t),t.stopImmediatePropagation(),t.preventDefault(),this.canvas&&this.canvas.renderAll()))},onInput:function(t){if(this.isEditing&&!this.inCompositionMode){var e,i,r,n=this.selectionStart||0,s=this.selectionEnd||0,o=this.text.length,a=this.hiddenTextarea.value.length;a>o?(r="left"===this._selectionDirection?s:n,e=a-o,i=this.hiddenTextarea.value.slice(r,r+e)):(e=a-o+s-n,i=this.hiddenTextarea.value.slice(n,n+e)),this.insertChars(i),t.stopPropagation()}},onCompositionStart:function(){this.inCompositionMode=!0,this.prevCompositionLength=0,this.compositionStart=this.selectionStart},onCompositionEnd:function(){this.inCompositionMode=!1},onCompositionUpdate:function(t){var e=t.data;this.selectionStart=this.compositionStart,this.selectionEnd=this.selectionEnd===this.selectionStart?this.compositionStart+this.prevCompositionLength:this.selectionEnd,this.insertChars(e,!1),this.prevCompositionLength=e.length},forwardDelete:function(t){if(this.selectionStart===this.selectionEnd){if(this.selectionStart===this.text.length)return;this.moveCursorRight(t)}this.removeChars(t)},copy:function(t){if(this.selectionStart!==this.selectionEnd){var e=this.getSelectedText(),i=this._getClipboardData(t);i&&i.setData("text",e),fabric.copiedText=e,fabric.copiedTextStyle=this.getSelectionStyles(this.selectionStart,this.selectionEnd),t.stopImmediatePropagation(),t.preventDefault(),this._copyDone=!0}},paste:function(t){var e=null,i=this._getClipboardData(t),r=!0;i?(e=i.getData("text").replace(/\r/g,""),fabric.copiedTextStyle&&fabric.copiedText===e||(r=!1)):e=fabric.copiedText,e&&this.insertChars(e,r),t.stopImmediatePropagation(),t.preventDefault()},cut:function(t){this.selectionStart!==this.selectionEnd&&(this.copy(t),this.removeChars(t))},_getClipboardData:function(t){return t&&t.clipboardData||fabric.window.clipboardData},_getWidthBeforeCursor:function(t,e){for(var i,r=this._textLines[t].slice(0,e),n=this._getLineWidth(this.ctx,t),s=this._getLineLeftOffset(n),o=0,a=r.length;oe){i=!0;var f=o-u,d=o,g=Math.abs(f-e),p=Math.abs(d-e);a=p=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="get"+t+"CursorOffset",r=this[i](e,"right"===this._selectionDirection);e.shiftKey?this.moveCursorWithShift(r):this.moveCursorWithoutShift(r),0!==r&&(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,i+=e.shiftKey?"Shift":"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){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(t):this._removeCharsFromTo(this.selectionStart,this.selectionEnd),this.setSelectionEnd(this.selectionStart),this._removeExtraneousStyles(),this.canvas&&this.canvas.renderAll(),this.setCoords(),this.fire("changed"),this.canvas&&this.canvas.fire("text:changed",{target:this})},_removeCharsNearCursor:function(t){if(0!==this.selectionStart)if(t.metaKey){var e=this.findLineBoundaryLeft(this.selectionStart);this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)}else if(t.altKey){var i=this.findWordBoundaryLeft(this.selectionStart);this._removeCharsFromTo(i,this.selectionStart),this.setSelectionStart(i)}else this._removeSingleCharAndStyle(this.selectionStart),this.setSelectionStart(this.selectionStart-1)}}),function(){var t=fabric.util.toFixed,e=fabric.Object.NUM_FRACTION_DIGITS;fabric.util.object.extend(fabric.IText.prototype,{_setSVGTextLineText:function(t,e,i,r,n,s){this._getLineStyle(t)?this._setSVGTextLineChars(t,e,i,r,s):fabric.Text.prototype._setSVGTextLineText.call(this,t,e,i,r,n)},_setSVGTextLineChars:function(t,e,i,r,n){for(var s=this._textLines[t],o=0,a=this._getLineLeftOffset(this._getLineWidth(this.ctx,t))-this.width/2,h=this._getSVGLineTopOffset(t),c=this._getHeightOfLine(this.ctx,t),l=0,u=s.length;l\n'].join("")},_createTextCharSpan:function(i,r,n,s,o){var a=this.getSvgStyles.call(fabric.util.object.extend({visible:!0,fill:this.fill,stroke:this.stroke,type:"text",getSvgFilter:fabric.Object.prototype.getSvgFilter},r));return['\t\t\t',fabric.util.string.escapeXml(i),"\n"].join("")}})}(),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.clone;e.Textbox=e.util.createClass(e.IText,e.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:2,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,initialize:function(t,i){this.ctx=e.util.createCanvasElement().getContext("2d"),this.callSuper("initialize",t,i),this.setControlsVisibility(e.Textbox.getTextboxControlVisibility()),this._dimensionAffectingProps.width=!0},_initDimensions:function(t){this.__skipDimension||(t||(t=e.util.createCanvasElement().getContext("2d"),this._setTextStyles(t)),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(t))},_generateStyleMap:function(){for(var t=0,e=0,i=0,r={},n=0;n0?(e=0,i++,t++):" "===this.text[i]&&n>0&&(e++,i++),r[n]={line:t,offset:e},i+=this._textLines[n].length,e+=this._textLines[n].length;return r},_getStyleDeclaration:function(t,e,i){if(this._styleMap){var r=this._styleMap[t];if(!r)return i?{}:null;t=r.line,e=r.offset+e}return this.callSuper("_getStyleDeclaration",t,e,i)},_setStyleDeclaration:function(t,e,i){var r=this._styleMap[t];t=r.line,e=r.offset+e,this.styles[t][e]=i},_deleteStyleDeclaration:function(t,e){var i=this._styleMap[t];t=i.line,e=i.offset+e,delete this.styles[t][e]},_getLineStyle:function(t){var e=this._styleMap[t];return this.styles[e.line]},_setLineStyle:function(t,e){var i=this._styleMap[t];this.styles[i.line]=e},_deleteLineStyle:function(t){var e=this._styleMap[t];delete this.styles[e.line]},_wrapText:function(t,e){var i,r=e.split(this._reNewline),n=[];for(i=0;i=this.width&&!d?(n.push(s),s="",r=l,d=!0):r+=g,d||(s+=c),s+=a,u=this._measureText(t,c,i,h),h++,d=!1,l>f&&(f=l);return p&&n.push(s),f>this.dynamicMinWidth&&(this.dynamicMinWidth=f-g),n},_splitTextIntoLines:function(){var t=this.textAlign;this.ctx.save(),this._setTextStyles(this.ctx),this.textAlign="left";var e=this._wrapText(this.ctx,this.text);return this.textAlign=t,this.ctx.restore(),this._textLines=e,this._styleMap=this._generateStyleMap(),e},setOnGroup:function(t,e){"scaleX"===t&&(this.set("scaleX",Math.abs(1/e)),this.set("width",this.get("width")*e/("undefined"==typeof this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=e)},get2DCursorLocation:function(t){"undefined"==typeof t&&(t=this.selectionStart);for(var e=this._textLines.length,i=0,r=0;r=h.getMinWidth()?(h.set("width",c),!0):void 0},fabric.Group.prototype._refreshControlsVisibility=function(){if("undefined"!=typeof fabric.Textbox)for(var t=this._objects.length;t--;)if(this._objects[t]instanceof fabric.Textbox)return void this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility())};var e=fabric.util.object.clone;fabric.util.object.extend(fabric.Textbox.prototype,{_removeExtraneousStyles:function(){for(var t in this._styleMap)this._textLines[t]||delete this.styles[this._styleMap[t].line]},insertCharStyleObject:function(t,e,i){var r=this._styleMap[t];t=r.line,e=r.offset+e,fabric.IText.prototype.insertCharStyleObject.apply(this,[t,e,i])},insertNewlineStyleObject:function(t,e,i){var r=this._styleMap[t];t=r.line,e=r.offset+e,fabric.IText.prototype.insertNewlineStyleObject.apply(this,[t,e,i])},shiftLineStyles:function(t,i){var r=e(this.styles),n=this._styleMap[t];t=n.line;for(var s in this.styles){var o=parseInt(s,10);o>t&&(this.styles[o+i]=r[o],r[o-i]||delete this.styles[o])}},_getTextOnPreviousLine:function(t){for(var e=this._textLines[t-1];this._styleMap[t-2]&&this._styleMap[t-2].line===this._styleMap[t-1].line;)e=this._textLines[t-2]+e,t--;return e},removeStyleObject:function(t,e){var i=this.get2DCursorLocation(e),r=this._styleMap[i.lineIndex],n=r.line,s=r.offset+i.charIndex;this._removeStyleObject(t,i,n,s)}})}(),function(){var t=fabric.IText.prototype._getNewSelectionStartFromOffset;fabric.IText.prototype._getNewSelectionStartFromOffset=function(e,i,r,n,s){n=t.call(this,e,i,r,n,s);for(var o=0,a=0,h=0;h=n));h++)"\n"!==this.text[o+a]&&" "!==this.text[o+a]||a++;return n-h+a}}(),function(){function request(t,e,i){var r=URL.parse(t);r.port||(r.port=0===r.protocol.indexOf("https:")?443:80);var n=0===r.protocol.indexOf("https:")?HTTPS:HTTP,s=n.request({hostname:r.hostname,port:r.port,path:r.path,method:"GET"},function(t){var r="";e&&t.setEncoding(e),t.on("end",function(){i(r)}),t.on("data",function(e){200===t.statusCode&&(r+=e)})});s.on("error",function(t){t.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+r.hostname+":"+r.port):fabric.log(t.message),i(null)}),s.end()}function requestFs(t,e){var i=require("fs");i.readFile(t,function(t,i){if(t)throw fabric.log(t),t;e(i)})}if("undefined"==typeof document||"undefined"==typeof window){var DOMParser=require("xmldom").DOMParser,URL=require("url"),HTTP=require("http"),HTTPS=require("https"),Canvas=require("canvas"),Image=require("canvas").Image;fabric.util.loadImage=function(t,e,i){function r(r){r?(n.src=new Buffer(r,"binary"),n._src=t,e&&e.call(i,n)):(n=null,e&&e.call(i,null,!0))}var n=new Image;t&&(t instanceof Buffer||0===t.indexOf("data"))?(n.src=n._src=t,e&&e.call(i,n)):t&&0!==t.indexOf("http")?requestFs(t,r):t?request(t,"binary",r):e&&e.call(i,t)},fabric.loadSVGFromURL=function(t,e,i){t=t.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim(),0!==t.indexOf("http")?requestFs(t,function(t){fabric.loadSVGFromString(t.toString(),e,i)}):request(t,"",function(t){fabric.loadSVGFromString(t,e,i)})},fabric.loadSVGFromString=function(t,e,i){var r=(new DOMParser).parseFromString(t);fabric.parseSVGDocument(r.documentElement,function(t,i){e&&e(t,i)},i)},fabric.util.getScript=function(url,callback){request(url,"",function(body){eval(body),callback&&callback()})},fabric.createCanvasForNode=function(t,e,i,r){r=r||i;var n=fabric.document.createElement("canvas"),s=new Canvas(t||600,e||600,r),o=new Canvas(t||600,e||600,r);n.style={},n.width=s.width,n.height=s.height,i=i||{},i.nodeCanvas=s,i.nodeCacheCanvas=o;var a=fabric.Canvas||fabric.StaticCanvas,h=new a(n,i);return h.nodeCanvas=s,h.nodeCacheCanvas=o,h.contextContainer=s.getContext("2d"),h.contextCache=o.getContext("2d"),h.Font=Canvas.Font,h};var originaInitStatic=fabric.StaticCanvas.prototype._initStatic;fabric.StaticCanvas.prototype._initStatic=function(t,e){t=t||fabric.document.createElement("canvas"),this.nodeCanvas=new Canvas(t.width,t.height),this.nodeCacheCanvas=new Canvas(t.width,t.height),originaInitStatic.call(this,t,e),this.contextContainer=this.nodeCanvas.getContext("2d"),this.contextCache=this.nodeCacheCanvas.getContext("2d"),this.Font=Canvas.Font},fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(t){return this.nodeCanvas.createJPEGStream(t)},fabric.StaticCanvas.prototype._initRetinaScaling=function(){if(this._isRetinaScaling())return this.lowerCanvasEl.setAttribute("width",this.width*fabric.devicePixelRatio),this.lowerCanvasEl.setAttribute("height",this.height*fabric.devicePixelRatio),this.nodeCanvas.width=this.width*fabric.devicePixelRatio,this.nodeCanvas.height=this.height*fabric.devicePixelRatio,this.contextContainer.scale(fabric.devicePixelRatio,fabric.devicePixelRatio),this},fabric.Canvas&&(fabric.Canvas.prototype._initRetinaScaling=fabric.StaticCanvas.prototype._initRetinaScaling);var origSetBackstoreDimension=fabric.StaticCanvas.prototype._setBackstoreDimension;fabric.StaticCanvas.prototype._setBackstoreDimension=function(t,e){return origSetBackstoreDimension.call(this,t,e),this.nodeCanvas[t]=e,this},fabric.Canvas&&(fabric.Canvas.prototype._setBackstoreDimension=fabric.StaticCanvas.prototype._setBackstoreDimension)}}(); \ No newline at end of file diff --git a/dist/fabric.min.js.gz b/dist/fabric.min.js.gz index 1b8630ff..af922952 100644 Binary files a/dist/fabric.min.js.gz and b/dist/fabric.min.js.gz differ diff --git a/dist/fabric.require.js b/dist/fabric.require.js index 10fefd3a..a0cfce29 100644 --- a/dist/fabric.require.js +++ b/dist/fabric.require.js @@ -1,5 +1,5 @@ var fabric = fabric || { - version: "1.6.4" + version: "1.6.5" }; if (typeof exports !== "undefined") { @@ -274,8 +274,8 @@ fabric.Collection = { if (!namespace) { return fabric; } - var parts = namespace.split("."), len = parts.length, obj = global || fabric.window; - for (var i = 0; i < len; ++i) { + var parts = namespace.split("."), len = parts.length, i, obj = global || fabric.window; + for (i = 0; i < len; ++i) { obj = obj[parts[i]]; } return obj; @@ -378,9 +378,12 @@ fabric.Collection = { return fabric.isLikelyNode ? new (require("canvas").Image)() : fabric.document.createElement("img"); }, createAccessors: function(klass) { - var proto = klass.prototype; - for (var i = proto.stateProperties.length; i--; ) { - var propName = proto.stateProperties[i], capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1), setterName = "set" + capitalizedPropName, getterName = "get" + capitalizedPropName; + var proto = klass.prototype, i, propName, capitalizedPropName, setterName, getterName; + for (i = proto.stateProperties.length; i--; ) { + propName = proto.stateProperties[i]; + capitalizedPropName = propName.charAt(0).toUpperCase() + propName.slice(1); + setterName = "set" + capitalizedPropName; + getterName = "get" + capitalizedPropName; if (!proto[getterName]) { proto[getterName] = function(property) { return new Function('return this.get("' + property + '")'); @@ -443,9 +446,9 @@ fabric.Collection = { y = 0; } } - var _isTransparent = true, imageData = ctx.getImageData(x, y, tolerance * 2 || 1, tolerance * 2 || 1); - for (var i = 3, l = imageData.data.length; i < l; i += 4) { - var temp = imageData.data[i]; + var _isTransparent = true, i, temp, imageData = ctx.getImageData(x, y, tolerance * 2 || 1, tolerance * 2 || 1), l = imageData.data.length; + for (i = 3; i < l; i += 4) { + temp = imageData.data[i]; _isTransparent = temp <= 0; if (_isTransparent === false) { break; @@ -790,14 +793,28 @@ fabric.Collection = { })(); (function() { - function extend(destination, source) { - for (var property in source) { - destination[property] = source[property]; + function extend(destination, source, deep) { + if (deep) { + if (source instanceof Array) { + destination = source.map(function(v) { + return clone(v, deep); + }); + } else if (source instanceof Object) { + for (var property in source) { + destination[property] = clone(source[property], deep); + } + } else { + destination = source; + } + } else { + for (var property in source) { + destination[property] = source[property]; + } } return destination; } - function clone(object) { - return extend({}, object); + function clone(object, deep) { + return extend({}, object, deep); } fabric.util.object = { extend: extend, @@ -1737,7 +1754,7 @@ if (typeof console !== "undefined") { } attributeValue.replace(reTransform, function(match) { var m = new RegExp(transform).exec(match).filter(function(match) { - return match !== "" && match != null; + return !!match; }), operation = m[1], args = m.slice(2).map(parseFloat); switch (operation) { case "translate": @@ -1868,7 +1885,7 @@ if (typeof console !== "undefined") { attr = attrs.item(j); el3.setAttribute(attr.nodeName, attr.nodeValue); } - while (el2.firstChild != null) { + while (el2.firstChild) { el3.appendChild(el2.firstChild); } el2 = el3; @@ -1908,7 +1925,9 @@ if (typeof console !== "undefined") { parsedDim.height = parseUnit(heightAttr); return parsedDim; } - minX = -parseFloat(viewBoxAttr[1]), minY = -parseFloat(viewBoxAttr[2]), viewBoxWidth = parseFloat(viewBoxAttr[3]), + minX = -parseFloat(viewBoxAttr[1]); + minY = -parseFloat(viewBoxAttr[2]); + viewBoxWidth = parseFloat(viewBoxAttr[3]); viewBoxHeight = parseFloat(viewBoxAttr[4]); if (!missingDimAttr) { parsedDim.width = parseUnit(widthAttr); @@ -1932,7 +1951,7 @@ if (typeof console !== "undefined") { matrix = translateMatrix + " matrix(" + scaleX + " 0" + " 0 " + scaleY + " " + minX * scaleX + " " + minY * scaleY + ") "; if (element.nodeName === "svg") { el = element.ownerDocument.createElement("g"); - while (element.firstChild != null) { + while (element.firstChild) { el.appendChild(element.firstChild); } element.appendChild(el); @@ -2254,9 +2273,9 @@ fabric.ElementsParser.prototype.parse = function() { fabric.ElementsParser.prototype.createObjects = function() { for (var i = 0, len = this.elements.length; i < len; i++) { this.elements[i].setAttribute("svgUid", this.svgUid); - (function(_this, i) { + (function(_obj, i) { setTimeout(function() { - _this.createObject(_this.elements[i], i); + _obj.createObject(_obj.elements[i], i); }, 0); })(this, i); } @@ -2496,7 +2515,9 @@ fabric.ElementsParser.prototype.checkIfDone = function() { fabric.Intersection.intersectLinePolygon = function(a1, a2, points) { var result = new Intersection(), length = points.length, b1, b2, inter; for (var i = 0; i < length; i++) { - b1 = points[i], b2 = points[(i + 1) % length], inter = Intersection.intersectLineLine(a1, a2, b1, b2); + b1 = points[i]; + b2 = points[(i + 1) % length]; + inter = Intersection.intersectLineLine(a1, a2, b1, b2); result.appendPoints(inter.points); } if (result.points.length > 0) { @@ -2569,7 +2590,9 @@ fabric.ElementsParser.prototype.checkIfDone = function() { } }, _rgbToHsl: function(r, g, b) { - r /= 255, g /= 255, b /= 255; + r /= 255; + g /= 255; + b /= 255; var h, s, l, max = fabric.util.array.max([ r, g, b ]), min = fabric.util.array.min([ r, g, b ]); l = (max + min) / 2; if (max === min) { @@ -2872,7 +2895,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() { markup = [ "\n' ]; } for (var i = 0; i < this.colorStops.length; i++) { - markup.push("\n'); + markup.push("\n'); } markup.push(this.type === "linear" ? "\n" : "\n"); return markup.join(""); @@ -3249,22 +3272,18 @@ fabric.Pattern = fabric.util.createClass({ } return this; }, - _createCanvasElement: function() { - var element = fabric.document.createElement("canvas"); + _createCanvasElement: function(canvasEl) { + var element = fabric.util.createCanvasElement(canvasEl); if (!element.style) { element.style = {}; } if (!element) { throw CANVAS_INIT_ERROR; } - this._initCanvasElement(element); - return element; - }, - _initCanvasElement: function(element) { - fabric.util.createCanvasElement(element); if (typeof element.getContext === "undefined") { throw CANVAS_INIT_ERROR; } + return element; }, _initOptions: function(options) { for (var prop in options) { @@ -3282,8 +3301,7 @@ fabric.Pattern = fabric.util.createClass({ this.viewportTransform = this.viewportTransform.slice(); }, _createLowerCanvas: function(canvasEl) { - this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement(); - this._initCanvasElement(this.lowerCanvasEl); + this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement(canvasEl); fabric.util.addClass(this.lowerCanvasEl, "lower-canvas"); if (this.interactive) { this._applyCanvasStyle(this.lowerCanvasEl); @@ -3352,10 +3370,11 @@ fabric.Pattern = fabric.util.createClass({ return Math.sqrt(this.viewportTransform[0] * this.viewportTransform[3]); }, setViewportTransform: function(vpt) { - var activeGroup = this.getActiveGroup(); + var activeGroup = this._activeGroup, object; this.viewportTransform = vpt; for (var i = 0, len = this._objects.length; i < len; i++) { - this._objects[i].setCoords(); + object = this._objects[i]; + object.group || object.setCoords(); } if (activeGroup) { activeGroup.setCoords(); @@ -3389,12 +3408,6 @@ fabric.Pattern = fabric.util.createClass({ getElement: function() { return this.lowerCanvasEl; }, - getActiveObject: function() { - return null; - }, - getActiveGroup: function() { - return null; - }, _onObjectAdded: function(obj) { this.stateful && obj.setupState(); obj._set("canvas", this); @@ -3409,6 +3422,7 @@ fabric.Pattern = fabric.util.createClass({ target: obj }); obj.fire("removed"); + delete obj.canvas; }, clearContext: function(ctx) { ctx.clearRect(0, 0, this.width, this.height); @@ -3419,6 +3433,10 @@ fabric.Pattern = fabric.util.createClass({ }, clear: function() { this._objects.length = 0; + this.backgroundImage = null; + this.overlayImage = null; + this.backgroundColor = ""; + this.overlayColor = ""; this.clearContext(this.contextContainer); this.fire("canvas:cleared"); this.renderAll(); @@ -3452,7 +3470,6 @@ fabric.Pattern = fabric.util.createClass({ } this.fire("after:render"); }, - drawControls: function() {}, _renderObjects: function(ctx, objects) { for (var i = 0, length = objects.length; i < length; ++i) { objects[i] && objects[i].render(ctx); @@ -3534,7 +3551,7 @@ fabric.Pattern = fabric.util.createClass({ var data = { objects: this._toObjects(methodName, propertiesToInclude) }; - extend(data, this.__serializeBgOverlay()); + extend(data, this.__serializeBgOverlay(propertiesToInclude)); fabric.util.populateWithProperties(this, data, propertiesToInclude); return data; }, @@ -3551,43 +3568,24 @@ fabric.Pattern = fabric.util.createClass({ originalValue = instance.includeDefaultValues; instance.includeDefaultValues = false; } - var originalProperties = this._realizeGroupTransformOnObject(instance), object = instance[methodName](propertiesToInclude); + var object = instance[methodName](propertiesToInclude); if (!this.includeDefaultValues) { instance.includeDefaultValues = originalValue; } - this._unwindGroupTransformOnObject(instance, originalProperties); return object; }, - _realizeGroupTransformOnObject: function(instance) { - var layoutProps = [ "angle", "flipX", "flipY", "height", "left", "scaleX", "scaleY", "top", "width" ]; - if (instance.group && instance.group === this.getActiveGroup()) { - var originalValues = {}; - layoutProps.forEach(function(prop) { - originalValues[prop] = instance[prop]; - }); - this.getActiveGroup().realizeTransform(instance); - return originalValues; - } else { - return null; - } - }, - _unwindGroupTransformOnObject: function(instance, originalValues) { - if (originalValues) { - instance.set(originalValues); - } - }, - __serializeBgOverlay: function() { + __serializeBgOverlay: function(propertiesToInclude) { var data = { - background: this.backgroundColor && this.backgroundColor.toObject ? this.backgroundColor.toObject() : this.backgroundColor + background: this.backgroundColor && this.backgroundColor.toObject ? this.backgroundColor.toObject(propertiesToInclude) : this.backgroundColor }; if (this.overlayColor) { - data.overlay = this.overlayColor.toObject ? this.overlayColor.toObject() : this.overlayColor; + data.overlay = this.overlayColor.toObject ? this.overlayColor.toObject(propertiesToInclude) : this.overlayColor; } if (this.backgroundImage) { - data.backgroundImage = this.backgroundImage.toObject(); + data.backgroundImage = this.backgroundImage.toObject(propertiesToInclude); } if (this.overlayImage) { - data.overlayImage = this.overlayImage.toObject(); + data.overlayImage = this.overlayImage.toObject(propertiesToInclude); } return data; }, @@ -3624,17 +3622,18 @@ fabric.Pattern = fabric.util.createClass({ markup.push("\n', "Created with Fabric.js ", fabric.version, "\n", "", fabric.createSVGFontFacesMarkup(this.getObjects()), fabric.createSVGRefElementsMarkup(this), "\n"); }, _setSVGObjects: function(markup, reviver) { - var instance, originalProperties; + var instance; for (var i = 0, objects = this.getObjects(), len = objects.length; i < len; i++) { instance = objects[i]; if (instance.excludeFromExport) { continue; } - originalProperties = this._realizeGroupTransformOnObject(instance); - markup.push(instance.toSVG(reviver)); - this._unwindGroupTransformOnObject(instance, originalProperties); + this._setSVGObject(markup, instance, reviver); } }, + _setSVGObject: function(markup, instance, reviver) { + markup.push(instance.toSVG(reviver)); + }, _setSVGBgOverlayImage: function(markup, property, reviver) { if (this[property] && this[property].toSVG) { markup.push(this[property].toSVG(reviver)); @@ -3651,7 +3650,7 @@ fabric.Pattern = fabric.util.createClass({ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, i, obj, objs; + var activeGroup = this._activeGroup, i, obj, objs; if (object === activeGroup) { objs = activeGroup._objects; for (i = objs.length; i--; ) { @@ -3669,7 +3668,7 @@ fabric.Pattern = fabric.util.createClass({ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, i, obj, objs; + var activeGroup = this._activeGroup, i, obj, objs; if (object === activeGroup) { objs = activeGroup._objects; for (i = 0; i < objs.length; i++) { @@ -3687,7 +3686,7 @@ fabric.Pattern = fabric.util.createClass({ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, i, obj, idx, newIdx, objs; + var activeGroup = this._activeGroup, i, obj, idx, newIdx, objs; if (object === activeGroup) { objs = activeGroup._objects; for (i = 0; i < objs.length; i++) { @@ -3730,7 +3729,7 @@ fabric.Pattern = fabric.util.createClass({ if (!object) { return this; } - var activeGroup = this.getActiveGroup ? this.getActiveGroup() : null, i, obj, idx, newIdx, objs; + var activeGroup = this._activeGroup, i, obj, idx, newIdx, objs; if (object === activeGroup) { objs = activeGroup._objects; for (i = objs.length; i--; ) { @@ -4176,7 +4175,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { }); (function() { - var getPointer = fabric.util.getPointer, degreesToRadians = fabric.util.degreesToRadians, radiansToDegrees = fabric.util.radiansToDegrees, atan2 = Math.atan2, abs = Math.abs, STROKE_OFFSET = .5; + var getPointer = fabric.util.getPointer, degreesToRadians = fabric.util.degreesToRadians, radiansToDegrees = fabric.util.radiansToDegrees, atan2 = Math.atan2, abs = Math.abs, supportLineDash = fabric.StaticCanvas.supports("setLineDash"), STROKE_OFFSET = .5; fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, { initialize: function(el, options) { options || (options = {}); @@ -4193,6 +4192,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { interactive: true, selection: true, selectionKey: "shiftKey", + altSelectionKey: null, selectionColor: "rgba(100, 100, 255, 0.3)", selectionDashArray: [], selectionBorderColor: "rgba(255, 255, 255, 0.3)", @@ -4208,6 +4208,8 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { skipTargetFind: false, isDrawingMode: false, preserveObjectStacking: false, + stopContextMenu: false, + fireRightClick: false, _initInteractive: function() { this._currentTransform = null; this._groupSelector = null; @@ -4456,7 +4458,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { } var center = target.getCenterPoint(), actualMouseByCenter = target.toLocalPoint(new fabric.Point(x, y), "center", "center")[by], lastMouseByCenter = target.toLocalPoint(new fabric.Point(t.lastX, t.lastY), "center", "center")[by], actualMouseByOrigin, constraintPosition, dim = target._getTransformedDimensions(); this._changeSkewTransformOrigin(actualMouseByCenter - lastMouseByCenter, t, by); - actualMouseByOrigin = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY)[by], + actualMouseByOrigin = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY)[by]; constraintPosition = target.translateToOriginPoint(center, t.originX, t.originY); skewed = this._setObjectSkew(actualMouseByOrigin, t, by, dim); t.lastX = x; @@ -4620,11 +4622,16 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { }, _drawSelection: function(ctx) { var groupSelector = this._groupSelector, left = groupSelector.left, top = groupSelector.top, aleft = abs(left), atop = abs(top); - ctx.fillStyle = this.selectionColor; - ctx.fillRect(groupSelector.ex - (left > 0 ? 0 : -left), groupSelector.ey - (top > 0 ? 0 : -top), aleft, atop); + if (this.selectionColor) { + ctx.fillStyle = this.selectionColor; + ctx.fillRect(groupSelector.ex - (left > 0 ? 0 : -left), groupSelector.ey - (top > 0 ? 0 : -top), aleft, atop); + } + if (!this.selectionLineWidth || !this.selectionBorderColor) { + return; + } ctx.lineWidth = this.selectionLineWidth; ctx.strokeStyle = this.selectionBorderColor; - if (this.selectionDashArray.length > 1) { + if (this.selectionDashArray.length > 1 && !supportLineDash) { var px = groupSelector.ex + STROKE_OFFSET - (left > 0 ? 0 : aleft), py = groupSelector.ey + STROKE_OFFSET - (top > 0 ? 0 : atop); ctx.beginPath(); fabric.util.drawDashedLine(ctx, px, py, px + aleft, py, this.selectionDashArray); @@ -4634,6 +4641,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { ctx.closePath(); ctx.stroke(); } else { + fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray); ctx.strokeRect(groupSelector.ex + STROKE_OFFSET - (left > 0 ? 0 : aleft), groupSelector.ey + STROKE_OFFSET - (top > 0 ? 0 : atop), aleft, atop); } }, @@ -4641,15 +4649,28 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { if (this.skipTargetFind) { return; } - var ignoreZoom = true, pointer = this.getPointer(e, ignoreZoom), activeGroup = this.getActiveGroup(), activeObject = this.getActiveObject(); + var ignoreZoom = true, pointer = this.getPointer(e, ignoreZoom), activeGroup = this.getActiveGroup(), activeObject = this.getActiveObject(), activeTarget; if (activeGroup && !skipGroup && this._checkTarget(pointer, activeGroup)) { + this._fireOverOutEvents(activeGroup, e); return activeGroup; } - if (activeObject && this._checkTarget(pointer, activeObject)) { + if (activeObject && activeObject._findTargetCorner(pointer)) { + this._fireOverOutEvents(activeObject, e); return activeObject; } + if (activeObject && this._checkTarget(pointer, activeObject)) { + if (!this.preserveObjectStacking) { + this._fireOverOutEvents(activeObject, e); + return activeObject; + } else { + activeTarget = activeObject; + } + } this.targets = []; var target = this._searchPossibleTargets(this._objects, pointer); + if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) { + target = activeTarget; + } this._fireOverOutEvents(target, e); return target; }, @@ -4950,6 +4971,35 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { } this._objects[i]._renderControls(ctx); } + }, + _toObject: function(instance, methodName, propertiesToInclude) { + var originalProperties = this._realizeGroupTransformOnObject(instance), object = this.callSuper("_toObject", instance, methodName, propertiesToInclude); + this._unwindGroupTransformOnObject(instance, originalProperties); + return object; + }, + _realizeGroupTransformOnObject: function(instance) { + var layoutProps = [ "angle", "flipX", "flipY", "height", "left", "scaleX", "scaleY", "top", "width" ]; + if (instance.group && instance.group === this.getActiveGroup()) { + var originalValues = {}; + layoutProps.forEach(function(prop) { + originalValues[prop] = instance[prop]; + }); + this.getActiveGroup().realizeTransform(instance); + return originalValues; + } else { + return null; + } + }, + _unwindGroupTransformOnObject: function(instance, originalValues) { + if (originalValues) { + instance.set(originalValues); + } + }, + _setSVGObject: function(markup, instance, reviver) { + var originalProperties; + originalProperties = this._realizeGroupTransformOnObject(instance); + this.callSuper("_setSVGObject", markup, instance, reviver); + this._unwindGroupTransformOnObject(instance, originalProperties); } }); for (var prop in fabric.StaticCanvas) { @@ -4983,6 +5033,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { addListener(this.upperCanvasEl, "mousemove", this._onMouseMove); addListener(this.upperCanvasEl, "mouseout", this._onMouseOut); addListener(this.upperCanvasEl, "wheel", this._onMouseWheel); + addListener(this.upperCanvasEl, "contextmenu", this._onContextMenu); addListener(this.upperCanvasEl, "touchstart", this._onMouseDown); addListener(this.upperCanvasEl, "touchmove", this._onMouseMove); if (typeof eventjs !== "undefined" && "add" in eventjs) { @@ -5005,6 +5056,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { this._onOrientationChange = this._onOrientationChange.bind(this); this._onMouseWheel = this._onMouseWheel.bind(this); this._onMouseOut = this._onMouseOut.bind(this); + this._onContextMenu = this._onContextMenu.bind(this); }, removeListeners: function() { removeListener(fabric.window, "resize", this._onResize); @@ -5012,6 +5064,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { removeListener(this.upperCanvasEl, "mousemove", this._onMouseMove); removeListener(this.upperCanvasEl, "mouseout", this._onMouseOut); removeListener(this.upperCanvasEl, "wheel", this._onMouseWheel); + removeListener(this.upperCanvasEl, "contextmenu", this._onContextMenu); removeListener(this.upperCanvasEl, "touchstart", this._onMouseDown); removeListener(this.upperCanvasEl, "touchmove", this._onMouseMove); if (typeof eventjs !== "undefined" && "remove" in eventjs) { @@ -5051,6 +5104,13 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { _onLongPress: function(e, self) { this.__onLongPress && this.__onLongPress(e, self); }, + _onContextMenu: function(e) { + if (this.stopContextMenu) { + e.stopPropagation(); + e.preventDefault(); + } + return false; + }, _onMouseDown: function(e) { this.__onMouseDown(e); addListener(fabric.document, "touchend", this._onMouseUp); @@ -5183,8 +5243,11 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { this._handleEvent(e, "up"); }, __onMouseDown: function(e) { - var isLeftClick = "which" in e ? e.which === 1 : e.button === 0; - if (!isLeftClick && !fabric.isTouchSupported) { + var isRightClick = "which" in e ? e.which === 3 : e.button === 2; + if (isRightClick) { + if (this.fireRightClick) { + this._handleEvent(e, "down", target ? target : null); + } return; } if (this.isDrawingMode) { @@ -5285,7 +5348,8 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { }, _transformObject: function(e) { var pointer = this.getPointer(e), transform = this._currentTransform; - transform.reset = false, transform.target.isMoving = true; + transform.reset = false; + transform.target.isMoving = true; this._beforeScaleTransform(e, transform); this._performTransformAction(e, transform, pointer); transform.actionPerformed && this.renderAll(); @@ -5499,116 +5563,57 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, { }); })(); -fabric.util.object.extend(fabric.StaticCanvas.prototype, { - toDataURL: function(options) { - options || (options = {}); - var format = options.format || "png", quality = options.quality || 1, multiplier = options.multiplier || 1, cropping = { - left: options.left, - top: options.top, - width: options.width, - height: options.height - }; - if (this._isRetinaScaling()) { - multiplier *= fabric.devicePixelRatio; - } - if (multiplier !== 1) { +(function() { + var supportQuality = fabric.StaticCanvas.supports("toDataURLWithQuality"); + fabric.util.object.extend(fabric.StaticCanvas.prototype, { + toDataURL: function(options) { + options || (options = {}); + var format = options.format || "png", quality = options.quality || 1, multiplier = options.multiplier || 1, cropping = { + left: options.left || 0, + top: options.top || 0, + width: options.width || 0, + height: options.height || 0 + }; return this.__toDataURLWithMultiplier(format, quality, cropping, multiplier); - } else { - return this.__toDataURL(format, quality, cropping); - } - }, - __toDataURL: function(format, quality, cropping) { - this.renderAll(); - var canvasEl = this.contextContainer.canvas, croppedCanvasEl = this.__getCroppedCanvas(canvasEl, cropping); - if (format === "jpg") { - format = "jpeg"; - } - var data = fabric.StaticCanvas.supports("toDataURLWithQuality") ? (croppedCanvasEl || canvasEl).toDataURL("image/" + format, quality) : (croppedCanvasEl || canvasEl).toDataURL("image/" + format); - if (croppedCanvasEl) { - croppedCanvasEl = null; - } - return data; - }, - __getCroppedCanvas: function(canvasEl, cropping) { - var croppedCanvasEl, croppedCtx, shouldCrop = "left" in cropping || "top" in cropping || "width" in cropping || "height" in cropping; - if (shouldCrop) { - croppedCanvasEl = fabric.util.createCanvasElement(); - croppedCtx = croppedCanvasEl.getContext("2d"); - croppedCanvasEl.width = cropping.width || this.width; - croppedCanvasEl.height = cropping.height || this.height; - croppedCtx.drawImage(canvasEl, -cropping.left || 0, -cropping.top || 0); - } - return croppedCanvasEl; - }, - __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) { - var origWidth = this.getWidth(), origHeight = this.getHeight(), scaledWidth = origWidth * multiplier, scaledHeight = origHeight * multiplier, activeObject = this.getActiveObject(), activeGroup = this.getActiveGroup(), zoom = this.getZoom(), newZoom = zoom * multiplier / fabric.devicePixelRatio; - if (multiplier > 1) { + }, + __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) { + var origWidth = this.getWidth(), origHeight = this.getHeight(), scaledWidth = (cropping.width || this.getWidth()) * multiplier, scaledHeight = (cropping.width || this.getHeight()) * multiplier, zoom = this.getZoom(), newZoom = zoom * multiplier, vp = this.viewportTransform, translateX = (vp[4] - cropping.left) * multiplier, translateY = (vp[5] - cropping.top) * multiplier, newVp = [ newZoom, 0, 0, newZoom, translateX, translateY ], originalInteractive = this.interactive; + this.viewportTransform = newVp; + this.interactive && (this.interactive = false); + if (origWidth !== scaledWidth || origHeight !== scaledHeight) { + this.setDimensions({ + width: scaledWidth, + height: scaledHeight + }); + } else { + this.renderAll(); + } + var data = this.__toDataURL(format, quality, cropping); + originalInteractive && (this.interactive = originalInteractive); + this.viewportTransform = vp; this.setDimensions({ - width: scaledWidth, - height: scaledHeight + width: origWidth, + height: origHeight + }); + return data; + }, + __toDataURL: function(format, quality) { + var canvasEl = this.contextContainer.canvas; + if (format === "jpg") { + format = "jpeg"; + } + var data = supportQuality ? canvasEl.toDataURL("image/" + format, quality) : canvasEl.toDataURL("image/" + format); + return data; + }, + toDataURLWithMultiplier: function(format, multiplier, quality) { + return this.toDataURL({ + format: format, + multiplier: multiplier, + quality: quality }); } - this.setZoom(newZoom); - if (cropping.left) { - cropping.left *= multiplier; - } - if (cropping.top) { - cropping.top *= multiplier; - } - if (cropping.width) { - cropping.width *= multiplier; - } else if (multiplier < 1) { - cropping.width = scaledWidth; - } - if (cropping.height) { - cropping.height *= multiplier; - } else if (multiplier < 1) { - cropping.height = scaledHeight; - } - if (activeGroup) { - this._tempRemoveBordersControlsFromGroup(activeGroup); - } else if (activeObject && this.deactivateAll) { - this.deactivateAll(); - } - var data = this.__toDataURL(format, quality, cropping); - if (activeGroup) { - this._restoreBordersControlsOnGroup(activeGroup); - } else if (activeObject && this.setActiveObject) { - this.setActiveObject(activeObject); - } - this.setZoom(zoom); - this.setDimensions({ - width: origWidth, - height: origHeight - }); - return data; - }, - toDataURLWithMultiplier: function(format, multiplier, quality) { - return this.toDataURL({ - format: format, - multiplier: multiplier, - quality: quality - }); - }, - _tempRemoveBordersControlsFromGroup: function(group) { - group.origHasControls = group.hasControls; - group.origBorderColor = group.borderColor; - group.hasControls = true; - group.borderColor = "rgba(0,0,0,0)"; - group.forEachObject(function(o) { - o.origBorderColor = o.borderColor; - o.borderColor = "rgba(0,0,0,0)"; - }); - }, - _restoreBordersControlsOnGroup: function(group) { - group.hideControls = group.origHideControls; - group.borderColor = group.origBorderColor; - group.forEachObject(function(o) { - o.borderColor = o.origBorderColor; - delete o.origBorderColor; - }); - } -}); + }); +})(); fabric.util.object.extend(fabric.StaticCanvas.prototype, { loadFromDatalessJSON: function(json, callback, reviver) { @@ -5802,7 +5807,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, { lockSkewingY: false, lockScalingFlip: false, excludeFromExport: false, - stateProperties: ("top left width height scaleX scaleY flipX flipY originX originY transformMatrix " + "stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit " + "angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor " + "alignX alignY meetOrSlice skewX skewY").split(" "), + stateProperties: ("top left width height scaleX scaleY flipX flipY originX originY transformMatrix " + "stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit " + "angle opacity fill fillRule globalCompositeOperation shadow clipTo visible backgroundColor " + "skewX skewY").split(" "), initialize: function(options) { if (options) { this.setOptions(options); @@ -5989,18 +5994,27 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, { if (!noTransform) { this.transform(ctx); } + this._setOpacity(ctx); + this._setShadow(ctx); + this._renderBackground(ctx); this._setStrokeStyles(ctx); this._setFillStyles(ctx); if (this.transformMatrix) { ctx.transform.apply(ctx, this.transformMatrix); } - this._setOpacity(ctx); - this._setShadow(ctx); this.clipTo && fabric.util.clipContext(this, ctx); this._render(ctx, noTransform); this.clipTo && ctx.restore(); ctx.restore(); }, + _renderBackground: function(ctx) { + if (!this.backgroundColor) { + return; + } + ctx.fillStyle = this.backgroundColor; + ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height); + this._removeShadow(ctx); + }, _setOpacity: function(ctx) { if (this.group) { this.group._setOpacity(ctx); @@ -6405,11 +6419,16 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, { }, intersectsWithObject: function(other) { var intersection = fabric.Intersection.intersectPolygonPolygon(getCoords(this.oCoords), getCoords(other.oCoords)); - return intersection.status === "Intersection"; + return intersection.status === "Intersection" || other.isContainedWithinObject(this) || this.isContainedWithinObject(other); }, isContainedWithinObject: function(other) { - var boundingRect = other.getBoundingRect(), point1 = new fabric.Point(boundingRect.left, boundingRect.top), point2 = new fabric.Point(boundingRect.left + boundingRect.width, boundingRect.top + boundingRect.height); - return this.isContainedWithinRect(point1, point2); + var points = getCoords(this.oCoords), i = 0; + for (;i < 4; i++) { + if (!other.containsPoint(points[i])) { + return false; + } + } + return true; }, isContainedWithinRect: function(pointTL, pointBR) { var boundingRect = this.getBoundingRect(); @@ -6443,7 +6462,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, { }; }, _findCrossPoints: function(point, oCoords) { - var b1, b2, a1, a2, xi, yi, xcount = 0, iLine; + var b1, b2, a1, a2, xi, xcount = 0, iLine; for (var lineKey in oCoords) { iLine = oCoords[lineKey]; if (iLine.o.y < point.y && iLine.d.y < point.y) { @@ -6454,14 +6473,12 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, { } if (iLine.o.x === iLine.d.x && iLine.o.x >= point.x) { xi = iLine.o.x; - yi = point.y; } else { b1 = 0; b2 = (iLine.d.y - iLine.o.y) / (iLine.d.x - iLine.o.x); a1 = point.y - b1 * point.x; a2 = iLine.o.y - b2 * iLine.o.x; xi = -(a1 - a2) / (b1 - b2); - yi = a1 + b1 * xi; } if (xi >= point.x) { xcount += 1; @@ -6653,29 +6670,53 @@ fabric.util.object.extend(fabric.Object.prototype, { }); })(); -fabric.util.object.extend(fabric.Object.prototype, { - hasStateChanged: function() { - return this.stateProperties.some(function(prop) { - return this.get(prop) !== this.originalState[prop]; - }, this); - }, - saveState: function(options) { - this.stateProperties.forEach(function(prop) { - this.originalState[prop] = this.get(prop); - }, this); - if (options && options.stateProperties) { - options.stateProperties.forEach(function(prop) { - this.originalState[prop] = this.get(prop); - }, this); - } - return this; - }, - setupState: function() { - this.originalState = {}; - this.saveState(); - return this; +(function() { + var extend = fabric.util.object.extend; + function saveProps(origin, destination, props) { + var tmpObj = {}, deep = true; + props.forEach(function(prop) { + tmpObj[prop] = origin[prop]; + }); + extend(origin[destination], tmpObj, deep); } -}); + function _isEqual(origValue, currentValue) { + if (origValue instanceof Array) { + if (origValue.length !== currentValue.length) { + return false; + } + var _currentValue = currentValue.concat().sort(), _origValue = origValue.concat().sort(); + return !_origValue.some(function(v, i) { + return !_isEqual(_currentValue[i], v); + }); + } else if (origValue instanceof Object) { + for (var key in origValue) { + if (!_isEqual(origValue[key], currentValue[key])) { + return false; + } + } + return true; + } else { + return origValue === currentValue; + } + } + fabric.util.object.extend(fabric.Object.prototype, { + hasStateChanged: function() { + return !_isEqual(this.originalState, this); + }, + saveState: function(options) { + saveProps(this, "originalState", this.stateProperties); + if (options && options.stateProperties) { + saveProps(this, "originalState", options.stateProperties); + } + return this; + }, + setupState: function(options) { + this.originalState = {}; + this.saveState(options); + return this; + } + }); +})(); (function() { var degreesToRadians = fabric.util.degreesToRadians, isVML = function() { @@ -6787,7 +6828,7 @@ fabric.util.object.extend(fabric.Object.prototype, { return p.scalarAdd(2 * this.padding); }, drawSelectionBackground: function(ctx) { - if (!this.selectionBackgroundColor || this.group || this !== this.canvas.getActiveObject()) { + if (!this.selectionBackgroundColor || this.group || !this.active) { return this; } ctx.save(); @@ -7168,9 +7209,10 @@ fabric.util.object.extend(fabric.Object.prototype, { var parsedAttributes = fabric.parseAttributes(element, fabric.Line.ATTRIBUTE_NAMES), points = [ parsedAttributes.x1 || 0, parsedAttributes.y1 || 0, parsedAttributes.x2 || 0, parsedAttributes.y2 || 0 ]; return new fabric.Line(points, extend(parsedAttributes, options)); }; - fabric.Line.fromObject = function(object) { - var points = [ object.x1, object.y1, object.x2, object.y2 ]; - return new fabric.Line(points, object); + fabric.Line.fromObject = function(object, callback) { + var points = [ object.x1, object.y1, object.x2, object.y2 ], line = new fabric.Line(points, object); + callback && callback(line); + return line; }; function makeEdgeToOriginGetter(propertyNames, originValues) { var origin = propertyNames.origin, axis1 = propertyNames.axis1, axis2 = propertyNames.axis2, dimension = propertyNames.dimension, nearest = originValues.nearest, center = originValues.center, farthest = originValues.farthest; @@ -7273,8 +7315,10 @@ fabric.util.object.extend(fabric.Object.prototype, { function isValidRadius(attributes) { return "radius" in attributes && attributes.radius >= 0; } - fabric.Circle.fromObject = function(object) { - return new fabric.Circle(object); + fabric.Circle.fromObject = function(object, callback) { + var circle = new fabric.Circle(object); + callback && callback(circle); + return circle; }; })(typeof exports !== "undefined" ? exports : this); @@ -7319,8 +7363,10 @@ fabric.util.object.extend(fabric.Object.prototype, { return 1; } }); - fabric.Triangle.fromObject = function(object) { - return new fabric.Triangle(object); + fabric.Triangle.fromObject = function(object, callback) { + var triangle = new fabric.Triangle(object); + callback && callback(triangle); + return triangle; }; })(typeof exports !== "undefined" ? exports : this); @@ -7401,8 +7447,10 @@ fabric.util.object.extend(fabric.Object.prototype, { ellipse.left -= ellipse.rx; return ellipse; }; - fabric.Ellipse.fromObject = function(object) { - return new fabric.Ellipse(object); + fabric.Ellipse.fromObject = function(object, callback) { + var ellipse = new fabric.Ellipse(object); + callback && callback(ellipse); + return ellipse; }; })(typeof exports !== "undefined" ? exports : this); @@ -7498,8 +7546,10 @@ fabric.util.object.extend(fabric.Object.prototype, { rect.visible = rect.visible && rect.width > 0 && rect.height > 0; return rect; }; - fabric.Rect.fromObject = function(object) { - return new fabric.Rect(object); + fabric.Rect.fromObject = function(object, callback) { + var rect = new fabric.Rect(object); + callback && callback(rect); + return rect; }; })(typeof exports !== "undefined" ? exports : this); @@ -7556,9 +7606,10 @@ fabric.util.object.extend(fabric.Object.prototype, { var points = fabric.parsePointsAttribute(element.getAttribute("points")), parsedAttributes = fabric.parseAttributes(element, fabric.Polyline.ATTRIBUTE_NAMES); return new fabric.Polyline(points, fabric.util.object.extend(parsedAttributes, options)); }; - fabric.Polyline.fromObject = function(object) { - var points = object.points; - return new fabric.Polyline(points, object, true); + fabric.Polyline.fromObject = function(object, callback) { + var polyline = new fabric.Polyline(object.points, object); + callback && callback(polyline); + return polyline; }; })(typeof exports !== "undefined" ? exports : this); @@ -7594,7 +7645,8 @@ fabric.util.object.extend(fabric.Object.prototype, { var points = this.points, minX = min(points, "x"), minY = min(points, "y"), maxX = max(points, "x"), maxY = max(points, "y"); this.width = maxX - minX || 0; this.height = maxY - minY || 0; - this.minX = minX || 0, this.minY = minY || 0; + this.minX = minX || 0; + this.minY = minY || 0; }, toObject: function(propertiesToInclude) { return extend(this.callSuper("toObject", propertiesToInclude), { @@ -7653,8 +7705,10 @@ fabric.util.object.extend(fabric.Object.prototype, { var points = fabric.parsePointsAttribute(element.getAttribute("points")), parsedAttributes = fabric.parseAttributes(element, fabric.Polygon.ATTRIBUTE_NAMES); return new fabric.Polygon(points, extend(parsedAttributes, options)); }; - fabric.Polygon.fromObject = function(object) { - return new fabric.Polygon(object.points, object, true); + fabric.Polygon.fromObject = function(object, callback) { + var polygon = new fabric.Polygon(object.points, object); + callback && callback(polygon); + return polygon; }; })(typeof exports !== "undefined" ? exports : this); @@ -8164,16 +8218,20 @@ fabric.util.object.extend(fabric.Object.prototype, { } }); fabric.Path.fromObject = function(object, callback) { + var path; if (typeof object.path === "string") { fabric.loadSVGFromURL(object.path, function(elements) { - var path = elements[0], pathUrl = object.path; + var pathUrl = object.path; + path = elements[0]; delete object.path; fabric.util.object.extend(path, object); path.setSourcePath(pathUrl); - callback(path); + callback && callback(path); }); } else { - callback(new fabric.Path(object.path, object)); + path = new fabric.Path(object.path, object); + callback && callback(path); + return path; } }; fabric.Path.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat([ "d" ]); @@ -8626,6 +8684,8 @@ fabric.util.object.extend(fabric.Object.prototype, { fabric.warn("fabric.Image is already defined."); return; } + var stateProperties = fabric.Object.prototype.stateProperties.concat(); + stateProperties.push("alignX", "alignY", "meetOrSlice"); fabric.Image = fabric.util.createClass(fabric.Object, { type: "image", crossOrigin: "", @@ -8636,6 +8696,7 @@ fabric.util.object.extend(fabric.Object.prototype, { _lastScaleX: 1, _lastScaleY: 1, minimumScaleTrigger: .5, + stateProperties: stateProperties, initialize: function(element, options, callback) { options || (options = {}); this.filters = []; @@ -8734,7 +8795,7 @@ fabric.util.object.extend(fabric.Object.prototype, { return object; }, toSVG: function(reviver) { - var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2, preserveAspectRatio = "none"; + var markup = this._createBaseSVGMarkup(), x = -this.width / 2, y = -this.height / 2, preserveAspectRatio = "none", filtered = true; if (this.group && this.group.type === "path-group") { x = this.left; y = this.top; @@ -8742,7 +8803,7 @@ fabric.util.object.extend(fabric.Object.prototype, { if (this.alignX !== "none" && this.alignY !== "none") { preserveAspectRatio = "x" + this.alignX + "Y" + this.alignY + " " + this.meetOrSlice; } - markup.push('\n', "\n"); + markup.push('\n', "\n"); if (this.stroke || this.strokeDashArray) { var origFill = this.fill; this.fill = null; @@ -8752,8 +8813,8 @@ fabric.util.object.extend(fabric.Object.prototype, { markup.push("\n"); return reviver ? reviver(markup.join("")) : markup.join(""); }, - getSrc: function() { - var element = this._originalElement; + getSrc: function(filtered) { + var element = filtered ? this._element : this._originalElement; if (element) { return fabric.isLikelyNode ? element._src : element.src; } else { @@ -8768,9 +8829,6 @@ fabric.util.object.extend(fabric.Object.prototype, { toString: function() { return '#'; }, - clone: function(callback, propertiesToInclude) { - this.constructor.fromObject(this.toObject(propertiesToInclude), callback); - }, applyFilters: function(callback, filters, imgElement, forResizing) { filters = filters || this.filters; imgElement = imgElement || this._originalElement; @@ -9018,8 +9076,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.Brightness = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Brightness = createClass(filters.BaseFilter, { type: "Brightness", initialize: function(options) { options = options || {}; @@ -9047,8 +9105,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.Convolute = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Convolute = createClass(filters.BaseFilter, { type: "Convolute", initialize: function(options) { options = options || {}; @@ -9101,8 +9159,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.GradientTransparency = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.GradientTransparency = createClass(filters.BaseFilter, { type: "GradientTransparency", initialize: function(options) { options = options || {}; @@ -9128,8 +9186,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}); - fabric.Image.filters.Grayscale = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Grayscale = createClass(filters.BaseFilter, { type: "Grayscale", applyTo: function(canvasEl) { var context = canvasEl.getContext("2d"), imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), data = imageData.data, len = imageData.width * imageData.height * 4, index = 0, average; @@ -9150,8 +9208,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}); - fabric.Image.filters.Invert = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Invert = createClass(filters.BaseFilter, { type: "Invert", applyTo: function(canvasEl) { var context = canvasEl.getContext("2d"), imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), data = imageData.data, iLen = data.length, i; @@ -9170,8 +9228,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.Mask = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Mask = createClass(filters.BaseFilter, { type: "Mask", initialize: function(options) { options = options || {}; @@ -9210,8 +9268,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.Noise = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Noise = createClass(filters.BaseFilter, { type: "Noise", initialize: function(options) { options = options || {}; @@ -9240,8 +9298,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.Pixelate = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Pixelate = createClass(filters.BaseFilter, { type: "Pixelate", initialize: function(options) { options = options || {}; @@ -9282,8 +9340,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.RemoveWhite = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.RemoveWhite = createClass(filters.BaseFilter, { type: "RemoveWhite", initialize: function(options) { options = options || {}; @@ -9316,8 +9374,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}); - fabric.Image.filters.Sepia = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Sepia = createClass(filters.BaseFilter, { type: "Sepia", applyTo: function(canvasEl) { var context = canvasEl.getContext("2d"), imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), data = imageData.data, iLen = data.length, i, avg; @@ -9337,8 +9395,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}); - fabric.Image.filters.Sepia2 = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Sepia2 = createClass(filters.BaseFilter, { type: "Sepia2", applyTo: function(canvasEl) { var context = canvasEl.getContext("2d"), imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), data = imageData.data, iLen = data.length, i, r, g, b; @@ -9360,8 +9418,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.Tint = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Tint = createClass(filters.BaseFilter, { type: "Tint", initialize: function(options) { options = options || {}; @@ -9399,8 +9457,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.Multiply = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Multiply = createClass(filters.BaseFilter, { type: "Multiply", initialize: function(options) { options = options || {}; @@ -9429,8 +9487,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric; - fabric.Image.filters.Blend = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Blend = createClass(filters.BaseFilter, { type: "Blend", initialize: function(options) { options = options || {}; @@ -9531,8 +9589,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), pow = Math.pow, floor = Math.floor, sqrt = Math.sqrt, abs = Math.abs, max = Math.max, round = Math.round, sin = Math.sin, ceil = Math.ceil; - fabric.Image.filters.Resize = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), pow = Math.pow, floor = Math.floor, sqrt = Math.sqrt, abs = Math.abs, max = Math.max, round = Math.round, sin = Math.sin, ceil = Math.ceil, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.Resize = createClass(filters.BaseFilter, { type: "Resize", resizeType: "hermite", scaleX: 0, @@ -9622,7 +9680,11 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ for (v = 0; v < dH; v++) { center.y = (v + .5) * ratioY; icenter.y = floor(center.y); - a = 0, red = 0, green = 0, blue = 0, alpha = 0; + a = 0; + red = 0; + green = 0; + blue = 0; + alpha = 0; for (i = icenter.x - range2X; i <= icenter.x + range2X; i++) { if (i < 0 || i >= oW) { continue; @@ -9738,8 +9800,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend; - fabric.Image.filters.ColorMatrix = fabric.util.createClass(fabric.Image.filters.BaseFilter, { + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, filters = fabric.Image.filters, createClass = fabric.util.createClass; + filters.ColorMatrix = createClass(filters.BaseFilter, { type: "ColorMatrix", initialize: function(options) { options || (options = {}); @@ -9773,7 +9835,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ (function(global) { "use strict"; - var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, clone = fabric.util.object.clone, toFixed = fabric.util.toFixed, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS; + var fabric = global.fabric || (global.fabric = {}), extend = fabric.util.object.extend, clone = fabric.util.object.clone, toFixed = fabric.util.toFixed, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, MIN_TEXT_WIDTH = 2; if (fabric.Text) { fabric.warn("fabric.Text is already defined"); return; @@ -9790,7 +9852,6 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ text: true, charSpacing: true, textAlign: true, - stroke: false, strokeWidth: false }, _reNewline: /\r?\n/, @@ -9828,7 +9889,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ } this._textLines = this._splitTextIntoLines(); this._clearCache(); - this.width = this._getTextWidth(ctx); + this.width = this._getTextWidth(ctx) || this.cursorWidth || MIN_TEXT_WIDTH; this.height = this._getTextHeight(ctx); }, toString: function() { @@ -9967,17 +10028,9 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ return this.fontSize * this._fontSizeMult; }, _renderTextBackground: function(ctx) { - this._renderTextBoxBackground(ctx); + this._renderBackground(ctx); this._renderTextLinesBackground(ctx); }, - _renderTextBoxBackground: function(ctx) { - if (!this.backgroundColor) { - return; - } - ctx.fillStyle = this.backgroundColor; - ctx.fillRect(this._getLeftOffset(), this._getTopOffset(), this.width, this.height); - this._removeShadow(ctx); - }, _renderTextLinesBackground: function(ctx) { if (!this.textBackgroundColor) { return; @@ -10064,7 +10117,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ function renderLinesAtOffset(offsets) { var i, lineHeight = 0, len, j, oLen, lineWidth, lineLeftOffset, heightOfLine; for (i = 0, len = _this._textLines.length; i < len; i++) { - lineWidth = _this._getLineWidth(ctx, i), lineLeftOffset = _this._getLineLeftOffset(lineWidth), + lineWidth = _this._getLineWidth(ctx, i); + lineLeftOffset = _this._getLineLeftOffset(lineWidth); heightOfLine = _this._getHeightOfLine(ctx, i); for (j = 0, oLen = offsets.length; j < oLen; j++) { ctx.fillRect(_this._getLeftOffset() + lineLeftOffset, lineHeight + (_this._fontSizeMult - 1 + offsets[j]) * _this.fontSize - halfOfVerticalBox, lineWidth, _this.fontSize / 15); @@ -10086,7 +10140,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ } }, _getFontDeclaration: function() { - return [ fabric.isLikelyNode ? this.fontWeight : this.fontStyle, fabric.isLikelyNode ? this.fontStyle : this.fontWeight, this.fontSize + "px", '"' + this.fontFamily + '"' ].join(" "); + return [ fabric.isLikelyNode ? this.fontWeight : this.fontStyle, fabric.isLikelyNode ? this.fontStyle : this.fontWeight, this.fontSize + "px", fabric.isLikelyNode ? '"' + this.fontFamily + '"' : this.fontFamily ].join(" "); }, render: function(ctx, noTransform) { if (!this.visible) { @@ -10257,8 +10311,10 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ }); return text; }; - fabric.Text.fromObject = function(object) { - return new fabric.Text(object.text, clone(object)); + fabric.Text.fromObject = function(object, callback) { + var text = new fabric.Text(object.text, clone(object)); + callback && callback(text); + return text; }; fabric.util.createAccessors(fabric.Text); })(typeof exports !== "undefined" ? exports : this); @@ -10672,6 +10728,7 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ styleDeclaration.scaleX = this.scaleX; styleDeclaration.scaleY = this.scaleY; styleDeclaration.canvas = this.canvas; + styleDeclaration.getObjectScaling = this.getObjectScaling; this._setShadow.call(styleDeclaration, ctx); } if (!this.caching || !charWidthsCache[cacheProp]) { @@ -10803,8 +10860,10 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ }); } }); - fabric.IText.fromObject = function(object) { - return new fabric.IText(object.text, clone(object)); + fabric.IText.fromObject = function(object, callback) { + var iText = new fabric.IText(object.text, clone(object)); + callback && callback(iText); + return iText; }; })(); @@ -11119,6 +11178,8 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ if (p.y > maxHeight) { p.y = maxHeight; } + p.x += this.canvas._offset.left; + p.y += this.canvas._offset.top; return { left: p.x + "px", top: p.y + "px", @@ -11327,6 +11388,44 @@ fabric.Image.filters.BaseFilter = fabric.util.createClass({ }, insertNewline: function() { this.insertChars("\n"); + }, + setSelectionStartEndWithShift: function(start, end, newSelection) { + if (newSelection <= start) { + if (end === start) { + this._selectionDirection = "left"; + } else if (this._selectionDirection === "right") { + this._selectionDirection = "left"; + this.selectionEnd = start; + } + this.selectionStart = newSelection; + } else if (newSelection > start && newSelection < end) { + if (this._selectionDirection === "right") { + this.selectionEnd = newSelection; + } else { + this.selectionStart = newSelection; + } + } else { + if (end === start) { + this._selectionDirection = "right"; + } else if (this._selectionDirection === "left") { + this._selectionDirection = "right"; + this.selectionStart = end; + } + this.selectionEnd = newSelection; + } + }, + setSelectionInBoundaries: function() { + var length = this.text.length; + if (this.selectionStart > length) { + this.selectionStart = length; + } else if (this.selectionStart < 0) { + this.selectionStart = 0; + } + if (this.selectionEnd > length) { + this.selectionEnd = length; + } else if (this.selectionEnd < 0) { + this.selectionEnd = 0; + } } }); })(); @@ -11421,17 +11520,12 @@ fabric.util.object.extend(fabric.IText.prototype, { }); }, setCursorByClick: function(e) { - var newSelectionStart = this.getSelectionStartFromPointer(e); + var newSelection = this.getSelectionStartFromPointer(e), start = this.selectionStart, end = this.selectionEnd; if (e.shiftKey) { - if (newSelectionStart < this.selectionStart) { - this.selectionEnd = this.selectionStart; - this.selectionStart = newSelectionStart; - } else { - this.selectionEnd = newSelectionStart; - } + this.setSelectionStartEndWithShift(start, end, newSelection); } else { - this.selectionStart = newSelectionStart; - this.selectionEnd = newSelectionStart; + this.selectionStart = newSelection; + this.selectionEnd = newSelection; } this._fireSelectionChanged(); this._updateTextarea(); @@ -11627,37 +11721,53 @@ fabric.util.object.extend(fabric.IText.prototype, { _getClipboardData: function(e) { return e && e.clipboardData || fabric.window.clipboardData; }, + _getWidthBeforeCursor: function(lineIndex, charIndex) { + var textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex), widthOfLine = this._getLineWidth(this.ctx, lineIndex), widthBeforeCursor = this._getLineLeftOffset(widthOfLine), _char; + for (var i = 0, len = textBeforeCursor.length; i < len; i++) { + _char = textBeforeCursor[i]; + widthBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); + } + return widthBeforeCursor; + }, getDownCursorOffset: function(e, isRight) { - var selectionProp = isRight ? this.selectionEnd : this.selectionStart, cursorLocation = this.get2DCursorLocation(selectionProp), _char, lineLeftOffset, lineIndex = cursorLocation.lineIndex, textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex), textOnSameLineAfterCursor = this._textLines[lineIndex].slice(cursorLocation.charIndex), textOnNextLine = this._textLines[lineIndex + 1] || ""; + var selectionProp = this._getSelectionForOffset(e, isRight), cursorLocation = this.get2DCursorLocation(selectionProp), lineIndex = cursorLocation.lineIndex; if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) { return this.text.length - selectionProp; } - var widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, lineIndex); - lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); - var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; - for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { - _char = textOnSameLineBeforeCursor[i]; - widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); - } - var indexOnNextLine = this._getIndexOnNextLine(cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor); - return textOnSameLineAfterCursor.length + 1 + indexOnNextLine; + var charIndex = cursorLocation.charIndex, widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex), indexOnOtherLine = this._getIndexOnLine(lineIndex + 1, widthBeforeCursor), textAfterCursor = this._textLines[lineIndex].slice(charIndex); + return textAfterCursor.length + indexOnOtherLine + 2; }, - _getIndexOnNextLine: function(cursorLocation, textOnNextLine, widthOfCharsOnSameLineBeforeCursor) { - var lineIndex = cursorLocation.lineIndex + 1, widthOfNextLine = this._getLineWidth(this.ctx, lineIndex), lineLeftOffset = this._getLineLeftOffset(widthOfNextLine), widthOfCharsOnNextLine = lineLeftOffset, indexOnNextLine = 0, foundMatch; - for (var j = 0, jlen = textOnNextLine.length; j < jlen; j++) { - var _char = textOnNextLine[j], widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); - widthOfCharsOnNextLine += widthOfChar; - if (widthOfCharsOnNextLine > widthOfCharsOnSameLineBeforeCursor) { + _getSelectionForOffset: function(e, isRight) { + if (e.shiftKey && this.selectionStart !== this.selectionEnd && isRight) { + return this.selectionEnd; + } else { + return this.selectionStart; + } + }, + getUpCursorOffset: function(e, isRight) { + var selectionProp = this._getSelectionForOffset(e, isRight), cursorLocation = this.get2DCursorLocation(selectionProp), lineIndex = cursorLocation.lineIndex; + if (lineIndex === 0 || e.metaKey || e.keyCode === 33) { + return -selectionProp; + } + var charIndex = cursorLocation.charIndex, widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex), indexOnOtherLine = this._getIndexOnLine(lineIndex - 1, widthBeforeCursor), textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex); + return -this._textLines[lineIndex - 1].length + indexOnOtherLine - textBeforeCursor.length; + }, + _getIndexOnLine: function(lineIndex, width) { + var widthOfLine = this._getLineWidth(this.ctx, lineIndex), textOnLine = this._textLines[lineIndex], lineLeftOffset = this._getLineLeftOffset(widthOfLine), widthOfCharsOnLine = lineLeftOffset, indexOnLine = 0, foundMatch; + for (var j = 0, jlen = textOnLine.length; j < jlen; j++) { + var _char = textOnLine[j], widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); + widthOfCharsOnLine += widthOfChar; + if (widthOfCharsOnLine > width) { foundMatch = true; - var leftEdge = widthOfCharsOnNextLine - widthOfChar, rightEdge = widthOfCharsOnNextLine, offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor), offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); - indexOnNextLine = offsetFromRightEdge < offsetFromLeftEdge ? j + 1 : j; + var leftEdge = widthOfCharsOnLine - widthOfChar, rightEdge = widthOfCharsOnLine, offsetFromLeftEdge = Math.abs(leftEdge - width), offsetFromRightEdge = Math.abs(rightEdge - width); + indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : j - 1; break; } } if (!foundMatch) { - indexOnNextLine = textOnNextLine.length; + indexOnLine = textOnLine.length - 1; } - return indexOnNextLine; + return indexOnLine; }, moveCursorDown: function(e) { if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) { @@ -11665,65 +11775,6 @@ fabric.util.object.extend(fabric.IText.prototype, { } this._moveCursorUpOrDown("Down", e); }, - moveCursorDownWithoutShift: function(offset) { - this._selectionDirection = "right"; - this.selectionEnd = this.selectionEnd + offset; - this.selectionStart = this.selectionEnd; - return offset !== 0; - }, - swapSelectionPoints: function() { - var swapSel = this.selectionEnd; - this.selectionEnd = this.selectionStart; - this.selectionStart = swapSel; - }, - moveCursorDownWithShift: function(offset) { - if (this.selectionEnd === this.selectionStart) { - this._selectionDirection = "right"; - } - if (this._selectionDirection === "right") { - this.selectionEnd += offset; - } else { - this.selectionStart += offset; - } - if (this.selectionEnd < this.selectionStart && this._selectionDirection === "left") { - this.swapSelectionPoints(); - this._selectionDirection = "right"; - } - if (this.selectionEnd > this.text.length) { - this.selectionEnd = this.text.length; - } - return offset !== 0; - }, - getUpCursorOffset: function(e, isRight) { - var selectionProp = isRight ? this.selectionEnd : this.selectionStart, cursorLocation = this.get2DCursorLocation(selectionProp), lineIndex = cursorLocation.lineIndex; - if (lineIndex === 0 || e.metaKey || e.keyCode === 33) { - return selectionProp; - } - var textOnSameLineBeforeCursor = this._textLines[lineIndex].slice(0, cursorLocation.charIndex), textOnPreviousLine = this._textLines[lineIndex - 1] || "", _char, widthOfSameLineBeforeCursor = this._getLineWidth(this.ctx, cursorLocation.lineIndex), lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor), widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; - for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { - _char = textOnSameLineBeforeCursor[i]; - widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); - } - var indexOnPrevLine = this._getIndexOnPrevLine(cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor); - return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length; - }, - _getIndexOnPrevLine: function(cursorLocation, textOnPreviousLine, widthOfCharsOnSameLineBeforeCursor) { - var lineIndex = cursorLocation.lineIndex - 1, widthOfPreviousLine = this._getLineWidth(this.ctx, lineIndex), lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine), widthOfCharsOnPreviousLine = lineLeftOffset, indexOnPrevLine = 0, foundMatch; - for (var j = 0, jlen = textOnPreviousLine.length; j < jlen; j++) { - var _char = textOnPreviousLine[j], widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); - widthOfCharsOnPreviousLine += widthOfChar; - if (widthOfCharsOnPreviousLine > widthOfCharsOnSameLineBeforeCursor) { - foundMatch = true; - var leftEdge = widthOfCharsOnPreviousLine - widthOfChar, rightEdge = widthOfCharsOnPreviousLine, offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor), offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); - indexOnPrevLine = offsetFromRightEdge < offsetFromLeftEdge ? j : j - 1; - break; - } - } - if (!foundMatch) { - indexOnPrevLine = textOnPreviousLine.length - 1; - } - return indexOnPrevLine; - }, moveCursorUp: function(e) { if (this.selectionStart === 0 && this.selectionEnd === 0) { return; @@ -11731,13 +11782,14 @@ fabric.util.object.extend(fabric.IText.prototype, { this._moveCursorUpOrDown("Up", e); }, _moveCursorUpOrDown: function(direction, e) { - var action = "get" + direction + "CursorOffset", moveAction = "moveCursor" + direction, offset = this[action](e, this._selectionDirection === "right"); + var action = "get" + direction + "CursorOffset", offset = this[action](e, this._selectionDirection === "right"); if (e.shiftKey) { - moveAction += "WithShift"; + this.moveCursorWithShift(offset); } else { - moveAction += "WithoutShift"; + this.moveCursorWithoutShift(offset); } - if (this[moveAction](offset)) { + if (offset !== 0) { + this.setSelectionInBoundaries(); this.abortCursorAnimation(); this._currentCursorOpacity = 1; this.initDelayedCursor(); @@ -11745,25 +11797,19 @@ fabric.util.object.extend(fabric.IText.prototype, { this._updateTextarea(); } }, - moveCursorUpWithShift: function(offset) { - if (this.selectionEnd === this.selectionStart) { - this._selectionDirection = "left"; - } - if (this._selectionDirection === "right") { - this.selectionEnd -= offset; - } else { - this.selectionStart -= offset; - } - if (this.selectionEnd < this.selectionStart && this._selectionDirection === "right") { - this.swapSelectionPoints(); - this._selectionDirection = "left"; - } + moveCursorWithShift: function(offset) { + var newSelection = this._selectionDirection === "left" ? this.selectionStart + offset : this.selectionEnd + offset; + this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection); return offset !== 0; }, - moveCursorUpWithoutShift: function(offset) { - this._selectionDirection = "left"; - this.selectionStart -= offset; - this.selectionEnd = this.selectionStart; + moveCursorWithoutShift: function(offset) { + if (offset < 0) { + this.selectionStart += offset; + this.selectionEnd = this.selectionStart; + } else { + this.selectionEnd += offset; + this.selectionStart = this.selectionEnd; + } return offset !== 0; }, moveCursorLeft: function(e) { @@ -11939,7 +11985,7 @@ fabric.util.object.extend(fabric.IText.prototype, { fabric.Textbox = fabric.util.createClass(fabric.IText, fabric.Observable, { type: "textbox", minWidth: 20, - dynamicMinWidth: 0, + dynamicMinWidth: 2, __cachedLines: null, lockScalingY: true, lockScalingFlip: true, @@ -11968,11 +12014,11 @@ fabric.util.object.extend(fabric.IText.prototype, { _generateStyleMap: function() { var realLineCount = 0, realLineCharCount = 0, charCount = 0, map = {}; for (var i = 0; i < this._textLines.length; i++) { - if (this.text[charCount] === "\n") { + if (this.text[charCount] === "\n" && i > 0) { realLineCharCount = 0; charCount++; realLineCount++; - } else if (this.text[charCount] === " ") { + } else if (this.text[charCount] === " " && i > 0) { realLineCharCount++; charCount++; } @@ -12135,8 +12181,10 @@ fabric.util.object.extend(fabric.IText.prototype, { }); } }); - fabric.Textbox.fromObject = function(object) { - return new fabric.Textbox(object.text, clone(object)); + fabric.Textbox.fromObject = function(object, callback) { + var textbox = new fabric.Textbox(object.text, clone(object)); + callback && callback(textbox); + return textbox; }; fabric.Textbox.getTextboxControlVisibility = function() { return { @@ -12348,37 +12396,55 @@ fabric.util.object.extend(fabric.IText.prototype, { canvasEl.style = {}; canvasEl.width = nodeCanvas.width; canvasEl.height = nodeCanvas.height; + options = options || {}; + options.nodeCanvas = nodeCanvas; + options.nodeCacheCanvas = nodeCacheCanvas; var FabricCanvas = fabric.Canvas || fabric.StaticCanvas, fabricCanvas = new FabricCanvas(canvasEl, options); - fabricCanvas.contextContainer = nodeCanvas.getContext("2d"); fabricCanvas.nodeCanvas = nodeCanvas; - fabricCanvas.contextCache = nodeCacheCanvas.getContext("2d"); fabricCanvas.nodeCacheCanvas = nodeCacheCanvas; + fabricCanvas.contextContainer = nodeCanvas.getContext("2d"); + fabricCanvas.contextCache = nodeCacheCanvas.getContext("2d"); fabricCanvas.Font = Canvas.Font; return fabricCanvas; }; + var originaInitStatic = fabric.StaticCanvas.prototype._initStatic; + fabric.StaticCanvas.prototype._initStatic = function(el, options) { + el = el || fabric.document.createElement("canvas"); + this.nodeCanvas = new Canvas(el.width, el.height); + this.nodeCacheCanvas = new Canvas(el.width, el.height); + originaInitStatic.call(this, el, options); + this.contextContainer = this.nodeCanvas.getContext("2d"); + this.contextCache = this.nodeCacheCanvas.getContext("2d"); + this.Font = Canvas.Font; + }; fabric.StaticCanvas.prototype.createPNGStream = function() { return this.nodeCanvas.createPNGStream(); }; fabric.StaticCanvas.prototype.createJPEGStream = function(opts) { return this.nodeCanvas.createJPEGStream(opts); }; - var origSetWidth = fabric.StaticCanvas.prototype.setWidth; - fabric.StaticCanvas.prototype.setWidth = function(width, options) { - origSetWidth.call(this, width, options); - this.nodeCanvas.width = width; + fabric.StaticCanvas.prototype._initRetinaScaling = function() { + if (!this._isRetinaScaling()) { + return; + } + this.lowerCanvasEl.setAttribute("width", this.width * fabric.devicePixelRatio); + this.lowerCanvasEl.setAttribute("height", this.height * fabric.devicePixelRatio); + this.nodeCanvas.width = this.width * fabric.devicePixelRatio; + this.nodeCanvas.height = this.height * fabric.devicePixelRatio; + this.contextContainer.scale(fabric.devicePixelRatio, fabric.devicePixelRatio); return this; }; if (fabric.Canvas) { - fabric.Canvas.prototype.setWidth = fabric.StaticCanvas.prototype.setWidth; + fabric.Canvas.prototype._initRetinaScaling = fabric.StaticCanvas.prototype._initRetinaScaling; } - var origSetHeight = fabric.StaticCanvas.prototype.setHeight; - fabric.StaticCanvas.prototype.setHeight = function(height, options) { - origSetHeight.call(this, height, options); - this.nodeCanvas.height = height; + var origSetBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension; + fabric.StaticCanvas.prototype._setBackstoreDimension = function(prop, value) { + origSetBackstoreDimension.call(this, prop, value); + this.nodeCanvas[prop] = value; return this; }; if (fabric.Canvas) { - fabric.Canvas.prototype.setHeight = fabric.StaticCanvas.prototype.setHeight; + fabric.Canvas.prototype._setBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension; } })(); diff --git a/package.json b/package.json index e2ca924a..cae5715c 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "fabric", "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.", "homepage": "http://fabricjs.com/", - "version": "1.6.4", + "version": "1.6.5", "author": "Juriy Zaytsev ", "contributors": [ { diff --git a/src/mixins/collection.mixin.js b/src/mixins/collection.mixin.js index 34cef890..fbd7ae11 100644 --- a/src/mixins/collection.mixin.js +++ b/src/mixins/collection.mixin.js @@ -6,7 +6,9 @@ fabric.Collection = { _objects: [], /** - * Adds objects to collection, then renders canvas (if `renderOnAddRemove` is not `false`) + * Adds objects to collection, Canvas or Group, then renders canvas + * (if `renderOnAddRemove` is not `false`). + * in case of Group no changes to bounding box are made. * Objects should be instances of (or inherit from) fabric.Object * @param {...fabric.Object} object Zero or more fabric instances * @return {Self} thisArg diff --git a/src/shapes/itext.class.js b/src/shapes/itext.class.js index 9f711873..f8ea01ba 100644 --- a/src/shapes/itext.class.js +++ b/src/shapes/itext.class.js @@ -888,6 +888,7 @@ styleDeclaration.scaleX = this.scaleX; styleDeclaration.scaleY = this.scaleY; styleDeclaration.canvas = this.canvas; + styleDeclaration.getObjectScaling = this.getObjectScaling; this._setShadow.call(styleDeclaration, ctx); }