diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9088c24..4bf91706 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,16 @@
+**Version 2.2.3**
+ - improvement: Allow to parse quoted url string. url('#myid') [#4881](https://github.com/kangax/fabric.js/pull/4881)
+ - improvement: text fromSVG import char-spacing attribute [#3718](https://github.com/kangax/fabric.js/pull/3718)
+ - fix: text toSVG export with multiple spaces in safari [#4880](https://github.com/kangax/fabric.js/pull/4880)
+ - fix: setSrc reset width and height on images [#4877](https://github.com/kangax/fabric.js/pull/4877)
+ - improvements: Removed forced origin swap when rotating [#4878](https://github.com/kangax/fabric.js/pull/4878)
+ - fix: Make the background of canvas cover all SVG in toSVG export [#4852](https://github.com/kangax/fabric.js/pull/4852)
+ - fix: Added startAngle to cacheProperties for fabric.Circle [#4875](https://github.com/kangax/fabric.js/pull/4875)
+ - fix: Rerender all the content of upperCanvas if canvas gets resized [#4850](https://github.com/kangax/fabric.js/pull/4850)
+ - fix: Remove references to context when disposing [#4846](https://github.com/kangax/fabric.js/pull/4846)
+ - improvements: Added single quoting to font names in toSVG [#4840](https://github.com/kangax/fabric.js/pull/4840)
+ - improvements: Added reserved space to wrapLine functionality [#4841](https://github.com/kangax/fabric.js/pull/4841)
+
**Version 2.2.2**
- Fixed: Applying filters to an image will invalidate its cache [#4828](https://github.com/kangax/fabric.js/pull/4828)
- Fixed: Attempt at fix font families that requires quoting [#4831](https://github.com/kangax/fabric.js/pull/4831)
diff --git a/HEADER.js b/HEADER.js
index 99febd68..1031cc02 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.2.2' };
+var fabric = fabric || { version: '2.2.3' };
if (typeof exports !== 'undefined') {
exports.fabric = fabric;
}
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
index c6195689..b402215f 100644
--- a/ISSUE_TEMPLATE.md
+++ b/ISSUE_TEMPLATE.md
@@ -25,7 +25,7 @@ Remove the template from below and provide thoughtful commentary *and code sampl
## Version
-2.0.2
+2.2.3
## Test Case
http://jsfiddle.net/fabricjs/Da7SP/
diff --git a/README.md b/README.md
index fe696178..43e282a1 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,6 @@
[](https://www.bountysource.com/trackers/23217-fabric-js?utm_source=23217&utm_medium=shield&utm_campaign=TRACKER_BADGE)
-[](https://gratipay.com/kangax/)
[](https://flattr.com/submit/auto?user_id=kangax&url=http://github.com/kangax/fabric.js&title=Fabric.js&language=&tags=github&category=software)
**Fabric.js** is a framework that makes it easy to work with HTML5 canvas element. It is an **interactive object model** on top of canvas element. It is also an **SVG-to-canvas parser**.
diff --git a/dist/fabric.js b/dist/fabric.js
index 304d2a19..18a5fe02 100644
--- a/dist/fabric.js
+++ b/dist/fabric.js
@@ -1,5 +1,5 @@
var fabric = fabric || {
- version: "2.2.2"
+ version: "2.2.3"
};
if (typeof exports !== "undefined") {
@@ -1806,6 +1806,7 @@ if (typeof console !== "undefined") {
"font-size": "fontSize",
"font-style": "fontStyle",
"font-weight": "fontWeight",
+ "letter-spacing": "charSpacing",
"paint-order": "paintFirst",
"stroke-dasharray": "strokeDashArray",
"stroke-linecap": "strokeLineCap",
@@ -1862,6 +1863,8 @@ if (typeof console !== "undefined") {
}
} else if (attr === "textAnchor") {
value = value === "start" ? "left" : value === "end" ? "right" : "center";
+ } else if (attr === "charSpacing") {
+ parsed = parseUnit(value, fontSize) / fontSize * 1e3;
} else if (attr === "paintFirst") {
var fillIndex = value.indexOf("fill");
var strokeIndex = value.indexOf("stroke");
@@ -2380,6 +2383,7 @@ fabric.ElementsParser = function(elements, callback, options, reviver, parsingOp
this.reviver = reviver;
this.svgUid = options && options.svgUid || 0;
this.parsingOptions = parsingOptions;
+ this.regexUrl = /^url\(['"]?#([^'"]+)['"]?\)/g;
};
fabric.ElementsParser.prototype.parse = function() {
@@ -2433,11 +2437,12 @@ fabric.ElementsParser.prototype.createCallback = function(index, el) {
};
fabric.ElementsParser.prototype.resolveGradient = function(obj, property) {
- var instanceFillValue = obj.get(property);
+ var instanceFillValue = obj[property];
if (!/^url\(/.test(instanceFillValue)) {
return;
}
- var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1);
+ var gradientId = this.regexUrl.exec(instanceFillValue)[1];
+ this.regexUrl.lastIndex = 0;
if (fabric.gradientDefs[this.svgUid][gradientId]) {
obj.set(property, fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][gradientId], obj));
}
@@ -3168,7 +3173,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
}
for (i = 0, len = colorStops.length; i < len; i++) {
var colorStop = colorStops[i];
- markup.push("\n');
+ markup.push("\n');
}
markup.push(this.type === "linear" ? "\n" : "\n");
return markup.join("");
@@ -3992,15 +3997,15 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
}
},
_setSVGBgOverlayColor: function(markup, property) {
- var filler = this[property];
+ var filler = this[property], vpt = this.viewportTransform, finalWidth = this.width / vpt[0], finalHeight = this.height / vpt[3];
if (!filler) {
return;
}
if (filler.toLive) {
var repeat = filler.repeat;
- markup.push('\n");
+ markup.push('\n");
} else {
- markup.push('\n");
+ markup.push('\n");
}
},
sendToBack: function(object) {
@@ -4135,6 +4140,10 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
return this.renderOnAddRemove && this.requestRenderAll();
},
dispose: function() {
+ if (this.isRendering) {
+ fabric.util.cancelAnimFrame(this.isRendering);
+ this.isRendering = 0;
+ }
this.forEachObject(function(object) {
object.dispose && object.dispose();
});
@@ -4143,7 +4152,7 @@ fabric.ElementsParser.prototype.checkIfDone = function() {
this.overlayImage = null;
this._iTextInstances = null;
this.lowerCanvasEl = null;
- this.cacheCanvasEl = null;
+ this.contextContainer = null;
return this;
},
toString: function() {
@@ -4689,19 +4698,23 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
this.clearContext(this.contextTop);
this.contextTopDirty = false;
}
- if (this.isDrawingMode && this._isCurrentlyDrawing) {
- this.freeDrawingBrush && this.freeDrawingBrush._render();
- }
+ this.renderTopLayer(this.contextTop);
var canvasToDrawOn = this.contextContainer;
this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());
return this;
},
- renderTop: function() {
- var ctx = this.contextTop;
- this.clearContext(ctx);
+ renderTopLayer: function(ctx) {
+ if (this.isDrawingMode && this._isCurrentlyDrawing) {
+ this.freeDrawingBrush && this.freeDrawingBrush._render();
+ }
if (this.selection && this._groupSelector) {
this._drawSelection(ctx);
}
+ },
+ renderTop: function() {
+ var ctx = this.contextTop;
+ this.clearContext(ctx);
+ this.renderTopLayer(ctx);
this.fire("after:render");
this.contextTopDirty = true;
return this;
@@ -4717,26 +4730,22 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
top: t.original.top
});
if (this._shouldCenterTransform(t.target)) {
- if (t.action === "rotate") {
- this._setOriginToCenter(t.target);
- } else {
- if (t.originX !== "center") {
- if (t.originX === "right") {
- t.mouseXSign = -1;
- } else {
- t.mouseXSign = 1;
- }
+ if (t.originX !== "center") {
+ if (t.originX === "right") {
+ t.mouseXSign = -1;
+ } else {
+ t.mouseXSign = 1;
}
- if (t.originY !== "center") {
- if (t.originY === "bottom") {
- t.mouseYSign = -1;
- } else {
- t.mouseYSign = 1;
- }
- }
- t.originX = "center";
- t.originY = "center";
}
+ if (t.originY !== "center") {
+ if (t.originY === "bottom") {
+ t.mouseYSign = -1;
+ } else {
+ t.mouseYSign = 1;
+ }
+ }
+ t.originX = "center";
+ t.originY = "center";
} else {
t.originX = t.original.originX;
t.originY = t.original.originY;
@@ -4861,8 +4870,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
ey: pointer.y,
lastX: pointer.x,
lastY: pointer.y,
- left: target.left,
- top: target.top,
theta: degreesToRadians(target.angle),
width: target.width * target.scaleX,
mouseXSign: 1,
@@ -4960,7 +4967,7 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
return skewed;
},
_scaleObject: function(x, y, by) {
- var t = this._currentTransform, target = t.target, lockScalingX = target.get("lockScalingX"), lockScalingY = target.get("lockScalingY"), lockScalingFlip = target.get("lockScalingFlip");
+ var t = this._currentTransform, target = t.target, lockScalingX = target.lockScalingX, lockScalingY = target.lockScalingY, lockScalingFlip = target.lockScalingFlip;
if (lockScalingX && lockScalingY) {
return false;
}
@@ -5062,13 +5069,13 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
}
},
_rotateObject: function(x, y) {
- var t = this._currentTransform;
- if (t.target.get("lockRotation")) {
+ var t = this._currentTransform, target = t.target, constraintPosition, constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY);
+ if (target.lockRotation) {
return false;
}
- var lastAngle = atan2(t.ey - t.top, t.ex - t.left), curAngle = atan2(y - t.top, x - t.left), angle = radiansToDegrees(curAngle - lastAngle + t.theta), hasRotated = true;
- if (t.target.snapAngle > 0) {
- var snapAngle = t.target.snapAngle, snapThreshold = t.target.snapThreshold || snapAngle, rightAngleLocked = Math.ceil(angle / snapAngle) * snapAngle, leftAngleLocked = Math.floor(angle / snapAngle) * snapAngle;
+ var lastAngle = atan2(t.ey - constraintPosition.y, t.ex - constraintPosition.x), curAngle = atan2(y - constraintPosition.y, x - constraintPosition.x), angle = radiansToDegrees(curAngle - lastAngle + t.theta), hasRotated = true;
+ if (target.snapAngle > 0) {
+ var snapAngle = target.snapAngle, snapThreshold = target.snapThreshold || snapAngle, rightAngleLocked = Math.ceil(angle / snapAngle) * snapAngle, leftAngleLocked = Math.floor(angle / snapAngle) * snapAngle;
if (Math.abs(angle - leftAngleLocked) < snapThreshold) {
angle = leftAngleLocked;
} else if (Math.abs(angle - rightAngleLocked) < snapThreshold) {
@@ -5079,10 +5086,11 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
angle = 360 + angle;
}
angle %= 360;
- if (t.target.angle === angle) {
+ if (target.angle === angle) {
hasRotated = false;
} else {
- t.target.angle = angle;
+ target.angle = angle;
+ target.setPositionByOrigin(constraintPosition, t.originX, t.originY);
}
return hasRotated;
},
@@ -5385,7 +5393,10 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
this.removeListeners();
wrapper.removeChild(this.upperCanvasEl);
wrapper.removeChild(this.lowerCanvasEl);
- delete this.upperCanvasEl;
+ this.upperCanvasEl = null;
+ this.cacheCanvasEl = null;
+ this.contextCache = null;
+ this.contextTop = null;
if (wrapper.parentNode) {
wrapper.parentNode.replaceChild(this.lowerCanvasEl, this.wrapperEl);
}
@@ -5709,7 +5720,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
target._scaling = false;
}
target.setCoords();
- this._restoreOriginXY(target);
if (transform.actionPerformed || this.stateful && target.hasStateChanged()) {
this.fire("object:modified", {
target: target,
@@ -5720,17 +5730,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
});
}
},
- _restoreOriginXY: function(target) {
- if (this._previousOriginX && this._previousOriginY) {
- var originPoint = target.translateToOriginPoint(target.getCenterPoint(), this._previousOriginX, this._previousOriginY);
- target.originX = this._previousOriginX;
- target.originY = this._previousOriginY;
- target.left = originPoint.x;
- target.top = originPoint.y;
- this._previousOriginX = null;
- this._previousOriginY = null;
- }
- },
_onMouseDownInDrawingMode: function(e) {
this._isCurrentlyDrawing = true;
if (this.getActiveObject()) {
@@ -5815,26 +5814,6 @@ fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, {
this.onBeforeScaleRotate(target);
}
},
- _setOriginToCenter: function(target) {
- this._previousOriginX = this._currentTransform.target.originX;
- this._previousOriginY = this._currentTransform.target.originY;
- var center = target.getCenterPoint();
- target.originX = "center";
- target.originY = "center";
- target.left = center.x;
- target.top = center.y;
- this._currentTransform.left = target.left;
- this._currentTransform.top = target.top;
- },
- _setCenterToOrigin: function(target) {
- var originPoint = target.translateToOriginPoint(target.getCenterPoint(), this._previousOriginX, this._previousOriginY);
- target.originX = this._previousOriginX;
- target.originY = this._previousOriginY;
- target.left = originPoint.x;
- target.top = originPoint.y;
- this._previousOriginX = null;
- this._previousOriginY = null;
- },
__onMouseMove: function(e) {
var target, pointer;
if (this.isDrawingMode) {
@@ -7498,7 +7477,9 @@ fabric.util.object.extend(fabric.Object.prototype, {
return [ stroke, "stroke-width: ", strokeWidth, "; ", "stroke-dasharray: ", strokeDashArray, "; ", "stroke-linecap: ", strokeLineCap, "; ", "stroke-linejoin: ", strokeLineJoin, "; ", "stroke-miterlimit: ", strokeMiterLimit, "; ", fill, "fill-rule: ", fillRule, "; ", "opacity: ", opacity, ";", filter, visibility ].join("");
},
getSvgSpanStyles: function(style, useWhiteSpace) {
- var term = "; ", strokeWidth = style.strokeWidth ? "stroke-width: " + style.strokeWidth + term : "", fontFamily = style.fontFamily ? "font-family: " + style.fontFamily.replace(/"/g, "'") + term : "", fontSize = style.fontSize ? "font-size: " + style.fontSize + "px" + term : "", fontStyle = style.fontStyle ? "font-style: " + style.fontStyle + term : "", fontWeight = style.fontWeight ? "font-weight: " + style.fontWeight + term : "", fill = style.fill ? getSvgColorString("fill", style.fill) : "", stroke = style.stroke ? getSvgColorString("stroke", style.stroke) : "", textDecoration = this.getSvgTextDecoration(style), deltaY = style.deltaY ? "baseline-shift: " + -style.deltaY + "; " : "";
+ var term = "; ";
+ var fontFamily = style.fontFamily ? "font-family: " + (style.fontFamily.indexOf("'") === -1 && style.fontFamily.indexOf('"') === -1 ? "'" + style.fontFamily + "'" : style.fontFamily) + term : "";
+ var strokeWidth = style.strokeWidth ? "stroke-width: " + style.strokeWidth + term : "", fontFamily = fontFamily, fontSize = style.fontSize ? "font-size: " + style.fontSize + "px" + term : "", fontStyle = style.fontStyle ? "font-style: " + style.fontStyle + term : "", fontWeight = style.fontWeight ? "font-weight: " + style.fontWeight + term : "", fill = style.fill ? getSvgColorString("fill", style.fill) : "", stroke = style.stroke ? getSvgColorString("stroke", style.stroke) : "", textDecoration = this.getSvgTextDecoration(style), deltaY = style.deltaY ? "baseline-shift: " + -style.deltaY + "; " : "";
if (textDecoration) {
textDecoration = "text-decoration: " + textDecoration + term;
}
@@ -8089,7 +8070,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
radius: 0,
startAngle: 0,
endAngle: pi * 2,
- cacheProperties: fabric.Object.prototype.cacheProperties.concat("radius"),
+ cacheProperties: fabric.Object.prototype.cacheProperties.concat("radius", "startAngle", "endAngle"),
_set: function(key, value) {
this.callSuper("_set", key, value);
if (key === "radius") {
@@ -9542,6 +9523,7 @@ fabric.util.object.extend(fabric.Object.prototype, {
setSrc: function(src, callback, options) {
fabric.util.loadImage(src, function(img) {
this.setElement(img, options);
+ this._setWidthHeight();
callback(this);
}, this, options && options.crossOrigin);
return this;
@@ -9651,8 +9633,8 @@ fabric.util.object.extend(fabric.Object.prototype, {
}
},
_setWidthHeight: function(options) {
- this.width = "width" in options ? options.width : this.getElement() ? this.getElement().width || 0 : 0;
- this.height = "height" in options ? options.height : this.getElement() ? this.getElement().height || 0 : 0;
+ this.width = options && "width" in options ? options.width : this.getElement() ? this.getElement().width || 0 : 0;
+ this.height = options && "height" in options ? options.height : this.getElement() ? this.getElement().height || 0 : 0;
},
parsePreserveAspectRatioAttribute: function() {
var pAR = fabric.util.parsePreserveAspectRatioAttribute(this.preserveAspectRatio || ""), rWidth = this._element.width, rHeight = this._element.height, scaleX = 1, scaleY = 1, offsetLeft = 0, offsetTop = 0, cropX = 0, cropY = 0, offset, pWidth = this.width, pHeight = this.height, parsedAttributes = {
@@ -12053,7 +12035,7 @@ fabric.Image.filters.BaseFilter.fromObject = function(object, callback) {
return 1;
}
});
- fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat("x y dx dy font-family font-style font-weight font-size text-decoration text-anchor".split(" "));
+ fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat("x y dx dy font-family font-style font-weight font-size letter-spacing text-decoration text-anchor".split(" "));
fabric.Text.DEFAULT_SVG_FONT_SIZE = 16;
fabric.Text.fromElement = function(element, callback, options) {
if (!element) {
@@ -13653,7 +13635,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
});
(function() {
- var toFixed = fabric.util.toFixed;
+ var toFixed = fabric.util.toFixed, multipleSpacesRegex = / +/g;
fabric.util.object.extend(fabric.Text.prototype, {
toSVG: function(reviver) {
var markup = this._createBaseSVGMarkup(), offsets = this._getSVGLeftTopOffsets(), textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);
@@ -13688,7 +13670,7 @@ fabric.util.object.extend(fabric.IText.prototype, {
};
},
_createTextCharSpan: function(_char, styleDecl, left, top) {
- var styleProps = this.getSvgSpanStyles(styleDecl, _char !== _char.trim()), fillStyles = styleProps ? 'style="' + styleProps + '"' : "", dy = styleDecl.deltaY, dySpan = "", NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
+ var shouldUseWhitespace = _char !== _char.trim() || _char.match(multipleSpacesRegex), styleProps = this.getSvgSpanStyles(styleDecl, shouldUseWhitespace), fillStyles = styleProps ? 'style="' + styleProps + '"' : "", dy = styleDecl.deltaY, dySpan = "", NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;
if (dy) {
dySpan = ' dy="' + toFixed(dy, NUM_FRACTION_DIGITS) + '" ';
}
@@ -13913,8 +13895,9 @@ fabric.util.object.extend(fabric.IText.prototype, {
}
return width;
},
- _wrapLine: function(_line, lineIndex, desiredWidth) {
- var lineWidth = 0, graphemeLines = [], line = [], words = _line.split(this._reSpaceAndTab), word = "", offset = 0, infix = " ", wordWidth = 0, infixWidth = 0, largestWordWidth = 0, lineJustStarted = true, additionalSpace = this._getWidthOfCharSpacing();
+ _wrapLine: function(_line, lineIndex, desiredWidth, reservedSpace) {
+ var lineWidth = 0, graphemeLines = [], line = [], words = _line.split(this._reSpaceAndTab), word = "", offset = 0, infix = " ", wordWidth = 0, infixWidth = 0, largestWordWidth = 0, lineJustStarted = true, additionalSpace = this._getWidthOfCharSpacing(), reservedSpace = reservedSpace || 0;
+ desiredWidth -= reservedSpace;
for (var i = 0; i < words.length; i++) {
word = fabric.util.string.graphemeSplit(words[i]);
wordWidth = this._measureWord(word, lineIndex, offset);
@@ -13940,8 +13923,8 @@ fabric.util.object.extend(fabric.IText.prototype, {
}
}
i && graphemeLines.push(line);
- if (largestWordWidth > this.dynamicMinWidth) {
- this.dynamicMinWidth = largestWordWidth - additionalSpace;
+ if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {
+ this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;
}
return graphemeLines;
},
diff --git a/dist/fabric.min.js b/dist/fabric.min.js
index ab1e7e75..e16458d9 100644
--- a/dist/fabric.min.js
+++ b/dist/fabric.min.js
@@ -1 +1 @@
-var fabric=fabric||{version:"2.2.2"};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 h=new ImageData(a,r,n);i.putImageData(h,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"],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.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,"")));e&&e.documentElement||n&&n(null);x.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 x.window.ActiveXObject&&((r=new ActiveXObject("Microsoft.XMLDOM")).async="false",r.loadXML(t.replace(//i,"")));x.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},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,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 h=s/a,c=o/a;0<=h&&h<=1&&0<=c&&c<=1?(n=new d("Intersection")).appendPoint(new f.Point(t.x+h*(e.x-t.x),t.y+h*(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,h=i.length;for(o=0;os.r2,h=t.width/2,c=t.height/2;for(var l in o.sort(function(t,e){return t.offset-e.offset}),"path"===t.type&&(h-=t.pathOffset.x,c-=t.pathOffset.y),s)"x1"===l||"x2"===l?s[l]+=this.offsetX-h:"y1"!==l&&"y2"!==l||(s[l]+=this.offsetY-c);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 s=t.fabric||(t.fabric={}),o=s.util.toFixed;s.Shadow?s.warn("fabric.Shadow is already defined."):(s.Shadow=s.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=s.Object.__uid++},_parseShadow:function(t){var e=t.trim(),i=s.Shadow.reOffsetsAndBlur.exec(e)||[];return{color:(e.replace(s.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=s.Object.NUM_FRACTION_DIGITS,n=s.util.rotateVector({x:this.offsetX,y:this.offsetY},s.util.degreesToRadians(-t.angle));return t.width&&t.height&&(e=100*o((Math.abs(n.x)+this.blur)/t.width,r)+20,i=100*o((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=s.Shadow.prototype;return["color","blur","offsetX","offsetY","affectStroke"].forEach(function(t){this[t]!==i[t]&&(e[t]=this[t])},this),e}}),s.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 r=fabric.util.object.extend,t=fabric.util.getElementOffset,c=fabric.util.removeFromArray,a=fabric.util.toFixed,s=fabric.util.transformPoint,o=fabric.util.invertTransform,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,_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(e,t,i,r){return"string"==typeof t?fabric.util.loadImage(t,function(t){t&&(this[e]=new fabric.Image(t,r)),i&&i(t)},this,r&&r.crossOrigin):(r&&t.setOptions(r),this[e]=t,i&&i(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=fabric.util.createCanvasElement();if(!t)throw e;if(t.style||(t.style={}),void 0===t.getContext)throw e;return t},_initOptions:function(t){this._setOptions(t),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){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"),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"),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("