diff --git a/CHANGELOG.md b/CHANGELOG.md
index 96644e39..01ef4081 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [2.4.4]
+- Fix: add clipPath to stateful cache check. [#5384](https://github.com/fabricjs/fabric.js/pull/5384)
+- Fix: restore draggability of small objects [#5379](https://github.com/fabricjs/fabric.js/pull/5379)
+- Improvement: Added strokeDashOffset to objects and from SVG import. [#5398](https://github.com/fabricjs/fabric.js/pull/5398)
+- Fix: do not mark objects as invisible if strokeWidth is > 0 [#5382](https://github.com/fabricjs/fabric.js/pull/5382)
+- Improvement: Better gradients parsing with xlink:href [#5357](https://github.com/fabricjs/fabric.js/pull/5357)
+
## [2.4.3]
- Fix: Shift click and onSelect function [#5348](https://github.com/fabricjs/fabric.js/pull/5348)
- Fix: Load from Json from images with filters and resize filters [#5346](https://github.com/fabricjs/fabric.js/pull/5346)
diff --git a/HEADER.js b/HEADER.js
index 1c481068..3904c4dd 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: '2.4.3' };
+var fabric = fabric || { version: '2.4.4' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
diff --git a/dist/fabric.js b/dist/fabric.js
index 95fc6fc9..a7a65dd3 100644
--- a/dist/fabric.js
+++ b/dist/fabric.js
@@ -1,7 +1,7 @@
/* build: `node build.js modules=ALL exclude=gestures,accessors requirejs minifier=uglifyjs` */
/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */
-var fabric = fabric || { version: '2.4.3' };
+var fabric = fabric || { version: '2.4.4' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
@@ -33,7 +33,8 @@ else {
* True when in environment that supports touch events
* @type boolean
*/
-fabric.isTouchSupported = 'ontouchstart' in fabric.window;
+fabric.isTouchSupported = 'ontouchstart' in fabric.window || 'ontouchstart' in fabric.document ||
+ (fabric.window && fabric.window.navigator && fabric.window.navigator.maxTouchPoints > 0);
/**
* True when in environment that's probably Node.js
@@ -52,7 +53,7 @@ fabric.SHARED_ATTRIBUTES = [
'transform',
'fill', 'fill-opacity', 'fill-rule',
'opacity',
- 'stroke', 'stroke-dasharray', 'stroke-linecap',
+ 'stroke', 'stroke-dasharray', 'stroke-linecap', 'stroke-dashoffset',
'stroke-linejoin', 'stroke-miterlimit',
'stroke-opacity', 'stroke-width',
'id', 'paint-order',
@@ -1788,7 +1789,10 @@ fabric.CommonMethods = {
(function() {
/**
* Copies all enumerable properties of one js object to another
+ * this does not and cannot compete with generic utils.
* Does not clone or extend fabric.Object subclasses.
+ * This is mostly for internal use and has extra handling for fabricJS objects
+ * it skips the canvas property in deep cloning.
* @memberOf fabric.util.object
* @param {Object} destination Where to copy to
* @param {Object} source Where to copy from
@@ -1812,7 +1816,10 @@ fabric.CommonMethods = {
}
else if (source && typeof source === 'object') {
for (var property in source) {
- if (source.hasOwnProperty(property)) {
+ if (property === 'canvas') {
+ destination[property] = extend({ }, source[property]);
+ }
+ else if (source.hasOwnProperty(property)) {
destination[property] = extend({ }, source[property], deep);
}
}
@@ -3379,6 +3386,7 @@ if (typeof console !== 'undefined') {
'letter-spacing': 'charSpacing',
'paint-order': 'paintFirst',
'stroke-dasharray': 'strokeDashArray',
+ 'stroke-dashoffset': 'strokeDashOffset',
'stroke-linecap': 'strokeLineCap',
'stroke-linejoin': 'strokeLineJoin',
'stroke-miterlimit': 'strokeMiterLimit',
@@ -3570,14 +3578,7 @@ if (typeof console !== 'undefined') {
}
// identity matrix
- var iMatrix = [
- 1, // a
- 0, // b
- 0, // c
- 1, // d
- 0, // e
- 0 // f
- ],
+ var iMatrix = fabric.iMatrix,
// == begin transform regexp
number = fabric.reNum,
@@ -3783,7 +3784,7 @@ if (typeof console !== 'undefined') {
/**
* @private
- * to support IE8 missing getElementById on SVGdocument
+ * to support IE8 missing getElementById on SVGdocument and on node xmlDOM
*/
function elementById(doc, id) {
var el;
@@ -4056,6 +4057,28 @@ if (typeof console !== 'undefined') {
}, clone(options), reviver, parsingOptions);
};
+ function recursivelyParseGradientsXlink(doc, gradient) {
+ var gradientsAttrs = ['gradientTransform', 'x1', 'x2', 'y1', 'y2', 'gradientUnits', 'cx', 'cy', 'r', 'fx', 'fy'],
+ xlinkAttr = 'xlink:href',
+ xLink = gradient.getAttribute(xlinkAttr).substr(1),
+ referencedGradient = elementById(doc, xLink);
+ if (referencedGradient && referencedGradient.getAttribute(xlinkAttr)) {
+ recursivelyParseGradientsXlink(doc, referencedGradient);
+ }
+ gradientsAttrs.forEach(function(attr) {
+ if (!gradient.hasAttribute(attr)) {
+ gradient.setAttribute(attr, referencedGradient.getAttribute(attr));
+ }
+ });
+ if (!gradient.children.length) {
+ var referenceClone = referencedGradient.cloneNode(true);
+ while (referenceClone.firstChild) {
+ gradient.appendChild(referenceClone.firstChild);
+ }
+ }
+ gradient.removeAttribute(xlinkAttr);
+ }
+
var reFontDeclaration = new RegExp(
'(normal|italic)?\\s*(normal|small-caps)?\\s*' +
'(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\s*(' +
@@ -4117,26 +4140,14 @@ if (typeof console !== 'undefined') {
'svg:linearGradient',
'svg:radialGradient'],
elList = _getMultipleNodes(doc, tagArray),
- el, j = 0, id, xlink,
- gradientDefs = { }, idsToXlinkMap = { };
+ el, j = 0, gradientDefs = { };
j = elList.length;
-
while (j--) {
el = elList[j];
- xlink = el.getAttribute('xlink:href');
- id = el.getAttribute('id');
- if (xlink) {
- idsToXlinkMap[id] = xlink.substr(1);
- }
- gradientDefs[id] = el;
- }
-
- for (id in idsToXlinkMap) {
- var el2 = gradientDefs[idsToXlinkMap[id]].cloneNode(true);
- el = gradientDefs[id];
- while (el2.firstChild) {
- el.appendChild(el2.firstChild);
+ if (el.getAttribute('xlink:href')) {
+ recursivelyParseGradientsXlink(doc, el);
}
+ gradientDefs[el.getAttribute('id')] = el;
}
return gradientDefs;
},
@@ -9834,8 +9845,8 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
/**
* @private
*/
- _getActionFromCorner: function(target, corner, e) {
- if (!corner) {
+ _getActionFromCorner: function(alreadySelected, corner, e) {
+ if (!corner || !alreadySelected) {
return 'drag';
}
@@ -9858,14 +9869,14 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
* @param {Event} e Event object
* @param {fabric.Object} target
*/
- _setupCurrentTransform: function (e, target) {
+ _setupCurrentTransform: function (e, target, alreadySelected) {
if (!target) {
return;
}
var pointer = this.getPointer(e),
corner = target._findTargetCorner(this.getPointer(e, true)),
- action = this._getActionFromCorner(target, corner, e),
+ action = this._getActionFromCorner(alreadySelected, corner, e),
origin = this._getOriginFromCorner(target, corner);
this._currentTransform = {
@@ -10338,8 +10349,11 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
/**
* Method that determines what object we are clicking on
* the skipGroup parameter is for internal use, is needed for shift+click action
+ * 11/09/2018 TODO: would be cool if findTarget could discern between being a full target
+ * or the outside part of the corner.
* @param {Event} e mouse event
* @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through
+ * @return {fabric.Object} the target found
*/
findTarget: function (e, skipGroup) {
if (this.skipTargetFind) {
@@ -11512,11 +11526,12 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fab
}
if (target) {
+ var alreadySelected = target === this._activeObject;
if (target.selectable) {
this.setActiveObject(target, e);
}
if (target === this._activeObject && (target.__corner || !shouldGroup)) {
- this._setupCurrentTransform(e, target);
+ this._setupCurrentTransform(e, target, alreadySelected);
}
}
this._handleEvent(e, 'down');
@@ -12715,6 +12730,13 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
*/
strokeDashArray: null,
+ /**
+ * Line offset of an object's stroke
+ * @type Number
+ * @default
+ */
+ strokeDashOffset: 0,
+
/**
* Line endings style of an object's stroke (one of "butt", "round", "square")
* @type String
@@ -12956,7 +12978,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
dirty: true,
/**
- * keeps the value of the last hovered coner during mouse move.
+ * keeps the value of the last hovered corner during mouse move.
* 0 is no corner, or 'mt', 'ml', 'mtr' etc..
* It should be private, but there is no harm in using it as
* a read-only property.
@@ -12966,7 +12988,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
__corner: 0,
/**
- * Determins if the fill or the stroke is drawn first (one of "fill" or "stroke")
+ * Determines if the fill or the stroke is drawn first (one of "fill" or "stroke")
* @type String
* @default
*/
@@ -12980,9 +13002,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
*/
stateProperties: (
'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +
- 'stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit ' +
+ 'stroke strokeWidth strokeDashArray strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit ' +
'angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor ' +
- 'skewX skewY fillRule paintFirst'
+ 'skewX skewY fillRule paintFirst clipPath'
).split(' '),
/**
@@ -12994,7 +13016,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
*/
cacheProperties: (
'fill stroke strokeWidth strokeDashArray width height paintFirst' +
- ' strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor'
+ ' strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit backgroundColor clipPath'
).split(' '),
/**
@@ -13007,7 +13029,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
clipPath: undefined,
/**
- * Meaningfull ONLY when the object is used as clipPath.
+ * Meaningful ONLY when the object is used as clipPath.
* if true, the clipPath will make the object clip to the outside of the clipPath
* since 2.4.0
* @type boolean
@@ -13016,7 +13038,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
inverted: false,
/**
- * Meaningfull ONLY when the object is used as clipPath.
+ * Meaningful ONLY when the object is used as clipPath.
* if true, the clipPath will have its top and left relative to canvas, and will
* not be influenced by the object transform. This will make the clipPath relative
* to the canvas, but clipping just a particular object.
@@ -13235,6 +13257,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
strokeWidth: toFixed(this.strokeWidth, NUM_FRACTION_DIGITS),
strokeDashArray: this.strokeDashArray ? this.strokeDashArray.concat() : this.strokeDashArray,
strokeLineCap: this.strokeLineCap,
+ strokeDashOffset: this.strokeDashOffset,
strokeLineJoin: this.strokeLineJoin,
strokeMiterLimit: toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS),
scaleX: toFixed(this.scaleX, NUM_FRACTION_DIGITS),
@@ -13409,7 +13432,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* Retrieves viewportTransform from Object's canvas if possible
* @method getViewportTransform
* @memberOf fabric.Object.prototype
- * @return {Boolean}
+ * @return {Array}
*/
getViewportTransform: function() {
if (this.canvas && this.canvas.viewportTransform) {
@@ -13425,7 +13448,9 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @return {Boolean}
*/
isNotVisible: function() {
- return this.opacity === 0 || (this.width === 0 && this.height === 0) || !this.visible;
+ return this.opacity === 0 ||
+ (this.width === 0 && this.height === 0 && this.strokeWidth === 0) ||
+ !this.visible;
},
/**
@@ -13624,7 +13649,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
},
/**
- * Draws a background for the object big as its untrasformed dimensions
+ * Draws a background for the object big as its untransformed dimensions
* @private
* @param {CanvasRenderingContext2D} ctx Context to render on
*/
@@ -13663,6 +13688,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
if (decl.stroke) {
ctx.lineWidth = decl.strokeWidth;
ctx.lineCap = decl.strokeLineCap;
+ ctx.lineDashOffset = decl.strokeDashOffset;
ctx.lineJoin = decl.strokeLineJoin;
ctx.miterLimit = decl.strokeMiterLimit;
ctx.strokeStyle = decl.stroke.toLive
@@ -13690,7 +13716,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* Sets line dash
* @param {CanvasRenderingContext2D} ctx Context to set the dash line on
* @param {Array} dashArray array representing dashes
- * @param {Function} alternative function to call if browaser does not support lineDash
+ * @param {Function} alternative function to call if browser does not support lineDash
*/
_setLineDash: function(ctx, dashArray, alternative) {
if (!dashArray) {
@@ -13857,7 +13883,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
},
/**
- * This function is an helper for svg import. it decoompose the transformMatrix
+ * This function is an helper for svg import. it decompose the transformMatrix
* and assign properties to object.
* untransformed coordinates
* @private
@@ -14054,7 +14080,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
* @param {Number} [options.r1=0] Radius of start point (only for radial gradients)
* @param {Number} [options.r2=0] Radius of end point (only for radial gradients)
* @param {Object} [options.colorStops] Color stops object eg. {0: 'ff0000', 1: '000000'}
- * @param {Object} [options.gradientTransform] transforMatrix for gradient
+ * @param {Object} [options.gradientTransform] transformMatrix for gradient
* @return {fabric.Object} thisArg
* @chainable
* @see {@link http://jsfiddle.net/fabricjs/58y8b/|jsFiddle demo}
@@ -14281,7 +14307,7 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati
/**
* Sets canvas globalCompositeOperation for specific object
- * custom composition operation for the particular object can be specifed using globalCompositeOperation property
+ * custom composition operation for the particular object can be specified using globalCompositeOperation property
* @param {CanvasRenderingContext2D} ctx Rendering canvas context
*/
_setupCompositeOperation: function (ctx) {
@@ -15343,6 +15369,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
var fillRule = this.fillRule ? this.fillRule : 'nonzero',
strokeWidth = this.strokeWidth ? this.strokeWidth : '0',
strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',
+ strokeDashOffset = this.strokeDashOffset ? this.strokeDashOffset : '0',
strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',
strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',
strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',
@@ -15357,6 +15384,7 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
'stroke-width: ', strokeWidth, '; ',
'stroke-dasharray: ', strokeDashArray, '; ',
'stroke-linecap: ', strokeLineCap, '; ',
+ 'stroke-dashoffset: ', strokeDashOffset, '; ',
'stroke-linejoin: ', strokeLineJoin, '; ',
'stroke-miterlimit: ', strokeMiterLimit, '; ',
fill,
@@ -15616,6 +15644,11 @@ fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prot
}
for (var i = 0, len = keys.length; i < len; i++) {
key = keys[i];
+ // since clipPath is in the statefull cache list and the clipPath objects
+ // would be iterated as an object, this would lead to possible infinite recursion
+ if (key === 'canvas') {
+ continue;
+ }
if (!_isEqual(origValue[key], currentValue[key])) {
return false;
}
diff --git a/dist/fabric.min.js b/dist/fabric.min.js
index 51cb2820..e83ccf49 100644
--- a/dist/fabric.min.js
+++ b/dist/fabric.min.js
@@ -1 +1 @@
-var fabric=fabric||{version:"2.4.3"};function resizeCanvasIfNeeded(t){var e=t.targetCanvas,i=e.width,r=e.height,n=t.destinationWidth,s=t.destinationHeight;i===n&&r===s||(e.width=n,e.height=s)}function copyGLTo2DDrawImage(t,e){var i=t.canvas,r=e.targetCanvas,n=r.getContext("2d");n.translate(0,r.height),n.scale(1,-1);var s=i.height-r.height;n.drawImage(i,0,s,r.width,r.height,0,0,r.width,r.height)}function copyGLTo2DPutImageData(t,e){var i=e.targetCanvas.getContext("2d"),r=e.destinationWidth,n=e.destinationHeight,s=r*n*4,o=new Uint8Array(this.imageBuffer,0,s),a=new Uint8ClampedArray(this.imageBuffer,0,s);t.readPixels(0,0,r,n,t.RGBA,t.UNSIGNED_BYTE,o);var c=new ImageData(a,r,n);i.putImageData(c,0,0)}"undefined"!=typeof exports?exports.fabric=fabric:"function"==typeof define&&define.amd&&define([],function(){return fabric}),"undefined"!=typeof document&&"undefined"!=typeof window?(fabric.document=document,fabric.window=window):(fabric.document=require("jsdom").jsdom(decodeURIComponent("%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E"),{features:{FetchExternalResources:["img"]}}),fabric.jsdomImplForWrapper=require("jsdom/lib/jsdom/living/generated/utils").implForWrapper,fabric.nodeCanvas=require("jsdom/lib/jsdom/utils").Canvas,fabric.window=fabric.document.defaultView,DOMParser=require("xmldom").DOMParser),fabric.isTouchSupported="ontouchstart"in fabric.window,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","paint-order","instantiated_by_use","clip-path"],fabric.DPI=96,fabric.reNum="(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:e[-+]?\\d+)?)",fabric.fontPaths={},fabric.iMatrix=[1,0,0,1,0,0],fabric.canvasModule="canvas",fabric.perfLimitSizeTotal=2097152,fabric.maxCacheSideLimit=4096,fabric.minCacheSideLimit=256,fabric.charWidthsCache={},fabric.textureSize=2048,fabric.enableGLFiltering=!0,fabric.devicePixelRatio=fabric.window.devicePixelRatio||fabric.window.webkitDevicePixelRatio||fabric.window.mozDevicePixelRatio||1,fabric.browserShadowBlurConstant=1,fabric.arcToSegmentsCache={},fabric.boundsOfCurveCache={},fabric.cachesBoundsOfCurve=!0,fabric.initFilterBackend=function(){return fabric.enableGLFiltering&&fabric.isWebglSupported&&fabric.isWebglSupported(fabric.textureSize)?(console.log("max texture size: "+fabric.maxTextureSize),new fabric.WebglFilterBackend({tileSize:fabric.textureSize})):fabric.Canvas2dFilterBackend?new fabric.Canvas2dFilterBackend:void 0},"undefined"!=typeof document&&"undefined"!=typeof window&&(window.fabric=fabric),function(){function r(t,e){if(this.__eventListeners[t]){var i=this.__eventListeners[t];e?i[i.indexOf(e)]=!1:fabric.util.array.fill(i,!1)}}function t(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 e(t,e){if(this.__eventListeners){if(0===arguments.length)for(t in this.__eventListeners)r.call(this,t);else if(1===arguments.length&&"object"==typeof t)for(var i in t)r.call(this,i,t[i]);else r.call(this,t,e);return this}}function i(t,e){if(this.__eventListeners){var i=this.__eventListeners[t];if(i){for(var r=0,n=i.length;r/g,">")},graphemeSplit:function(t){var e,i=0,r=[];for(i=0;i/i,"")));if(!e||!e.documentElement)return n&&n(null),!1;C.parseSVGDocument(e.documentElement,function(t,e,i,r){n&&n(t,e,i,r)},i,r)}})},loadSVGFromString:function(t,n,e,i){var r;if(t=t.trim(),"undefined"!=typeof DOMParser){var s=new DOMParser;s&&s.parseFromString&&(r=s.parseFromString(t,"text/xml"))}else C.window.ActiveXObject&&((r=new ActiveXObject("Microsoft.XMLDOM")).async="false",r.loadXML(t.replace(//i,"")));C.parseSVGDocument(r.documentElement,function(t,e,i,r){n(t,e,i,r)},e,i)}})}("undefined"!=typeof exports?exports:this),fabric.ElementsParser=function(t,e,i,r,n){this.elements=t,this.callback=e,this.options=i,this.reviver=r,this.svgUid=i&&i.svgUid||0,this.parsingOptions=n,this.regexUrl=/^url\(['"]?#([^'"]+)['"]?\)/g},function(t){t.parse=function(){this.instances=new Array(this.elements.length),this.numElements=this.elements.length,this.createObjects()},t.createObjects=function(){var i=this;this.elements.forEach(function(t,e){t.setAttribute("svgUid",i.svgUid),i.createObject(t,e)})},t.findTag=function(t){return fabric[fabric.util.string.capitalize(t.tagName.replace("svg:",""))]},t.createObject=function(t,e){var i=this.findTag(t);if(i&&i.fromElement)try{i.fromElement(t,this.createCallback(e,t),this.options)}catch(t){fabric.log(t)}else this.checkIfDone()},t.createCallback=function(i,r){var n=this;return function(t){var e;n.resolveGradient(t,"fill"),n.resolveGradient(t,"stroke"),t instanceof fabric.Image&&(e=t.parsePreserveAspectRatioAttribute(r)),t._removeTransformMatrix(e),n.resolveClipPath(t),n.reviver&&n.reviver(r,t),n.instances[i]=t,n.checkIfDone()}},t.extractPropertyDefinition=function(t,e,i){var r=t[e];if(/^url\(/.test(r)){var n=this.regexUrl.exec(r)[1];return this.regexUrl.lastIndex=0,fabric[i][this.svgUid][n]}},t.resolveGradient=function(t,e){var i=this.extractPropertyDefinition(t,e,"gradientDefs");i&&t.set(e,fabric.Gradient.fromElement(i,t))},t.createClipPathCallback=function(t,e){return function(t){t._removeTransformMatrix(),t.fillRule=t.clipRule,e.push(t)}},t.resolveClipPath=function(t){var e,i,r,n,s=this.extractPropertyDefinition(t,"clipPath","clipPaths");if(s){r=[],i=fabric.util.invertTransform(t.calcTransformMatrix());for(var o=0;ot.x&&this.y>t.y},gte:function(t){return this.x>=t.x&&this.y>=t.y},lerp:function(t,e){return void 0===e&&(e=.5),e=Math.max(Math.min(1,e),0),new i(this.x+(t.x-this.x)*e,this.y+(t.y-this.y)*e)},distanceFrom:function(t){var e=this.x-t.x,i=this.y-t.y;return Math.sqrt(e*e+i*i)},midPointFrom:function(t){return this.lerp(t)},min:function(t){return new i(Math.min(this.x,t.x),Math.min(this.y,t.y))},max:function(t){return new i(Math.max(this.x,t.x),Math.max(this.y,t.y))},toString:function(){return this.x+","+this.y},setXY:function(t,e){return this.x=t,this.y=e,this},setX:function(t){return this.x=t,this},setY:function(t){return this.y=t,this},setFromPoint:function(t){return this.x=t.x,this.y=t.y,this},swap:function(t){var e=this.x,i=this.y;this.x=t.x,this.y=t.y,t.x=e,t.y=i},clone:function(){return new i(this.x,this.y)}}}("undefined"!=typeof exports?exports:this),function(t){"use strict";var f=t.fabric||(t.fabric={});function d(t){this.status=t,this.points=[]}f.Intersection?f.warn("fabric.Intersection is already defined"):(f.Intersection=d,f.Intersection.prototype={constructor:d,appendPoint:function(t){return this.points.push(t),this},appendPoints:function(t){return this.points=this.points.concat(t),this}},f.Intersection.intersectLineLine=function(t,e,i,r){var n,s=(r.x-i.x)*(t.y-i.y)-(r.y-i.y)*(t.x-i.x),o=(e.x-t.x)*(t.y-i.y)-(e.y-t.y)*(t.x-i.x),a=(r.y-i.y)*(e.x-t.x)-(r.x-i.x)*(e.y-t.y);if(0!==a){var c=s/a,h=o/a;0<=c&&c<=1&&0<=h&&h<=1?(n=new d("Intersection")).appendPoint(new f.Point(t.x+c*(e.x-t.x),t.y+c*(e.y-t.y))):n=new d}else n=new d(0===s||0===o?"Coincident":"Parallel");return n},f.Intersection.intersectLinePolygon=function(t,e,i){var r,n,s,o,a=new d,c=i.length;for(o=0;os.r2,c=t.width/2,h=t.height/2;for(var l in o.sort(function(t,e){return t.offset-e.offset}),"path"===t.type&&(c-=t.pathOffset.x,h-=t.pathOffset.y),s)"x1"===l||"x2"===l?s[l]+=this.offsetX-c:"y1"!==l&&"y2"!==l||(s[l]+=this.offsetY-h);if(n='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"',this.gradientTransform&&(n+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" '),"linear"===this.type?r=["\n']:"radial"===this.type&&(r=["\n']),"radial"===this.type){if(a)for((o=o.concat()).reverse(),e=0,i=o.length;e\n')}return r.push("linear"===this.type?"\n":"\n"),r.join("")},toLive:function(t){var e,i,r,n=fabric.util.object.clone(this.coords);if(this.type){for("linear"===this.type?e=t.createLinearGradient(n.x1,n.y1,n.x2,n.y2):"radial"===this.type&&(e=t.createRadialGradient(n.x1,n.y1,n.r1,n.x2,n.y2,n.r2)),i=0,r=this.colorStops.length;i\n\n\n'},setOptions:function(t){for(var e in t)this[e]=t[e]},toLive:function(t){var e="function"==typeof this.source?this.source():this.source;if(!e)return"";if(void 0!==e.src){if(!e.complete)return"";if(0===e.naturalWidth||0===e.naturalHeight)return""}return t.createPattern(e,this.repeat)}})}(),function(t){"use strict";var o=t.fabric||(t.fabric={}),a=o.util.toFixed;o.Shadow?o.warn("fabric.Shadow is already defined."):(o.Shadow=o.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(t){for(var e in"string"==typeof t&&(t=this._parseShadow(t)),t)this[e]=t[e];this.id=o.Object.__uid++},_parseShadow:function(t){var e=t.trim(),i=o.Shadow.reOffsetsAndBlur.exec(e)||[];return{color:(e.replace(o.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(),offsetX:parseInt(i[1],10)||0,offsetY:parseInt(i[2],10)||0,blur:parseInt(i[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(t){var e=40,i=40,r=o.Object.NUM_FRACTION_DIGITS,n=o.util.rotateVector({x:this.offsetX,y:this.offsetY},o.util.degreesToRadians(-t.angle)),s=new o.Color(this.color);return t.width&&t.height&&(e=100*a((Math.abs(n.x)+this.blur)/t.width,r)+20,i=100*a((Math.abs(n.y)+this.blur)/t.height,r)+20),t.flipX&&(n.x*=-1),t.flipY&&(n.y*=-1),'\n\t\n\t\n\t\n\t\n\t\n\t\t\n\t\t\n\t\n\n'},toObject:function(){if(this.includeDefaultValues)return{color:this.color,blur:this.blur,offsetX:this.offsetX,offsetY:this.offsetY,affectStroke:this.affectStroke};var e={},i=o.Shadow.prototype;return["color","blur","offsetX","offsetY","affectStroke"].forEach(function(t){this[t]!==i[t]&&(e[t]=this[t])},this),e}}),o.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/)}("undefined"!=typeof exports?exports:this),function(){"use strict";if(fabric.StaticCanvas)fabric.warn("fabric.StaticCanvas is already defined.");else{var n=fabric.util.object.extend,t=fabric.util.getElementOffset,h=fabric.util.removeFromArray,a=fabric.util.toFixed,s=fabric.util.transformPoint,o=fabric.util.invertTransform,i=fabric.util.getNodeCanvas,r=fabric.util.createCanvasElement,e=new Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(t,e){e||(e={}),this.renderAndResetBound=this.renderAndReset.bind(this),this.requestRenderAllBound=this.requestRenderAll.bind(this),this._initStatic(t,e)},backgroundColor:"",backgroundImage:null,overlayColor:"",overlayImage:null,includeDefaultValues:!0,stateful:!1,renderOnAddRemove:!0,clipTo:null,controlsAboveOverlay:!1,allowTouchScrolling:!1,imageSmoothingEnabled:!0,viewportTransform:fabric.iMatrix.concat(),backgroundVpt:!0,overlayVpt:!0,onBeforeScaleRotate:function(){},enableRetinaScaling:!0,vptCoords:{},skipOffscreen:!0,clipPath:void 0,_initStatic:function(t,e){var i=this.requestRenderAllBound;this._objects=[],this._createLowerCanvas(t),this._initOptions(e),this._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=t(this.lowerCanvasEl),this},setOverlayImage:function(t,e,i){return this.__setBgOverlayImage("overlayImage",t,e,i)},setBackgroundImage:function(t,e,i){return this.__setBgOverlayImage("backgroundImage",t,e,i)},setOverlayColor:function(t,e){return this.__setBgOverlayColor("overlayColor",t,e)},setBackgroundColor:function(t,e){return this.__setBgOverlayColor("backgroundColor",t,e)},_setImageSmoothing:function(){var t=this.getContext();t.imageSmoothingEnabled=t.imageSmoothingEnabled||t.webkitImageSmoothingEnabled||t.mozImageSmoothingEnabled||t.msImageSmoothingEnabled||t.oImageSmoothingEnabled,t.imageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(i,t,r,n){return"string"==typeof t?fabric.util.loadImage(t,function(t){if(t){var e=new fabric.Image(t,n);(this[i]=e).canvas=this}r&&r(t)},this,n&&n.crossOrigin):(n&&t.setOptions(n),(this[i]=t)&&(t.canvas=this),r&&r(t)),this},__setBgOverlayColor:function(t,e,i){return this[t]=e,this._initGradient(e,t),this._initPattern(e,t,i),this},_createCanvasElement:function(){var t=r();if(!t)throw e;if(t.style||(t.style={}),void 0===t.getContext)throw e;return t},_initOptions:function(t){var e=this.lowerCanvasEl;this._setOptions(t),this.width=this.width||parseInt(e.width,10)||0,this.height=this.height||parseInt(e.height,10)||0,this.lowerCanvasEl.style&&(e.width=this.width,e.height=this.height,e.style.width=this.width+"px",e.style.height=this.height+"px",this.viewportTransform=this.viewportTransform.slice())},_createLowerCanvas:function(t){t&&t.getContext?this.lowerCanvasEl=t:this.lowerCanvasEl=fabric.util.getById(t)||this._createCanvasElement(),fabric.util.addClass(this.lowerCanvasEl,"lower-canvas"),this.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;for(var r in e=e||{},t)i=t[r],e.cssOnly||(this._setBackstoreDimension(r,t[r]),i+="px",this.hasLostContext=!0),e.backstoreOnly||this._setCssDimension(r,i);return this._isCurrentlyDrawing&&this.freeDrawingBrush&&this.freeDrawingBrush._setBrushStyles(),this._initRetinaScaling(),this._setImageSmoothing(),this.calcOffset(),e.cssOnly||this.requestRenderAll(),this},_setBackstoreDimension:function(t,e){return this.lowerCanvasEl[t]=e,this.upperCanvasEl&&(this.upperCanvasEl[t]=e),this.cacheCanvasEl&&(this.cacheCanvasEl[t]=e),this[t]=e,this},_setCssDimension:function(t,e){return this.lowerCanvasEl.style[t]=e,this.upperCanvasEl&&(this.upperCanvasEl.style[t]=e),this.wrapperEl&&(this.wrapperEl.style[t]=e),this},getZoom:function(){return this.viewportTransform[0]},setViewportTransform:function(t){var e,i,r,n=this._activeObject;for(this.viewportTransform=t,i=0,r=this._objects.length;i\n'),this._setSVGObjects(i,e),this.clipPath&&i.push("\n"),this._setSVGBgOverlayColor(i,"overlayColor"),this._setSVGBgOverlayImage(i,"overlayImage",e),i.push(""),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,r=e.width||this.width,n=e.height||this.height,s='viewBox="0 0 '+this.width+" "+this.height+'" ',o=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?s='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,s='viewBox="'+a(-i[4]/i[0],o)+" "+a(-i[5]/i[3],o)+" "+a(this.width/i[0],o)+" "+a(this.height/i[3],o)+'" '),t.push(""),i.join("")},_setSVGPreamble:function(t,e){e.suppressPreamble||t.push('\n','\n')},_setSVGHeader:function(t,e){var i,r=e.width||this.width,n=e.height||this.height,s='viewBox="0 0 '+this.width+" "+this.height+'" ',o=fabric.Object.NUM_FRACTION_DIGITS;e.viewBox?s='viewBox="'+e.viewBox.x+" "+e.viewBox.y+" "+e.viewBox.width+" "+e.viewBox.height+'" ':this.svgViewportTransformation&&(i=this.viewportTransform,s='viewBox="'+a(-i[4]/i[0],o)+" "+a(-i[5]/i[3],o)+" "+a(this.width/i[0],o)+" "+a(this.height/i[3],o)+'" '),t.push("