diff --git a/js/fabric-v1.7.22.js b/js/fabric-v1.7.22.js index f399de64..1735ce79 100644 --- a/js/fabric-v1.7.22.js +++ b/js/fabric-v1.7.22.js @@ -14327,6 +14327,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati else { return this.minScaleLimit; } + } else if (value !== value) { + return this.minScaleLimit; + } else if (value === 0) { + return 1e-4; } return value; }, diff --git a/js/fabric-v1.7.22.min.js b/js/fabric-v1.7.22.min.js index 29af01c7..2851451d 100644 --- a/js/fabric-v1.7.22.min.js +++ b/js/fabric-v1.7.22.min.js @@ -1 +1,555 @@ -var fabric=fabric||{version:"1.7.22"};"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(decodeURIComponent("%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E")),fabric.document.createWindow?fabric.window=fabric.document.createWindow():fabric.window=fabric.document.parentWindow),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"],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.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)}},fabric.CommonMethods={_setOptions:function(t){for(var e in t)this.set(e,t[e])},_initGradient:function(t,e){!t||!t.colorStops||t instanceof fabric.Gradient||this.set(e,new fabric.Gradient(t))},_initPattern:function(t,e,i){!t||!t.source||t instanceof fabric.Pattern?i&&i():this.set(e,new fabric.Pattern(t,i))},_initClipping:function(t){if(t.clipTo&&"string"==typeof t.clipTo){var e=fabric.util.getFunctionBody(t.clipTo);void 0!==e&&(this.clipTo=new Function("ctx",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,e){this[t]=e},toggle:function(t){var e=this.get(t);return"boolean"==typeof e&&this.set(t,!e),this},get:function(t){return this[t]}},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-1!==i&&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);return{x:t.x*r-t.y*i,y:t.x*i+t.y*r}},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);return{left:i,top:o,width:n,height:Math.abs(o-a)}},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])>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--;)n="set"+(r=(i=o.stateProperties[e]).charAt(0).toUpperCase()+i.slice(1)),o[s="get"+r]||(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?P-=2*f:1===c&&P<0&&(P+=2*f);for(var E=Math.ceil(Math.abs(P/f*2)),I=[],L=P/E,F=8/3*Math.sin(L/4)*Math.sin(L/4)/Math.sin(L/2),B=A+L,R=0;R=n?s-n:2*Math.PI-(n-s)}function i(t,e,i,r,n,a,h,c){var l=o.call(arguments);if(s[l])return s[l];var u,f,d,g,p,v,b,m,_=Math.sqrt,y=Math.min,x=Math.max,C=Math.abs,S=[],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*a,u=-3*e+9*r-9*a+3*c,d=3*r-3*e),C(u)<1e-12){if(C(f)<1e-12)continue;0<(g=-d/f)&&g<1&&S.push(g)}else(b=f*f-4*d*u)<0||(0<(p=(-f+(m=_(b)))/(2*u))&&p<1&&S.push(p),0<(v=(-f-m)/(2*u))&&v<1&&S.push(v));for(var T,j,k,M=S.length,D=M;M--;)T=(k=1-(g=S[M]))*k*k*t+3*k*k*g*i+3*k*g*g*n+g*g*g*h,w[0][M]=T,j=k*k*k*e+3*k*k*g*r+3*k*g*g*a+g*g*g*c,w[1][M]=j;w[0][D]=t,w[1][D]=e,w[0][D+1]=h,w[1][D+1]=c;var A=[{x:y.apply(null,w[0]),y:y.apply(null,w[1])},{x:x.apply(null,w[0]),y:x.apply(null,w[1])}];return s[l]=A,A}var r={},n={},s={},o=Array.prototype.join;fabric.util.drawArc=function(e,i,r,n){for(var s=n[0],o=n[1],a=n[2],h=n[3],c=n[4],l=[[],[],[],[]],u=t(n[5]-i,n[6]-r,s,o,h,c,a),f=0,d=u.length;f>>0;if(0===i)return-1;var r=0;if(arguments.length>0&&((r=Number(arguments[1]))!=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=e})}}}(),function(){function t(e,i,r){if(r)if(!fabric.isLikelyNode&&i instanceof Element)e=i;else if(i instanceof Array){e=[];for(var n=0,s=i.length;n/g,">")}}}(),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){for(var e=null,r=this;r.constructor.superclass;){var n=r.constructor.superclass.prototype[t];if(r[t]!==n){e=n;break}r=r.constructor.superclass.prototype}return e?arguments.length>1?e.apply(this,i.call(arguments,1)):e.call(this):console.log("tried to callSuper "+t+", method not found in prototype chain",this)}var i=Array.prototype.slice,r=function(){},n=function(){for(var t in{toString:1})if("toString"===t)return!1;return!0}(),s=function(t,e,i){for(var r in e)r in t.prototype&&"function"==typeof t.prototype[r]&&(e[r]+"").indexOf("callSuper")>-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],n&&(e.toString!==Object.prototype.toString&&(t.prototype.toString=e.toString),e.valueOf!==Object.prototype.valueOf&&(t.prototype.valueOf=e.valueOf))};fabric.util.createClass=function(){function n(){this.initialize.apply(this,arguments)}var o=null,a=i.call(arguments,0);"function"==typeof a[0]&&(o=a.shift()),n.superclass=o,n.subclasses=[],o&&(t.prototype=o.prototype,n.prototype=new t,o.subclasses.push(n));for(var h=0,c=a.length;h=.9999?"":"alpha(opacity="+100*e+")",i.filter=i.filter.replace(r,e)):i.filter+=" alpha(opacity="+100*e+")",t}),fabric.util.setStyle=function(t,e){var i=t.style;if(!i)return t;if("string"==typeof e)return t.style.cssText+=";"+e,e.indexOf("opacity")>-1?n(t,e.match(/opacity:\s*(\d?\.?\d*)/)[1]):t;for(var r in e)"opacity"===r?n(t,e[r]):i["float"===r||"cssFloat"===r?void 0===i.styleFloat?"cssFloat":"styleFloat":r]=e[r];return t}}(),function(){function t(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 e(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)===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}}var i,r=Array.prototype.slice,n=function(t){return r.call(t,0)};try{i=n(fabric.document.childNodes)instanceof Array}catch(t){}i||(n=function(t){for(var e=new Array(t.length),i=t.length;i--;)e[i]=t[i];return e});var s;s=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(){var t=fabric.document.documentElement.style,e="userSelect"in t?"userSelect":"MozUserSelect"in t?"MozUserSelect":"WebkitUserSelect"in t?"WebkitUserSelect":"KhtmlUserSelect"in t?"KhtmlUserSelect":"";fabric.util.makeElementUnselectable=function(t){return void 0!==t.onselectstart&&(t.onselectstart=fabric.util.falseFunction),e?t.style[e]="none":"string"==typeof t.unselectable&&(t.unselectable="on"),t},fabric.util.makeElementSelectable=function(t){return void 0!==t.onselectstart&&(t.onselectstart=null),e?t.style[e]="":"string"==typeof t.unselectable&&(t.unselectable=""),t}}(),function(){fabric.util.getScript=function(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.getById=function(t){return"string"==typeof t?fabric.document.getElementById(t):t},fabric.util.toArray=n,fabric.util.makeElement=t,fabric.util.addClass=function(t,e){t&&-1===(" "+t.className+" ").indexOf(" "+e+" ")&&(t.className+=(t.className?" ":"")+e)},fabric.util.wrapElement=function(e,i,r){return"string"==typeof i&&(i=t(i,r)),e.parentNode&&e.parentNode.replaceChild(i,e),i.appendChild(e),i},fabric.util.getScrollLeftTop=e,fabric.util.getElementOffset=function(t){var i,r,n=t&&t.ownerDocument,o={left:0,top:0},a={left:0,top:0},h={borderLeftWidth:"left",borderTopWidth:"top",paddingLeft:"left",paddingTop:"top"};if(!n)return a;for(var c in h)a[h[c]]+=parseInt(s(t,c),10)||0;return i=n.documentElement,void 0!==t.getBoundingClientRect&&(o=t.getBoundingClientRect()),r=e(t),{left:o.left+r.left-(i.clientLeft||0)+a.left,top:o.top+r.top-(i.clientTop||0)+a.top}},fabric.util.getElementStyle=s}(),function(){function t(){}var e=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{if(t[e]())return t[e]}catch(t){}}();fabric.util.request=function(i,r){r||(r={});var n=r.method?r.method.toUpperCase():"GET",s=r.onComplete||function(){},o=e(),a=r.body||r.parameters;return o.onreadystatechange=function(){4===o.readyState&&(s(o),o.onreadystatechange=t)},"GET"===n&&(a=null,"string"==typeof r.parameters&&(i=function(t,e){return t+(/\?/.test(t)?"&":"?")+e}(i,r.parameters))),o.open(n,i,!0),"POST"!==n&&"PUT"!==n||o.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),o.send(a),o}}(),fabric.log=function(){},fabric.warn=function(){},"undefined"!=typeof console&&["log","warn"].forEach(function(t){void 0!==console[t]&&"function"==typeof console[t].apply&&(fabric[t]=function(){return console[t].apply(console,arguments)})}),function(){function t(){return!1}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=function(i){e(function(r){i||(i={});var n,s=r||+new Date,o=i.duration||500,a=s+o,h=i.onChange||t,c=i.abort||t,l=i.onComplete||t,u=i.easing||function(t,e,i,r){return-i*Math.cos(t/r*(Math.PI/2))+i+e},f="startValue"in i?i.startValue:0,d="endValue"in i?i.endValue:100,g=i.byValue||d-f;i.onStart&&i.onStart(),function t(r){if(c())l(d,1,1);else{var p=(n=r||+new Date)>a?o:n-s,v=p/o,b=u(p,f,g,o),m=Math.abs((b-f)/g);h(b,m,v),n>a?i.onComplete&&i.onComplete():e(t)}}(s)})},fabric.util.requestAnimFrame=e}(),function(){fabric.util.animateColor=function(t,e,i,r){var n=new fabric.Color(t).getSource(),s=new fabric.Color(e).getSource();r=r||{},fabric.util.animate(fabric.util.object.extend(r,{duration:i||500,startValue:n,endValue:s,byValue:s,easing:function(t,e,i,n){return function(t,e,i){var r="rgba("+parseInt(t[0]+i*(e[0]-t[0]),10)+","+parseInt(t[1]+i*(e[1]-t[1]),10)+","+parseInt(t[2]+i*(e[2]-t[2]),10);return r+=","+(t&&e?parseFloat(t[3]+i*(e[3]-t[3])):1),r+=")"}(e,i,r.colorEasing?r.colorEasing(t,n):1-Math.cos(t/n*(Math.PI/2)))}}))}}(),function(){function t(t,e,i,r){return ta?a:o),1===o&&1===a&&0===c&&0===l&&0===g&&0===v)return C;if((g||v)&&(S=" translate("+f(g)+" "+f(v)+") "),r=S+" matrix("+o+" 0 0 "+a+" "+c*o+" "+l*a+") ","svg"===t.nodeName){for(n=t.ownerDocument.createElement("g");t.firstChild;)n.appendChild(t.firstChild);t.appendChild(n)}else r=(n=t).getAttribute("transform")+r;return n.setAttribute("transform",r),C}var h=t.fabric||(t.fabric={}),c=h.util.object.extend,l=h.util.object.clone,u=h.util.toFixed,f=h.util.parseUnit,d=h.util.multiplyTransformMatrices,g=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i,p=/^(symbol|image|marker|pattern|view|svg)$/i,v=/^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i,b=/^(symbol|g|a|svg)$/i,m={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",opacity:"opacity"},_={stroke:"strokeOpacity",fill:"fillOpacity"};h.cssRules={},h.gradientDefs={},h.parseTransformAttribute=function(){function t(t,e,i){t[i]=Math.tan(h.util.degreesToRadians(e[0]))}var e=[1,0,0,1,0,0],i=h.reNum,r="(?:\\s+,?\\s*|,\\s*)",n="(?:"+("(?:(matrix)\\s*\\(\\s*("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")\\s*\\))")+"|"+("(?:(translate)\\s*\\(\\s*("+i+")(?:"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(scale)\\s*\\(\\s*("+i+")(?:"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(rotate)\\s*\\(\\s*("+i+")(?:"+r+"("+i+")"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(skewX)\\s*\\(\\s*("+i+")\\s*\\))")+"|"+("(?:(skewY)\\s*\\(\\s*("+i+")\\s*\\))")+")",s="^\\s*(?:"+("(?:"+n+"(?:"+r+"*"+n+")*)")+"?)\\s*$",o=new RegExp(s),a=new RegExp(n,"g");return function(i){var r=e.concat(),s=[];if(!i||i&&!o.test(i))return r;i.replace(a,function(i){var o=new RegExp(n).exec(i).filter(function(t){return!!t}),a=o[1],c=o.slice(2).map(parseFloat);switch(a){case"translate":!function(t,e){t[4]=e[0],2===e.length&&(t[5]=e[1])}(r,c);break;case"rotate":c[0]=h.util.degreesToRadians(c[0]),function(t,e){var i=Math.cos(e[0]),r=Math.sin(e[0]),n=0,s=0;3===e.length&&(n=e[1],s=e[2]),t[0]=i,t[1]=r,t[2]=-r,t[3]=i,t[4]=n-(i*n-r*s),t[5]=s-(r*n+i*s)}(r,c);break;case"scale":!function(t,e){var i=e[0],r=2===e.length?e[1]:e[0];t[0]=i,t[3]=r}(r,c);break;case"skewX":t(r,c,2);break;case"skewY":t(r,c,1);break;case"matrix":r=c}s.push(r.concat()),r=e.concat()});for(var c=s[0];s.length>1;)s.shift(),c=h.util.multiplyTransformMatrices(c,s[0]);return c}}();var y=new RegExp("^\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*$");h.parseSVGDocument=function(t,e,i,n){if(t){!function(t){for(var e=r(t,["use","svg:use"]),i=0;e.length&&i/i,""))),n&&n.documentElement||e&&e(null),h.parseSVGDocument(n.documentElement,function(t,i){e&&e(t,i)},i,r)}})},loadSVGFromString:function(t,e,i,r){t=t.trim();var n;if("undefined"!=typeof DOMParser){var s=new DOMParser;s&&s.parseFromString&&(n=s.parseFromString(t,"text/xml"))}else h.window.ActiveXObject&&((n=new ActiveXObject("Microsoft.XMLDOM")).async="false",n.loadXML(t.replace(//i,"")));h.parseSVGDocument(n.documentElement,function(t,i){e(t,i)},i,r)}})}("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,i){return void 0===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={});i.Intersection?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")).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},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={});r.Color?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,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}var i=fabric.util.object.clone;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:parseFloat(e),color:i.toRgb(),opacity:i.getAlpha()})}return this},toObject:function(t){var e={type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY,gradientTransform:this.gradientTransform?this.gradientTransform.concat():this.gradientTransform};return fabric.util.populateWithProperties(this,e,t),e},toSVG:function(t){var e,r,n=i(this.coords,!0),s=i(this.colorStops,!0),o=n.r1>n.r2;if(s.sort(function(t,e){return t.offset-e.offset}),!t.group||"path-group"!==t.group.type)for(var a in n)"x1"===a||"x2"===a?n[a]+=this.offsetX-t.width/2:"y1"!==a&&"y2"!==a||(n[a]+=this.offsetY-t.height/2);if(r='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"',this.gradientTransform&&(r+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" '),"linear"===this.type?e=["\n']:"radial"===this.type&&(e=["\n']),"radial"===this.type){if(o){(s=s.concat()).reverse();for(l=0;l0)for(var c=h/Math.max(n.r1,n.r2),l=0;l\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'},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 e=t.fabric||(t.fabric={}),i=e.util.toFixed;e.Shadow?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)||[];return{color:(i.replace(e.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").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));return t.width&&t.height&&(r=100*i((Math.abs(o.x)+this.blur)/t.width,s)+20,n=100*i((Math.abs(o.y)+this.blur)/t.height,s)+20),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}}),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)fabric.warn("fabric.StaticCanvas is already defined.");else{var t=fabric.util.object.extend,e=fabric.util.getElementOffset,i=fabric.util.removeFromArray,r=fabric.util.toFixed,n=fabric.util.transformPoint,s=fabric.util.invertTransform,o=new Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(t,e){e||(e={}),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:!1,_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){return this[t]=e,this._initGradient(e,t),this._initPattern(e,t,i),this},_createCanvasElement:function(t){var e=fabric.util.createCanvasElement(t);if(e.style||(e.style={}),!e)throw o;if(void 0===e.getContext)throw o;return e},_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){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 this.viewportTransform[0]},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","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),"\n")},createSVGRefElementsMarkup:function(){var t=this;return["backgroundColor","overlayColor"].map(function(e){var i=t[e];if(i&&i.toLive)return i.toSVG(t,!1)}).join("")},createSVGFontFacesMarkup:function(){for(var t,e,i,r,n,s,o="",a={},h=fabric.fontPaths,c=this.getObjects(),l=0,u=c.length;l',"\n",o,"","\n"].join("")),o},_setSVGObjects:function(t,e){for(var i,r=0,n=this.getObjects(),s=n.length;r\n")}else t.push('\n")},sendToBack:function(t){if(!t)return this;var e,r,n,s=this._activeGroup;if(t===s)for(e=(n=s._objects).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;e0+c&&(o=s-1,i(this._objects,n),this._objects.splice(o,0,n)),c++;else 0!==(s=this._objects.indexOf(t))&&(o=this._findNewLowerIndex(t,s,e),i(this._objects,t),this._objects.splice(o,0,t));return this.renderAll&&this.renderAll(),this},_findNewLowerIndex:function(t,e,i){var r;if(i){r=e;for(var n=e-1;n>=0;--n){if(t.intersectsWithObject(this._objects[n])||t.isContainedWithinObject(this._objects[n])||this._objects[n].isContainedWithinObject(t)){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,c=0;if(t===h)for(r=(a=h._objects).length;r--;)n=a[r],(s=this._objects.indexOf(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 void 0!==i.getImageData;case"setLineDash":return void 0!==i.setLineDash;case"toDataURL":return void 0!==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,e=this.canvas.getZoom();t.shadowColor=this.shadow.color,t.shadowBlur=this.shadow.blur*e,t.shadowOffsetX=this.shadow.offsetX*e,t.shadowOffsetY=this.shadow.offsetY*e}},_resetShadow:function(){var t=this.canvas.contextTop;t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0}}),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.length>1&&t.eq(this._points[this._points.length-1])||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,e,i=this.canvas.contextTop,r=this.canvas.viewportTransform,n=this._points[0],s=this._points[1];if(i.save(),i.transform(r[0],r[1],r[2],r[3],r[4],r[5]),i.beginPath(),2===this._points.length&&n.x===s.x&&n.y===s.y){var o=this.width/1e3;n=new fabric.Point(n.x,n.y),s=new fabric.Point(s.x,s.y),n.x-=o,s.x+=o}for(i.moveTo(n.x,n.y),t=1,e=this._points.length;t2;for(c&&(a=t[2].xt[e-2].x?1:n.x===t[e-2].x?0:-1,h=n.y>t[e-2].y?1:n.y===t[e-2].y?0:-1),i.push("L ",n.x+a*r," ",n.y+h*r),i},createPath:function(t){var e=new fabric.Path(t,{fill:null,stroke:this.color,strokeWidth:this.width,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeDashArray:this.strokeDashArray,originX:"center",originY:"center"}),i=new fabric.Point(e.left,e.top);return e.originX=fabric.Object.prototype.originX,e.originY=fabric.Object.prototype.originY,i=e.translateToGivenOrigin(i,"center","center",e.originX,e.originY),e.top=i.y,e.left=i.x,this.shadow&&(this.shadow.affectStroke=!0,e.setShadow(this.shadow)),e},_finalizeAndAddPath:function(){this.canvas.contextTop.closePath();var t=this.convertPointsToSVGPath(this._points).join("");if("M 0 0 Q 0 0 0 0 L 0 0"!==t){var e=this.createPath(t);this.canvas.add(e),e.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire("path:created",{path:e})}else this.canvas.renderAll()}}),fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(t){this.canvas=t,this.points=[]},drawDot:function(t){var e=this.addPoint(t),i=this.canvas.contextTop,r=this.canvas.viewportTransform;i.save(),i.transform(r[0],r[1],r[2],r[3],r[4],r[5]),i.fillStyle=e.fill,i.beginPath(),i.arc(e.x,e.y,e.radius,0,2*Math.PI,!1),i.closePath(),i.fill(),i.restore()},onMouseDown:function(t){this.points.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.drawDot(t)},onMouseMove:function(t){this.drawDot(t)},onMouseUp:function(){var t=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var e=[],i=0,r=this.points.length;i0?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])<=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&&cs?t.x<0?t.x+=s:t.x-=s:t.x=0,n(t.y)>s?t.y<0?t.y+=s:t.y-=s: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),h=!0;if(n.target.snapAngle>0){var c=n.target.snapAngle,l=n.target.snapThreshold||c,u=Math.ceil(a/c)*c,f=Math.floor(a/c)*c;Math.abs(a-f)0?0:-i),e.ey-(r>0?0:-r),o,a)),this.selectionLineWidth&&this.selectionBorderColor)if(t.lineWidth=this.selectionLineWidth,t.strokeStyle=this.selectionBorderColor,this.selectionDashArray.length>1&&!s){var h=e.ex+.5-(i>0?0:o),c=e.ey+.5-(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 fabric.Object.prototype._setLineDash.call(this,t,this.selectionDashArray),t.strokeRect(e.ex+.5-(i>0?0:o),e.ey+.5-(r>0?0:a),o,a)},findTarget:function(t,e){if(!this.skipTargetFind){var i,r,n=this.getPointer(t,!0),s=this.getActiveGroup(),o=this.getActiveObject();if(this.targets=[],s&&!e&&s===this._searchPossibleTargets([s],n))return this._fireOverOutEvents(s,t),s;if(o&&o._findTargetCorner(n))return this._fireOverOutEvents(o,t),o;if(o&&o===this._searchPossibleTargets([o],n)){if(!this.preserveObjectStacking)return this._fireOverOutEvents(o,t),o;i=o,r=this.targets,this.targets=[]}var a=this._searchPossibleTargets(this._objects,n);return t[this.altSelectionKey]&&a&&i&&a!==i&&(a=i,this.targets=r),this._fireOverOutEvents(a,t),a}},_fireOverOutEvents:function(t,e){var i,r,n=this._hoveredTarget;n!==t&&(i={e:e,target:t,previousTarget:this._hoveredTarget},r={e:e,target:this._hoveredTarget,nextTarget:t},this._hoveredTarget=t),t?n!==t&&(n&&(this.fire("mouse:out",r),n.fire("mouseout",r)),this.fire("mouse:over",i),t.fire("mouseover",i)):n&&(this.fire("mouse:out",r),n.fire("mouseout",r))},_checkTarget:function(t,e){if(e&&e.visible&&e.evented&&this.containsPoint(null,e,t)){if(!this.perPixelTargetFind&&!e.perPixelTargetFind||e.isEditing)return!0;if(!this.isTargetTransparent(e,t.x,t.y))return!0}},_searchPossibleTargets:function(t,e){for(var i,r,n,s=t.length;s--;)if(this._checkTarget(e,t[s])){"group"===(i=t[s]).type&&i.subTargetCheck&&(r=this._normalizePointer(i,e),(n=this._searchPossibleTargets(i._objects,r))&&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.upperCanvasEl.className="":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,"touch-action":"none"}),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){var e=this._activeObject;e&&(e.set("active",!1),t!==e&&e.onDeselect&&"function"==typeof e.onDeselect&&e.onDeselect()),this._activeObject=t,t.set("active",!0)},setActiveObject:function(t,e){var i=this.getActiveObject();return i&&i!==t&&i.fire("deselected",{e:e}),this._setActiveObject(t),this.fire("object:selected",{target:t,e:e}),t.fire("selected",{e:e}),this.renderAll(),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._hoveredTarget===t&&(this._hoveredTarget=null),this.callSuper("_onObjectRemoved",t)},_discardActiveObject:function(){var t=this._activeObject;t&&(t.set("active",!1),t.onDeselect&&"function"==typeof t.onDeselect&&t.onDeselect()),this._activeObject=null},discardActiveObject:function(t){var e=this._activeObject;return e&&(this.fire("before:selection:cleared",{target:e,e:t}),this._discardActiveObject(),this.fire("selection:cleared",{e:t}),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 e&&(this.fire("before:selection:cleared",{e:t,target:e}),this._discardActiveGroup(),this.fire("selection:cleared",{e:t})),this},deactivateAll:function(){for(var t,e=this.getObjects(),i=0,r=e.length;i1)){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||null)}},__onMouseWheel:function(t){this._handleEvent(t,"wheel")},_transformObject:function(t){var e=this.getPointer(t),i=this._currentTransform;i.reset=!1,i.target.isMoving=!0,i.shiftKey=t.shiftKey,i.altKey=t[this.centeredKey],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))&&(this._fire("moving",s,t),this.setCursor(s.moveCursor||this.moveCursor)),e.actionPerformed=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,r=this.getActiveGroup(),n=e._findTargetCorner&&(!r||!r.contains(e))&&e._findTargetCorner(this.getPointer(t,!0));return n?this._setCornerCursor(n,e,t):this.setCursor(i),!0},_setCornerCursor:function(t,i,r){if(t in e)this.setCursor(this._getRotatedCornerCursor(t,i,r));else{if("mtr"!==t||!i.hasRotatingPoint)return this.setCursor(this.defaultCursor),!1;this.setCursor(this.rotationCursor)}},_getRotatedCornerCursor:function(t,i,r){var n=Math.round(i.getAngle()%360/45);return n<0&&(n+=8),n+=e[t],r[this.altActionKey]&&e[t]%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),e)}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,e),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})).addWithUpdate(),this.setActiveGroup(e,t),e.saveCoords(),this.fire("selection:created",{target:e,e:t}),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.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.height||this.getHeight())*r,h=this.getZoom()*r,c=this.viewportTransform,l=[h,0,0,h,(c[4]-i.left)*r,(c[5]-i.top)*r],u=this.interactive;this.viewportTransform=l,this.interactive&&(this.interactive=!1),n!==o||s!==a?this.setDimensions({width:o,height:a},{backstoreOnly:!0}):this.renderAll();var f=this.__toDataURL(t,e,i);return u&&(this.interactive=u),this.viewportTransform=c,this.setDimensions({width:n,height:s},{backstoreOnly:!0}),f},__toDataURL:function(e,i){var r=this.contextContainer.canvas;"jpg"===e&&(e="jpeg");return t?r.toDataURL("image/"+e,i):r.toDataURL("image/"+e)},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),n=this,s=this.renderOnAddRemove;return this.renderOnAddRemove=!1,this._enlivenObjects(r.objects,function(t){n.clear(),n._setBgOverlay(r,function(){t.forEach(function(t,e){n.insertAt(t,e)}),n.renderOnAddRemove=s,delete r.objects,delete r.backgroundImage,delete r.overlayImage,delete r.background,delete r.overlay,n._setOptions(r),n.renderAll(),e&&e()})},i),this}},_setBgOverlay:function(t,e){var i={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(t.backgroundImage||t.overlayImage||t.background||t.overlay){var r=function(){i.backgroundImage&&i.overlayImage&&i.backgroundColor&&i.overlayColor&&e&&e()};this.__setBgOverlay("backgroundImage",t.backgroundImage,i,r),this.__setBgOverlay("overlayImage",t.overlayImage,i,r),this.__setBgOverlay("backgroundColor",t.background,i,r),this.__setBgOverlay("overlayColor",t.overlay,i,r)}else e&&e()},__setBgOverlay:function(t,e,i,r){var n=this;if(!e)return i[t]=!0,void(r&&r());"backgroundImage"===t||"overlayImage"===t?fabric.util.enlivenObjects([e],function(e){n[t]=e[0],i[t]=!0,r&&r()}):this["set"+fabric.util.string.capitalize(t,!0)](e,function(){i[t]=!0,r&&r()})},_enlivenObjects:function(t,e,i){t&&0!==t.length?fabric.util.enlivenObjects(t,function(t){e&&e(t)},null,i):e&&e([])},_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.object.clone,n=e.util.toFixed,s=e.util.string.capitalize,o=e.util.degreesToRadians,a=e.StaticCanvas.supports("setLineDash"),h=!e.isLikelyNode;e.Object||(e.Object=e.util.createClass(e.CommonMethods,{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,objectCaching:h,statefullCache:!1,noScaleCache:!0,dirty:!0,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor skewX skewY fillRule".split(" "),cacheProperties:"fill stroke strokeWidth strokeDashArray width height strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor".split(" "),initialize:function(t){(t=t||{})&&this.setOptions(t)},_createCacheCanvas:function(){this._cacheProperties={},this._cacheCanvas=e.document.createElement("canvas"),this._cacheContext=this._cacheCanvas.getContext("2d"),this._updateCacheCanvas()},_limitCacheSize:function(t){var i=e.perfLimitSizeTotal,r=t.width,n=t.height,s=e.maxCacheSideLimit,o=e.minCacheSideLimit;if(r<=s&&n<=s&&r*n<=i)return rl&&(t.zoomX/=r/l,t.width=l,t.capped=!0),n>u&&(t.zoomY/=n/u,t.height=u,t.capped=!0),t},_getCacheCanvasDimensions:function(){var t=this.canvas&&this.canvas.getZoom()||1,i=this.getObjectScaling(),r=this.canvas&&this.canvas._isRetinaScaling()?e.devicePixelRatio:1,n=this._getNonTransformedDimensions(),s=i.scaleX*t*r,o=i.scaleY*t*r;return{width:n.x*s+2,height:n.y*o+2,zoomX:s,zoomY:o,x:n.x,y:n.y}},_updateCacheCanvas:function(){if(this.noScaleCache&&this.canvas&&this.canvas._currentTransform){var t=this.canvas._currentTransform.target,i=this.canvas._currentTransform.action;if(this===t&&i.slice&&"scale"===i.slice(0,5))return!1}var r,n,s=this._cacheCanvas,o=this._limitCacheSize(this._getCacheCanvasDimensions()),a=e.minCacheSideLimit,h=o.width,c=o.height,l=o.zoomX,u=o.zoomY,f=h!==this.cacheWidth||c!==this.cacheHeight,d=this.zoomX!==l||this.zoomY!==u,g=f||d,p=0,v=0,b=!1;if(f){var m=this._cacheCanvas.width,_=this._cacheCanvas.height,y=h>m||c>_;b=y||(h<.9*m||c<.9*_)&&m>a&&_>a,y&&!o.capped&&(h>a||c>a)&&(p=.1*h,v=.1*c)}return!!g&&(b?(s.width=Math.ceil(h+p),s.height=Math.ceil(c+v)):(this._cacheContext.setTransform(1,0,0,1,0,0),this._cacheContext.clearRect(0,0,s.width,s.height)),r=o.x*l/2,n=o.y*u/2,this.cacheTranslationX=Math.round(s.width/2-r)+r,this.cacheTranslationY=Math.round(s.height/2-n)+n,this.cacheWidth=h,this.cacheHeight=c,this._cacheContext.translate(this.cacheTranslationX,this.cacheTranslationY),this._cacheContext.scale(l,u),this.zoomX=l,this.zoomY=u,!0)},setOptions:function(t){this._setOptions(t),this._initGradient(t.fill,"fill"),this._initGradient(t.stroke,"stroke"),this._initClipping(t),this._initPattern(t.fill,"fill"),this._initPattern(t.stroke,"stroke")},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),this.angle&&t.rotate(o(this.angle)),t.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1)),this.skewX&&t.transform(1,0,Math.tan(o(this.skewX)),1,0,0),this.skewY&&t.transform(1,Math.tan(o(this.skewY)),0,1,0,0)},toObject:function(t){var i=e.Object.NUM_FRACTION_DIGITS,r={type:this.type,originX:this.originX,originY:this.originY,left:n(this.left,i),top:n(this.top,i),width:n(this.width,i),height:n(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:n(this.strokeWidth,i),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:n(this.strokeMiterLimit,i),scaleX:n(this.scaleX,i),scaleY:n(this.scaleY,i),angle:n(this.getAngle(),i),flipX:this.flipX,flipY:this.flipY,opacity:n(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():null,skewX:n(this.skewX,i),skewY:n(this.skewY,i)};return e.util.populateWithProperties(this,r,t),this.includeDefaultValues||(r=this._removeDefaultValues(r)),r},toDatalessObject:function(t){return this.toObject(t)},_removeDefaultValues:function(t){var i=e.util.getKlass(t.type).prototype;return i.stateProperties.forEach(function(e){t[e]===i[e]&&delete t[e];"[object Array]"===Object.prototype.toString.call(t[e])&&"[object Array]"===Object.prototype.toString.call(i[e])&&0===t[e].length&&0===i[e].length&&delete t[e]}),t},toString:function(){return"#"},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}},_set:function(t,i){var r="scaleX"===t||"scaleY"===t,n=this[t]!==i;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?"dirty"===t&&this.group&&this.group.set("dirty",i):i=new e.Shadow(i),this[t]=i,n&&this.cacheProperties.indexOf(t)>-1&&(this.group&&this.group.set("dirty",!0),this.dirty=!0),n&&this.group&&this.stateProperties.indexOf(t)>-1&&this.group.set("dirty",!0),"width"!==t&&"height"!==t||(this.minScaleLimit=Math.min(.1,1/Math.max(this.width,this.height))),this},setOnGroup:function(){},setSourcePath:function(t){return this.sourcePath=t,this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:e.iMatrix.concat()},isNotVisible:function(){return 0===this.opacity||0===this.width&&0===this.height||!this.visible},render:function(t,i){this.isNotVisible()||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(t.save(),this._setupCompositeOperation(t),this.drawSelectionBackground(t),i||this.transform(t),this._setOpacity(t),this._setShadow(t),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.clipTo&&e.util.clipContext(this,t),this.shouldCache(i)?(this._cacheCanvas||this._createCacheCanvas(),this.isCacheDirty(i)&&(this.statefullCache&&this.saveState({propertySet:"cacheProperties"}),this.drawObject(this._cacheContext,i),this.dirty=!1),this.drawCacheOnCanvas(t)):(this._removeCacheCanvas(),this.dirty=!1,this.drawObject(t,i),i&&this.objectCaching&&this.statefullCache&&this.saveState({propertySet:"cacheProperties"})),this.clipTo&&t.restore(),t.restore())},_removeCacheCanvas:function(){this._cacheCanvas=null,this.cacheWidth=0,this.cacheHeight=0},needsItsOwnCache:function(){return!1},shouldCache:function(t){return!t&&this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching())},willDrawShadow:function(){return!!this.shadow&&(0!==this.shadow.offsetX||0!==this.shadow.offsetY)},drawObject:function(t,e){this._renderBackground(t),this._setStrokeStyles(t),this._setFillStyles(t),this._render(t,e)},drawCacheOnCanvas:function(t){t.scale(1/this.zoomX,1/this.zoomY),t.drawImage(this._cacheCanvas,-this.cacheTranslationX,-this.cacheTranslationY)},isCacheDirty:function(t){if(this.isNotVisible())return!1;if(this._cacheCanvas&&!t&&this._updateCacheCanvas())return!0;if(this.dirty||this.statefullCache&&this.hasStateChanged("cacheProperties")){if(this._cacheCanvas&&!t){var e=this.cacheWidth/this.zoomX,i=this.cacheHeight/this.zoomY;this._cacheContext.clearRect(-e/2,-i/2,e,i)}return!0}return!1},_renderBackground:function(t){if(this.backgroundColor){var e=this._getNonTransformedDimensions();t.fillStyle=this.backgroundColor,t.fillRect(-e.x/2,-e.y/2,e.x,e.y),this._removeShadow(t)}},_setOpacity:function(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),a?t.setLineDash(e):i&&i(t))},_renderControls:function(t){if(this.active&&(!this.group||this.group===this.canvas.getActiveGroup())){var i,r=this.getViewportTransform(),n=this.calcTransformMatrix();n=e.util.multiplyTransformMatrices(r,n),i=e.util.qrDecompose(n),t.save(),t.translate(i.translateX,i.translateY),t.lineWidth=1*this.borderScaleFactor,this.group||(t.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1),this.group&&this.group===this.canvas.getActiveGroup()?(t.rotate(o(i.angle)),this.drawBordersInGroup(t,i)):(t.rotate(o(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)},_applyPatternGradientTransform:function(t,e){if(e.toLive){var i=e.gradientTransform||e.patternTransform;i&&t.transform.apply(t,i);var r=-this.width/2+e.offsetX||0,n=-this.height/2+e.offsetY||0;t.translate(r,n)}},_renderFill:function(t){this.fill&&(t.save(),this._applyPatternGradientTransform(t,this.fill),"evenodd"===this.fillRule?t.fill("evenodd"):t.fill(),t.restore())},_renderStroke:function(t){this.stroke&&0!==this.strokeWidth&&(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(t),t.save(),this._setLineDash(t,this.strokeDashArray,this._renderDashedStroke),this._applyPatternGradientTransform(t,this.stroke),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 1},toJSON:function(t){return this.toObject(t)},setGradient:function(t,i){i||(i={});var r={colorStops:[]};return 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),r.gradientTransform=i.gradientTransform,e.Gradient.prototype.addColorStop.call(r,i.colorStops),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.group&&this.group===this.canvas._activeGroup&&this.group.remove(this),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,o(-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._fromObject=function(t,i,n,s,o){var a=e[t];if(i=r(i,!0),!s){var h=o?new a(i[o],i):new a(i);return n&&n(h),h}e.util.enlivenPatterns([i.fill,i.stroke],function(t){void 0!==t[0]&&(i.fill=t[0]),void 0!==t[1]&&(i.stroke=t[1]);var e=o?new a(i[o],i):new a(i);n&&n(e)})},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=void 0!==i&&void 0!==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")},onDeselect:function(){}})}(),function(){var t=fabric.util.degreesToRadians,e=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,aCoords:null,getCoords:function(t,e){this.oCoords||this.setCoords();var i=t?this.aCoords:this.oCoords;return function(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)]}(e?this.calcCoords(t):i)},intersectsWithRect:function(t,e,i,r){var n=this.getCoords(i,r);return"Intersection"===fabric.Intersection.intersectPolygonRectangle(n,t,e).status},intersectsWithObject:function(t,e,i){return"Intersection"===fabric.Intersection.intersectPolygonPolygon(this.getCoords(e,i),t.getCoords(e,i)).status||t.isContainedWithinObject(this,e,i)||this.isContainedWithinObject(t,e,i)},isContainedWithinObject:function(t,e,i){for(var r=this.getCoords(e,i),n=0,s=t._getImageLines(i?t.calcCoords(e):e?t.aCoords:t.oCoords);n<4;n++)if(!t.containsPoint(r[n],s))return!1;return!0},isContainedWithinRect:function(t,e,i,r){var n=this.getBoundingRect(i,r);return n.left>=t.x&&n.left+n.width<=e.x&&n.top>=t.y&&n.top+n.height<=e.y},containsPoint:function(t,e,i,r){var e=e||this._getImageLines(r?this.calcCoords(i):i?this.aCoords:this.oCoords),n=this._findCrossPoints(t,e);return 0!==n&&n%2==1},isOnScreen:function(t){if(!this.canvas)return!1;for(var e,i=this.canvas.vptCoords.tl,r=this.canvas.vptCoords.br,n=this.getCoords(!0,t),s=0;s<4;s++)if((e=n[s]).x<=r.x&&e.x>=i.x&&e.y<=r.y&&e.y>=i.y)return!0;if(this.intersectsWithRect(i,r,!0))return!0;var o={x:(i.x+r.x)/2,y:(i.y+r.y)/2};return!!this.containsPoint(o,null,!0)},_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=0;for(var a in e)if(!((s=e[a]).o.y=t.y&&s.d.y>=t.y||(s.o.x===s.d.x&&s.o.x>=t.x?n=s.o.x:(i=0,r=(s.d.y-s.o.y)/(s.d.x-s.o.x),n=-(t.y-i*t.x-(s.o.y-r*s.o.x))/(i-r)),n>=t.x&&(o+=1),2!==o)))break;return o},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(t,e){var i=this.getCoords(t,e);return fabric.util.makeBoundingBoxFromPoints(i)},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(t){return Math.abs(t)0?Math.atan(o/s):0,l=s/Math.cos(c)/2,u=Math.cos(c+i)*l,f=Math.sin(c+i)*l,d=this.getCenterPoint(),g=e?d:fabric.util.transformPoint(d,r),p=new fabric.Point(g.x-u,g.y-f),v=new fabric.Point(p.x+s*h,p.y+s*a),b=new fabric.Point(p.x-o*a,p.y+o*h),m=new fabric.Point(g.x+u,g.y+f);if(!e)var _=new fabric.Point((p.x+b.x)/2,(p.y+b.y)/2),y=new fabric.Point((v.x+p.x)/2,(v.y+p.y)/2),x=new fabric.Point((m.x+v.x)/2,(m.y+v.y)/2),C=new fabric.Point((m.x+b.x)/2,(m.y+b.y)/2),S=new fabric.Point(y.x+a*this.rotatingPointOffset,y.y-h*this.rotatingPointOffset);g={tl:p,tr:v,br:m,bl:b};return e||(g.ml=_,g.mt=y,g.mr=x,g.mb=C,g.mtr=S),g},setCoords:function(t,e){return this.oCoords=this.calcCoords(t),e||(this.aCoords=this.calcCoords(!0)),t||this._setCornerCoords&&this._setCornerCoords(),this},_calcRotateMatrix:function(){if(this.angle){var e=t(this.angle),i=Math.cos(e),r=Math.sin(e);return 6.123233995736766e-17!==i&&-1.8369701987210297e-16!==i||(i=0),[i,r,-r,i,0,0]}return fabric.iMatrix.concat()},calcTransformMatrix:function(t){var i,r,n=this.getCenterPoint(),s=[1,0,0,1,n.x,n.y],o=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0);return r=this.group&&!t?e(this.group.calcTransformMatrix(),s):s,this.angle&&(i=this._calcRotateMatrix(),r=e(r,i)),r=e(r,o)},_calcDimensionsTransformMatrix:function(i,r,n){var s,o=[this.scaleX*(n&&this.flipX?-1:1),0,0,this.scaleY*(n&&this.flipY?-1:1),0,0];return i&&(s=[1,0,Math.tan(t(i)),1],o=e(o,s,!0)),r&&(s=[1,Math.tan(t(r)),0,1],o=e(o,s,!0)),o},_getNonTransformedDimensions:function(){var t=this.strokeWidth;return{x:this.width+t,y:this.height+t}},_getTransformedDimensions:function(t,e){void 0===t&&(t=this.skewX),void 0===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("")}}),i.Line.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),i.Line.fromElement=function(t,e){e=e||{};var n=i.parseAttributes(t,i.Line.ATTRIBUTE_NAMES),s=[n.x1||0,n.y1||0,n.x2||0,n.y2||0];return e.originX="left",e.originY="top",new i.Line(s,r(n,e))},i.Line.fromObject=function(t,e,r){var s=n(t,!0);s.points=[t.x1,t.y1,t.x2,t.y2];var o=i.Object._fromObject("Line",s,function(t){delete t.points,e&&e(t)},r,"points");return o&&delete o.points,o})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=Math.PI,r=e.util.object.extend;e.Circle?e.warn("fabric.Circle is already defined."):(e.Circle=e.util.createClass(e.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*i,cacheProperties:e.Object.prototype.cacheProperties.concat("radius"),initialize:function(t){this.callSuper("initialize",t),this.set("radius",t&&t.radius||0)},_set:function(t,e){return this.callSuper("_set",t,e),"radius"===t&&this.setRadius(e),this},toObject:function(t){return this.callSuper("toObject",["radius","startAngle","endAngle"].concat(t))},toSVG:function(t){var e=this._createBaseSVGMarkup(),r=0,n=0,s=(this.endAngle-this.startAngle)%(2*i);if(0===s)this.group&&"path-group"===this.group.type&&(r=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>i?"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)}}),e.Circle.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),e.Circle.fromElement=function(t,i){i||(i={});var n=e.parseAttributes(t,e.Circle.ATTRIBUTE_NAMES);if(!function(t){return"radius"in t&&t.radius>=0}(n))throw new Error("value of `r` attribute is required and can not be negative");n.left=n.left||0,n.top=n.top||0;var s=new e.Circle(r(n,i));return s.left-=s.radius,s.top-=s.radius,s},e.Circle.fromObject=function(t,i,r){return e.Object._fromObject("Circle",t,i,r)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={});e.Triangle?e.warn("fabric.Triangle is already defined"):(e.Triangle=e.util.createClass(e.Object,{type:"triangle",initialize:function(t){this.callSuper("initialize",t),this.set("width",t&&t.width||100).set("height",t&&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("")}}),e.Triangle.fromObject=function(t,i,r){return e.Object._fromObject("Triangle",t,i,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;e.Ellipse?e.warn("fabric.Ellipse is already defined."):(e.Ellipse=e.util.createClass(e.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:e.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this.set("rx",t&&t.rx||0),this.set("ry",t&&t.ry||0)},_set:function(t,e){switch(this.callSuper("_set",t,e),t){case"rx":this.rx=e,this.set("width",2*e);break;case"ry":this.ry=e,this.set("height",2*e)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(t){return this.callSuper("toObject",["rx","ry"].concat(t))},toSVG:function(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)}}),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},e.Ellipse.fromObject=function(t,i,r){return e.Object._fromObject("Ellipse",t,i,r)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;e.Rect?e.warn("fabric.Rect is already defined"):(e.Rect=e.util.createClass(e.Object,{stateProperties:e.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:e.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(t,e){if(1!==this.width||1!==this.height){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)}else t.fillRect(-.5,-.5,1,1)},_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){return this.callSuper("toObject",["rx","ry"].concat(t))},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("")}}),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,r){return e.Object._fromObject("Rect",t,i,r)})}("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.toFixed,o=e.Object.NUM_FRACTION_DIGITS;e.Polyline?e.warn("fabric.Polyline is already defined"):(e.Polyline=e.util.createClass(e.Object,{type:"polyline",points:null,minX:0,minY:0,cacheProperties:e.Object.prototype.cacheProperties.concat("points"),initialize:function(t,e){e=e||{},this.points=t||[],this.callSuper("initialize",e),this._calcDimensions(),"top"in e||(this.top=this.minY),"left"in e||(this.left=this.minX),this.pathOffset={x:this.minX+this.width/2,y:this.minY+this.height/2}},_calcDimensions:function(){var t=this.points,e=r(t,"x"),i=r(t,"y"),s=n(t,"x"),o=n(t,"y");this.width=s-e||0,this.height=o-i||0,this.minX=e||0,this.minY=i||0},toObject:function(t){return i(this.callSuper("toObject",t),{points:this.points.concat()})},toSVG:function(t){var e=[],i=0,r=0,n=this._createBaseSVGMarkup();this.group&&"path-group"===this.group.type||(i=this.pathOffset.x,r=this.pathOffset.y);for(var a=0,h=this.points.length;a\n'),t?t(n.join("")):n.join("")},commonRender:function(t,e){var i,r=this.points.length,n=e?0:this.pathOffset.x,s=e?0:this.pathOffset.y;if(!r||isNaN(this.points[r-1].y))return!1;t.beginPath(),t.moveTo(this.points[0].x-n,this.points[0].y-s);for(var o=0;o"},toObject:function(t){return n(this.callSuper("toObject",["sourcePath","pathOffset"].concat(t)),{path:this.path.map(function(t){return t.slice()}),top:this.top,left:this.left})},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){var r=t.paths;delete t.paths,"string"==typeof r?e.loadSVGFromURL(r,function(n){var s=r,o=e.util.groupSVGElements(n,t,s);t.paths=r,i(o)}):e.util.enlivenObjects(r,function(n){var s=new e.PathGroup(n,t);t.paths=r,i(s)})},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;if(!e.Group){var s={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,cacheProperties:[],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;e.originX&&(this.originX=e.originX),e.originY&&(this.originY=e.originY),i?(this._updateObjectsCoords(!0),this._updateObjectsACoords()):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",e)),this.setCoords(),this.saveCoords()},_updateObjectsACoords:function(){for(var t=this._objects.length;t--;)this._objects[t].setCoords(!0,!0)},_updateObjectsCoords:function(t){for(var e=this.getCenterPoint(),i=this._objects.length;i--;)this._updateObjectCoords(this._objects[i],e,t)},_updateObjectCoords:function(t,e,i){if(t.__origHasControls=t.hasControls,t.hasControls=!1,!i){var r=t.getLeft(),n=t.getTop();t.set({left:r-e.x,top:n-e.y}),t.setCoords(!0,!0)}},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.setCoords(),this.dirty=!0,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.setCoords(),this.dirty=!0,this},_onObjectAdded:function(t){this.dirty=!0,t.group=this,t._set("canvas",this.canvas)},_onObjectRemoved:function(t){this.dirty=!0,delete t.group,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){var e=this.getObjects().map(function(e){var i=e.includeDefaultValues;e.includeDefaultValues=e.group.includeDefaultValues;var r=e.toObject(t);return e.includeDefaultValues=i,r});return i(this.callSuper("toObject",t),{objects:e})},toDatalessObject:function(t){var e=this.getObjects().map(function(e){var i=e.includeDefaultValues;e.includeDefaultValues=e.group.includeDefaultValues;var r=e.toDatalessObject(t);return e.includeDefaultValues=i,r});return i(this.callSuper("toDatalessObject",t),{objects:e})},render:function(t){this._transformDone=!0,this.callSuper("render",t),this._transformDone=!1},shouldCache:function(){var t=this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching());if(this.caching=t,t)for(var e=0,i=this._objects.length;e\n');for(var i=0,r=this._objects.length;i\n"),t?t(e.join("")):e.join("")},get:function(t){if(t in s){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(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){var e=function(){},i=(t=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()}}),fabric.Image.filters.BaseFilter.fromObject=function(t,e){var i=new fabric.Image.filters[t.type](t);return e&&e(i),i},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[S*d+w],e+=p[h]*c,i+=p[h+1]*c,r+=p[h+2]*c,n+=p[h+3]*c);_[s]=e,_[s+1]=i,_[s+2]=r,_[s+3]=n+y*(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=e.Image.filters.BaseFilter.fromObject}("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).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*f=e)){P=r(1e3*s(c-O.x)),w[P]||(w[P]={});for(var I=T.y-S;I<=T.y+S;I++)I<0||I>=o||(E=r(1e3*s(I-O.y)),w[P][E]||(w[P][E]=b(n(i(P*y,2)+i(E*x,2))/1e3)),(f=w[P][E])>0&&(j+=f,k+=f*p[d=4*(I*e+c)],M+=f*p[d+1],D+=f*p[d+2],A+=f*p[d+3]))}v[d=4*(h*a+t)]=k/j,v[d+1]=M/j,v[d+2]=D/j,v[d+3]=A/j}return++tt)return 0;if(e*=Math.PI,s(e)<1e-16)return 1;var i=e/t;return h(e)*h(i)/e/i}}(this.lanczosLobes),m=this.rcpScaleX,_=this.rcpScaleY,y=2/this.rcpScaleX,x=2/this.rcpScaleY,C=c(m*this.lanczosLobes/2),S=c(_*this.lanczosLobes/2),w={},O={},T={};return u(0)},bilinearFiltering:function(t,e,i,n,s){var o,a,h,c,l,u,f,d,g,p=0,v=this.rcpScaleX,b=this.rcpScaleY,m=t.getContext("2d"),_=4*(e-1),y=m.getImageData(0,0,e,i).data,x=m.getImageData(0,0,n,s),C=x.data;for(h=0;h1&&I<-1||(y=2*I*I*I-3*I*I+1)>0&&(T+=y*g[(E=4*(P+k*e))+3],C+=y,g[E+3]<255&&(y=y*g[E+3]/250),S+=y*g[E],w+=y*g[E+1],O+=y*g[E+2],x+=y)}v[_]=S/x,v[_+1]=w/x,v[_+2]=O/x,v[_+3]=T/C}return p},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}}),e.Image.filters.Resize.fromObject=e.Image.filters.BaseFilter.fromObject}("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'},_getCacheCanvasDimensions:function(){var t=this.callSuper("_getCacheCanvasDimensions"),e=this.fontSize;return t.width+=e*t.zoomX,t.height+=e*t.zoomY,t},_render:function(t){this._setTextStyles(t),this.group&&"path-group"===this.group.type&&t.translate(this.left,this.top),this._renderTextLinesBackground(t),this._renderText(t),this._renderTextDecoration(t)},_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},_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)for(var l=this._getWidthOfCharSpacing(),u=0,f=(i=i.split("")).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?i: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;t.fillStyle=s,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=[]},_shouldClearDimensionCache:function(){var t=this._forceClearCache;return t||(t=this.hasStateChanged("_dimensionAffectingProps")),t&&(this.saveState({propertySet:"_dimensionAffectingProps"}),this.dirty=!0),t},_getLineWidth:function(t,e){if(this.__lineWidths[e])return-1===this.__lineWidths[e]?this.width:this.__lineWidths[e];var i,r=this._textLines[e];return i=""===r?0:this._measureLine(t,e),this.__lineWidths[e]=i,i&&"justify"===this.textAlign&&r.split(/\s+/).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=this._textLines[e],n=t.measureText(r).width,s=0;return 0!==this.charSpacing&&(s=(r.split("").length-1)*this._getWidthOfCharSpacing()),(i=n+s)>0?i:0},_renderTextDecoration:function(t){if(this.textDecoration){var e=this.height/2,i=this,r=[];this.textDecoration.indexOf("underline")>-1&&r.push(.85),this.textDecoration.indexOf("line-through")>-1&&r.push(.43),this.textDecoration.indexOf("overline")>-1&&r.push(-.12),r.length>0&&function(r){var n,s,o,a,h,c,l,u=0;for(n=0,s=i._textLines.length;n\n",e.textBgRects.join(""),'\t\t\n',e.textSpans.join(""),"\t\t\n","\t\n")},getSvgStyles:function(t){return e.Object.prototype.getSvgStyles.call(this,t)+" white-space: pre;"},_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"):this._setSVGTextLineJustifed(t,n,h,o)},_setSVGTextLineJustifed:function(t,n,s,o){var a=e.util.createCanvasElement().getContext("2d");this._setTextStyles(a);var h,c,l=this._textLines[t].split(/\s+/),u=this._getWidthOfWords(a,l.join("")),f=this.width-u,d=l.length-1,g=d>0?f/d:0,p=this._getFillAttributes(this.fill);for(o+=this._getLineLeftOffset(this._getLineWidth(a,t)),t=0,c=l.length;t",e.util.string.escapeXml(h),"\n"),o+=this._getWidthOfWords(a,h)+g},_setSVGTextLineBg:function(t,e,n,s,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),this._dimensionAffectingProps.indexOf(t)>-1&&(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)).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)*o,h=s.getHeight()+a,c=0;return"left"===s.originX&&(c=s.getWidth()/2),"right"===s.originX&&(c=-s.getWidth()/2),s.set({left:s.getLeft()+c,top:s.getTop()-h/2+s.fontSize*(.18+s._fontSizeFraction)/s.lineHeight}),s},e.Text.fromObject=function(t,i,r){return e.Object._fromObject("Text",t,i,r,"text")},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=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(),h=0;for(var m,_=0,y=(g=n.split("")).length;_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);var e,i,r,n,s,o,a,h,c,l,u=0,f=this._getLeftOffset(),d=this._getTopOffset(),g="";t.save();for(var p=0,v=this._textLines.length;p0?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.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()))}},_setEditingProps:function(){this.hoverCursor="text",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},_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=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)).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.hiddenTextarea.blur&&this.hiddenTextarea.blur(),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())for(var r=0,n=t.length;r=i&&(o=!0,s[h-i]=this.styles[e][a],delete this.styles[e][a])}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])}var h=r||t(n[i-1]);h&&(this.styles[e][i]=h),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 r){(s=parseInt(n,10))<=e&&delete r[s]}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,t.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.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&&(!t.e.button||1===t.e.button)){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)||t.e.button&&1!==t.e.button||(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.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(t){for(var e,i=this.getLocalPointer(t),r=0,n=0,s=0,o=0,a=0,h=this._textLines.length;as?0:1);return this.flipX&&(o=n-o),o>this.text.length&&(o=this.text.length),o}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.setAttribute("autocorrect","off"),this.hiddenTextarea.setAttribute("autocomplete","off"),this.hiddenTextarea.setAttribute("spellcheck","false"),this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea",""),this.hiddenTextarea.setAttribute("wrap","off");var t=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+t.top+"; left: "+t.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; line-height: 1px; paddingーtop: "+t.fontSize+";",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(),t.keyCode>=33&&t.keyCode<=40?(this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.renderAll()}},onKeyUp:function(t){this.isEditing&&!this._copyDone?t.keyCode in this.ctrlKeysMapUp&&(t.ctrlKey||t.metaKey)&&(this[this.ctrlKeysMapUp[t.keyCode]](t),t.stopImmediatePropagation(),t.preventDefault(),this.canvas&&this.canvas.renderAll()):this._copyDone=!1},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 u=s-l,f=s,d=Math.abs(u-e);o=Math.abs(f-e)=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorUpOrDown("Down",t)},moveCursorUp:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",t)},_moveCursorUpOrDown:function(t,e){var i=this["get"+t+"CursorOffset"](e,"right"===this._selectionDirection);e.shiftKey?this.moveCursorWithShift(i):this.moveCursorWithoutShift(i),0!==i&&(this.setSelectionInBoundaries(),this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(t){var e="left"===this._selectionDirection?this.selectionStart+t:this.selectionEnd+t;return this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,e),0!==t},moveCursorWithoutShift:function(t){return t<0?(this.selectionStart+=t,this.selectionEnd=this.selectionStart):(this.selectionEnd+=t,this.selectionStart=this.selectionEnd),0!==t},moveCursorLeft:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorLeftOrRight("Left",t)},_move:function(t,e,i){var r;if(t.altKey)r=this["findWordBoundary"+i](this[e]);else{if(!t.metaKey&&35!==t.keyCode&&36!==t.keyCode)return this[e]+="Left"===i?-1:1,!0;r=this["findLineBoundary"+i](this[e])}if(void 0!==typeof r&&this[e]!==r)return this[e]=r,!0},_moveLeft:function(t,e){return this._move(t,e,"Left")},_moveRight:function(t,e){return this._move(t,e,"Right")},moveCursorLeftWithoutShift:function(t){var e=!0;return this._selectionDirection="left",this.selectionEnd===this.selectionStart&&0!==this.selectionStart&&(e=this._moveLeft(t,"selectionStart")),this.selectionEnd=this.selectionStart,e},moveCursorLeftWithShift:function(t){return"right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveLeft(t,"selectionEnd"):0!==this.selectionStart?(this._selectionDirection="left",this._moveLeft(t,"selectionStart")):void 0},moveCursorRight:function(t){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorLeftOrRight("Right",t)},_moveCursorLeftOrRight:function(t,e){var i="moveCursor"+t+"With";this._currentCursorOpacity=1,e.shiftKey?i+="Shift":i+="outShift",this[i](e)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(t){return"left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveRight(t,"selectionStart"):this.selectionEnd!==this.text.length?(this._selectionDirection="right",this._moveRight(t,"selectionEnd")):void 0},moveCursorRightWithoutShift:function(t){var e=!0;return this._selectionDirection="right",this.selectionStart===this.selectionEnd?(e=this._moveRight(t,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd,e},removeChars:function(t){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(t):this._removeCharsFromTo(this.selectionStart,this.selectionEnd),this.set("dirty",!0),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={});e.Textbox=e.util.createClass(e.IText,e.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:2,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,noScaleCache:!1,_dimensionAffectingProps:e.Text.prototype._dimensionAffectingProps.concat("width"),initialize:function(t,i){this.callSuper("initialize",t,i),this.setControlsVisibility(e.Textbox.getTextboxControlVisibility()),this.ctx=this.objectCaching?this._cacheContext:e.util.createCanvasElement().getContext("2d")},_initDimensions:function(t){this.__skipDimension||(t||(t=e.util.createCanvasElement().getContext("2d"),this._setTextStyles(t),this.clearContextTop()),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(t),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(t),this.setCoords())},_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&&!f?(n.push(s),s="",r=c,f=!0):r+=d,f||(s+=" "),s+=a,l=this._measureText(t," ",i,h),h++,f=!1,c>u&&(u=c);return g&&n.push(s),u>this.dynamicMinWidth&&(this.dynamicMinWidth=u-d),n},_splitTextIntoLines:function(t){t=t||this.ctx;var e=this.textAlign;this._styleMap=null,t.save(),this._setTextStyles(t),this.textAlign="left";var i=this._wrapText(t,this.text);return this.textAlign=e,t.restore(),this._textLines=i,this._styleMap=this._generateStyleMap(),i},setOnGroup:function(t,e){"scaleX"===t&&(this.set("scaleX",Math.abs(1/e)),this.set("width",this.get("width")*e/(void 0===this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=e)},get2DCursorLocation:function(t){void 0===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(void 0!==fabric.Textbox)for(var t=this._objects.length;t--;)if(this._objects[t]instanceof fabric.Textbox)return void this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility())},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,e){t=this._styleMap[t].line,fabric.IText.prototype.shiftLineStyles.call(this,t,e)},_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).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)})});n.on("error",function(t){t.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+r.hostname+":"+r.port):fabric.log(t.message),i(null)}),n.end()}function requestFs(t,e){require("fs").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){0!==(t=t.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim()).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||{}).nodeCanvas=s,i.nodeCacheCanvas=o;var a=new(fabric.Canvas||fabric.StaticCanvas)(n,i);return a.nodeCanvas=s,a.nodeCacheCanvas=o,a.contextContainer=s.getContext("2d"),a.contextCache=o.getContext("2d"),a.Font=Canvas.Font,a};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 +var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(e,b,d){if(d.get||d.set)throw new TypeError("ES3 does not support getters and setters.");e!=Array.prototype&&e!=Object.prototype&&(e[b]=d.value)};$jscomp.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global?global:e};$jscomp.global=$jscomp.getGlobal(this); +$jscomp.polyfill=function(e,b,d,c){if(b){d=$jscomp.global;e=e.split(".");for(c=0;cd&&(d=Math.max(0,a+d));if(null==c||c>a)c=a;c=Number(c);0>c&&(c=Math.max(0,a+c));for(d=Number(d||0);db||1342177279>>=1)d+=d;return c}},"es6-impl","es3");$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.symbolCounter_=0; +$jscomp.Symbol=function(e){return $jscomp.SYMBOL_PREFIX+(e||"")+$jscomp.symbolCounter_++};$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var e=$jscomp.global.Symbol.iterator;e||(e=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[e]&&$jscomp.defineProperty(Array.prototype,e,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}}; +$jscomp.arrayIterator=function(e){var b=0;return $jscomp.iteratorPrototype(function(){return bf;)f+=n[l++%h], +f>e&&(f=e),a[k?"lineTo":"moveTo"](f,0),k=!k;a.restore()},createCanvasElement:function(a){a||(a=fabric.document.createElement("canvas"));a.getContext||"undefined"===typeof G_vmlCanvasManager||G_vmlCanvasManager.initElement(a);return a},createImage:function(){return fabric.isLikelyNode?new (require("canvas").Image):fabric.document.createElement("img")},createAccessors:function(a){a=a.prototype;var f,c,b,d;for(f=a.stateProperties.length;f--;)c=a.stateProperties[f],b=c.charAt(0).toUpperCase()+c.slice(1), +d="set"+b,b="get"+b,a[b]||(a[b]=new Function('return this.get("'+c+'")')),a[d]||(a[d]=new Function("value",'return this.set("'+c+'", value)'))},clipContext:function(a,f){f.save();f.beginPath();a.clipTo(f);f.clip()},multiplyTransformMatrices:function(a,f,c){return[a[0]*f[0]+a[2]*f[1],a[1]*f[0]+a[3]*f[1],a[0]*f[2]+a[2]*f[3],a[1]*f[2]+a[3]*f[3],c?0:a[0]*f[4]+a[2]*f[5]+a[4],c?0:a[1]*f[4]+a[3]*f[5]+a[5]]},qrDecompose:function(a){var f=d(a[1],a[0]),h=c(a[0],2)+c(a[1],2),k=b(h),e=(a[0]*a[3]-a[2]*a[1])/k, +h=d(a[0]*a[2]+a[1]*a[3],h);return{angle:f/g,scaleX:k,scaleY:e,skewX:h/g,skewY:0,translateX:a[4],translateY:a[5]}},customTransformMatrix:function(c,f,b){b=[1,0,a(Math.tan(b*g)),1];c=[a(c),0,0,a(f)];return fabric.util.multiplyTransformMatrices(c,b,!0)},resetObjectTransform:function(a){a.scaleX=1;a.scaleY=1;a.skewX=0;a.skewY=0;a.flipX=!1;a.flipY=!1;a.setAngle(0)},getFunctionBody:function(a){return(String(a).match(/function[^{]*\{([\s\S]*)\}/)||{})[1]},isTransparent:function(a,f,c,b){0b?f-b: +0,c=c>b?c-b:0);var d=!0;f=a.getImageData(f,c,2*b||1,2*b||1);c=f.data.length;for(a=3;a=d,!1!==d);a+=4);return d},parsePreserveAspectRatioAttribute:function(a){var f="meet",c;(a=a.split(" "))&&a.length&&(f=a.pop(),"meet"!==f&&"slice"!==f?(c=f,f="meet"):a.length&&(c=a.pop()));a="none"!==c?c.slice(1,4):"none";c="none"!==c?c.slice(5,8):"none";return{meetOrSlice:f,alignX:a,alignY:c}},clearFabricFontCache:function(a){a?fabric.charWidthsCache[a]&&delete fabric.charWidthsCache[a]:fabric.charWidthsCache= +{}},limitDimsByArea:function(a,f){var c=Math.sqrt(f*a);return{x:Math.floor(c),y:Math.floor(f/c)}},capValue:function(a,f,c){return Math.max(a,Math.min(f,c))}}})("undefined"!==typeof exports?exports:this); +(function(){function e(c,g,h,e,p,q,t){var l=f.call(arguments);if(a[l])return a[l];var k=Math.PI,m=t*k/180,n=Math.sin(m),m=Math.cos(m),y=0,x=0;h=Math.abs(h);e=Math.abs(e);var u=-m*c*.5-n*g*.5,C=-m*g*.5+n*c*.5,D=h*h,z=e*e,E=C*C,B=u*u,F=D*z-D*E-z*B,G=0;0>F?(D=Math.sqrt(1-F/(D*z)),h*=D,e*=D):G=(p===q?-1:1)*Math.sqrt(F/(D*E+z*B));E=G*h*C/e;B=-G*e*u/h;G=m*E-n*B+.5*c;D=n*E+m*B+.5*g;z=d(1,0,(u-E)/h,(C-B)/e);C=d((u-E)/h,(C-B)/e,(-u-E)/h,(-C-B)/e);0===q&&0C&&(C+=2*k);k=Math.ceil(Math.abs(C/ +k*2));u=[];C/=k;E=8/3*Math.sin(C/4)*Math.sin(C/4)/Math.sin(C/2);B=z+C;for(F=0;F=a?c-a:2*Math.PI- +(a-c)}function c(a,c,b,d,g,e,t,r){var l=f.call(arguments);if(h[l])return h[l];var k=Math.sqrt,m=Math.min,n=Math.max,p=Math.abs,q=[],C=[[],[]],D,z,E,B,F;z=6*a-12*b+6*g;D=-3*a+9*b-9*g+3*t;E=3*b-3*a;for(var G=0;2>G;++G)0p(D)?1E-12>p(z)||(B=-E/z,0B&&q.push(B)):(B=z*z-4*E*D,0>B||(F=k(B),B=(-z+F)/(2*D),0B&&q.push(B),B=(-z-F)/(2*D),0B&&q.push(B)));for(p=k=q.length;k--;)B=q[k],z=1-B,D=z*z*z*a+3*z*z*B*b+3*z*B*B*g+B*B*B*t,C[0][k]=D,D= +z*z*z*c+3*z*z*B*d+3*z*B*B*e+B*B*B*r,C[1][k]=D;C[0][p]=a;C[1][p]=c;C[0][p+1]=t;C[1][p+1]=r;m=[{x:m.apply(null,C[0]),y:m.apply(null,C[1])},{x:n.apply(null,C[0]),y:n.apply(null,C[1])}];return h[l]=m}var a={},g={},h={},f=Array.prototype.join;fabric.util.drawArc=function(a,f,c,b){var d=[[],[],[],[]];b=e(b[5]-f,b[6]-c,b[0],b[1],b[3],b[4],b[2]);for(var g=0,h=b.length;g>>0;if(0===a)return-1;var d=0;0=a)return-1;for(d=0<=d?d:Math.max(a-Math.abs(d),0);d>>0;a>>0;d>> +0;a>>0;a>>0;h>>0,a=0,d;if(1=c)throw new TypeError;}while(1)}for(;a=c})}}})(); +(function(){function e(b,d,c){if(c)if(!fabric.isLikelyNode&&d instanceof Element)b=d;else if(d instanceof Array){b=[];for(var a=0,g=d.length;a/g,">")}}})(); +(function(){var e=Array.prototype.slice,b=Function.prototype.apply,d=function(){};Function.prototype.bind||(Function.prototype.bind=function(c){var a=this,g=e.call(arguments,1),h;h=g.length?function(){return b.call(a,this instanceof d?this:c,g.concat(e.call(arguments)))}:function(){return b.call(a,this instanceof d?this:c,arguments)};d.prototype=this.prototype;h.prototype=new d;return h})})(); +(function(){function e(){}function b(a){for(var f=null,c=this;c.constructor.superclass;){var b=c.constructor.superclass.prototype[a];if(c[a]!==b){f=b;break}c=c.constructor.superclass.prototype}return f?1f?h:l-d;a=g/h;g=p(g,q,r,h);k(g,Math.abs((g-q)/r),a);l>f?c.onComplete&&c.onComplete():b(A)}})(d)})};fabric.util.requestAnimFrame=b})(); +(function(){fabric.util.animateColor=function(e,b,d,c){e=(new fabric.Color(e)).getSource();b=(new fabric.Color(b)).getSource();c=c||{};fabric.util.animate(fabric.util.object.extend(c,{duration:d||500,startValue:e,endValue:b,byValue:b,easing:function(a,b,d,f){a=c.colorEasing?c.colorEasing(a,f):1-Math.cos(a/f*(Math.PI/2));f="rgba("+parseInt(b[0]+a*(d[0]-b[0]),10)+","+parseInt(b[1]+a*(d[1]-b[1]),10)+","+parseInt(b[2]+a*(d[2]-b[2]),10);f+=","+(b&&d?parseFloat(b[3]+a*(d[3]-b[3])):1);return f+")"}}))}})(); +(function(){function e(a,c,b,f){aa?b/2*a*a+c:-b/2*(--a*(a-2)-1)+c},easeInCubic:function(a,c,b,f){return b*(a/=f)*a*a+c},easeOutCubic:function(a,c,b,f){return b*((a=a/f-1)*a*a+1)+c},easeInOutCubic:function(a,c,b,f){a/=f/2;return 1>a?b/2*a*a*a+c:b/2*((a-=2)*a*a+2)+c},easeInQuart:function(a,c,b,f){return b*(a/=f)*a*a*a+c},easeOutQuart:function(a,c,b,f){return-b*((a=a/f-1)*a*a*a-1)+c},easeInOutQuart:function(a, +c,b,f){a/=f/2;return 1>a?b/2*a*a*a*a+c:-b/2*((a-=2)*a*a*a-2)+c},easeInQuint:function(a,c,b,f){return b*(a/=f)*a*a*a*a+c},easeOutQuint:function(a,c,b,f){return b*((a=a/f-1)*a*a*a*a+1)+c},easeInOutQuint:function(a,c,b,f){a/=f/2;return 1>a?b/2*a*a*a*a*a+c:b/2*((a-=2)*a*a*a*a+2)+c},easeInSine:function(a,c,b,f){return-b*Math.cos(a/f*(Math.PI/2))+b+c},easeOutSine:function(a,c,b,f){return b*Math.sin(a/f*(Math.PI/2))+c},easeInOutSine:function(a,c,b,f){return-b/2*(Math.cos(Math.PI*a/f)-1)+c},easeInExpo:function(a, +c,b,f){return 0===a?c:b*Math.pow(2,10*(a/f-1))+c},easeOutExpo:function(a,c,b,f){return a===f?c+b:b*(-Math.pow(2,-10*a/f)+1)+c},easeInOutExpo:function(a,c,b,f){if(0===a)return c;if(a===f)return c+b;a/=f/2;return 1>a?b/2*Math.pow(2,10*(a-1))+c:b/2*(-Math.pow(2,-10*--a)+2)+c},easeInCirc:function(a,c,b,f){return-b*(Math.sqrt(1-(a/=f)*a)-1)+c},easeOutCirc:function(a,c,b,f){return b*Math.sqrt(1-(a=a/f-1)*a)+c},easeInOutCirc:function(a,c,b,f){a/=f/2;return 1>a?-b/2*(Math.sqrt(1-a*a)-1)+c:b/2*(Math.sqrt(1- +(a-=2)*a)+1)+c},easeInElastic:function(a,c,d,f){var g=0;if(0===a)return c;a/=f;if(1===a)return c+d;g||(g=.3*f);d=e(d,d,g,1.70158);return-b(d,a,f)+c},easeOutElastic:function(a,c,b,f){var d=0;if(0===a)return c;a/=f;if(1===a)return c+b;d||(d=.3*f);b=e(b,b,d,1.70158);return b.a*Math.pow(2,-10*a)*Math.sin(2*(a*f-b.s)*Math.PI/b.p)+b.c+c},easeInOutElastic:function(a,c,d,f){var g=0;if(0===a)return c;a/=f/2;if(2===a)return c+d;g||(g=.3*f*1.5);d=e(d,d,g,1.70158);return 1>a?-.5*b(d,a,f)+c:d.a*Math.pow(2,-10* +--a)*Math.sin(2*(a*f-d.s)*Math.PI/d.p)*.5+d.c+c},easeInBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);return b*(a/=f)*a*((d+1)*a-d)+c},easeOutBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);return b*((a=a/f-1)*a*((d+1)*a+d)+1)+c},easeInOutBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);a/=f/2;return 1>a?b/2*a*a*(((d*=1.525)+1)*a-d)+c:b/2*((a-=2)*a*(((d*=1.525)+1)*a+d)+2)+c},easeInBounce:d,easeOutBounce:c,easeInOutBounce:function(a,b,h,f){return ab?b:c);if(1===c&&1===b&&0===d&&0===g&& +0===m&&0===n)return r;if(m||n)A=" translate("+q(m)+" "+q(n)+") ";c=A+" matrix("+c+" 0 0 "+b+" "+d*c+" "+g*b+") ";if("svg"===a.nodeName){for(b=a.ownerDocument.createElement("g");a.firstChild;)b.appendChild(a.firstChild);a.appendChild(b)}else b=a,c=b.getAttribute("transform")+c;b.setAttribute("transform",c);return r}var k=e.fabric||(e.fabric={}),m=k.util.object.extend,n=k.util.object.clone,p=k.util.toFixed,q=k.util.parseUnit,t=k.util.multiplyTransformMatrices,r=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i, +v=/^(symbol|image|marker|pattern|view|svg)$/i,A=/^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i,w=/^(symbol|g|a|svg)$/i,y={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",opacity:"opacity"},x={stroke:"strokeOpacity",fill:"fillOpacity"};k.cssRules={};k.gradientDefs={};k.parseTransformAttribute=function(){function a(a,f){var c=Math.cos(f[0]),b=Math.sin(f[0]),d=0,g=0;3===f.length&&(d=f[1],g=f[2]);a[0]=c;a[1]=b;a[2]=-b;a[3]=c;a[4]=d-(c*d-b*g);a[5]=g-(b*d+c*g)}function f(a,f){var c=2===f.length?f[1]:f[0];a[0]=f[0];a[3]=c}function c(a,f){a[4]=f[0];2=== +f.length&&(a[5]=f[1])}var b=[1,0,0,1,0,0],d=k.reNum,g="(?:"+("(?:(matrix)\\s*\\(\\s*("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")\\s*\\))")+"|"+("(?:(translate)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+("(?:(scale)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+("(?:(rotate)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+ +("(?:(skewX)\\s*\\(\\s*("+d+")\\s*\\))")+"|"+("(?:(skewY)\\s*\\(\\s*("+d+")\\s*\\))")+")",l=new RegExp("^\\s*(?:"+("(?:"+g+"(?:(?:\\s+,?\\s*|,\\s*)*"+g+")*)")+"?)\\s*$"),h=new RegExp(g,"g");return function(d){var e=b.concat(),m=[];if(!d||d&&!l.test(d))return e;d.replace(h,function(d){var l=(new RegExp(g)).exec(d).filter(function(a){return!!a});d=l[1];l=l.slice(2).map(parseFloat);switch(d){case "translate":c(e,l);break;case "rotate":l[0]=k.util.degreesToRadians(l[0]);a(e,l);break;case "scale":f(e, +l);break;case "skewX":e[2]=Math.tan(k.util.degreesToRadians(l[0]));break;case "skewY":e[1]=Math.tan(k.util.degreesToRadians(l[0]));break;case "matrix":e=l}m.push(e.concat());e=b.concat()});for(d=m[0];1/i,"")));d&&d.documentElement||f&&f(null);k.parseSVGDocument(d.documentElement,function(a,c){f&&f(a,c)},c,b)}})},loadSVGFromString:function(a,f,c,b){a=a.trim();var d;if("undefined"!==typeof DOMParser){var g=new DOMParser;g&&g.parseFromString&&(d=g.parseFromString(a,"text/xml"))}else k.window.ActiveXObject&& +(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(a.replace(//i,"")));k.parseSVGDocument(d.documentElement,function(a,c){f(a,c)},c,b)}})})("undefined"!==typeof exports?exports:this);fabric.ElementsParser=function(e,b,d,c,a){this.elements=e;this.callback=b;this.options=d;this.reviver=c;this.svgUid=d&&d.svgUid||0;this.parsingOptions=a}; +fabric.ElementsParser.prototype.parse=function(){this.instances=Array(this.elements.length);this.numElements=this.elements.length;this.createObjects()};fabric.ElementsParser.prototype.createObjects=function(){for(var e=0,b=this.elements.length;eb.x&&this.y>b.y},gte:function(b){return this.x>=b.x&&this.y>=b.y},lerp:function(d,c){"undefined"===typeof c&&(c=.5);c=Math.max(Math.min(1,c),0);return new b(this.x+(d.x-this.x)*c,this.y+(d.y-this.y)*c)},distanceFrom:function(b){var c=this.x-b.x;b=this.y-b.y;return Math.sqrt(c*c+b*b)},midPointFrom:function(b){return this.lerp(b)},min:function(d){return new b(Math.min(this.x,d.x),Math.min(this.y,d.y))},max:function(d){return new b(Math.max(this.x,d.x),Math.max(this.y, +d.y))},toString:function(){return this.x+","+this.y},setXY:function(b,c){this.x=b;this.y=c;return this},setX:function(b){this.x=b;return this},setY:function(b){this.y=b;return this},setFromPoint:function(b){this.x=b.x;this.y=b.y;return this},swap:function(b){var c=this.x,a=this.y;this.x=b.x;this.y=b.y;b.x=c;b.y=a},clone:function(){return new b(this.x,this.y)}})})("undefined"!==typeof exports?exports:this); +(function(e){function b(b){this.status=b;this.points=[]}var d=e.fabric||(e.fabric={});d.Intersection?d.warn("fabric.Intersection is already defined"):(d.Intersection=b,d.Intersection.prototype={constructor:b,appendPoint:function(b){this.points.push(b);return this},appendPoints:function(b){this.points=this.points.concat(b);return this}},d.Intersection.intersectLineLine=function(c,a,g,h){var f,l=(h.x-g.x)*(c.y-g.y)-(h.y-g.y)*(c.x-g.x);f=(a.x-c.x)*(c.y-g.y)-(a.y-c.y)*(c.x-g.x);g=(h.y-g.y)*(a.x-c.x)- +(h.x-g.x)*(a.y-c.y);0!==g?(l/=g,f/=g,0<=l&&1>=l&&0<=f&&1>=f?(f=new b("Intersection"),f.appendPoint(new d.Point(c.x+l*(a.x-c.x),c.y+l*(a.y-c.y)))):f=new b):f=0===l||0===f?new b("Coincident"):new b("Parallel");return f},d.Intersection.intersectLinePolygon=function(c,a,d){for(var g=new b,f=d.length,l,e,m=0;mc&&(c+=1);1c?b:c<2/3?a+(b-a)*(2/3-c)*6:a}var c=e.fabric||(e.fabric={});c.Color?c.warn("fabric.Color is already defined."):(c.Color=b,c.Color.prototype={_tryParsingColor:function(a){var c;a in b.colorNameMap&&(a=b.colorNameMap[a]);"transparent"===a&&(c=[255,255,255,0]);c||(c=b.sourceFromHex(a));c||(c=b.sourceFromRgb(a));c||(c=b.sourceFromHsl(a));c||(c=[0,0,0,1]);c&& +this.setSource(c)},_rgbToHsl:function(a,b,d){a/=255;b/=255;d/=255;var f,g,h,e=c.util.array.max([a,b,d]);g=c.util.array.min([a,b,d]);h=(e+g)/2;if(e===g)f=g=0;else{var n=e-g;g=.5l;l++)c.push(Math.round(.5*f[l]+.5*a[l]));c[3]=d;this.setSource(c);return this}},c.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*)?\)$/,c.Color.reHSLa= +/^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/,c.Color.reHex=/^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i,c.Color.colorNameMap={aqua:"#00FFFF",black:"#000000",blue:"#0000FF",fuchsia:"#FF00FF",gray:"#808080",grey:"#808080",green:"#008000",lime:"#00FF00",maroon:"#800000",navy:"#000080",olive:"#808000",orange:"#FFA500",purple:"#800080",red:"#FF0000",silver:"#C0C0C0",teal:"#008080",white:"#FFFFFF",yellow:"#FFFF00"},c.Color.fromRgb=function(a){return b.fromSource(b.sourceFromRgb(a))}, +c.Color.sourceFromRgb=function(a){if(a=a.match(b.reRGBa)){var c=parseInt(a[1],10)/(/%$/.test(a[1])?100:1)*(/%$/.test(a[1])?255:1),d=parseInt(a[2],10)/(/%$/.test(a[2])?100:1)*(/%$/.test(a[2])?255:1),f=parseInt(a[3],10)/(/%$/.test(a[3])?100:1)*(/%$/.test(a[3])?255:1);return[parseInt(c,10),parseInt(d,10),parseInt(f,10),a[4]?parseFloat(a[4]):1]}},c.Color.fromRgba=b.fromRgb,c.Color.fromHsl=function(a){return b.fromSource(b.sourceFromHsl(a))},c.Color.sourceFromHsl=function(a){if(a=a.match(b.reHSLa)){var c= +(parseFloat(a[1])%360+360)%360/360,h=parseFloat(a[2])/(/%$/.test(a[2])?100:1),f=parseFloat(a[3])/(/%$/.test(a[3])?100:1);if(0===h)f=h=c=f;else var l=.5>=f?f*(h+1):f+h-f*h,e=2*f-l,f=d(e,l,c+1/3),h=d(e,l,c),c=d(e,l,c-1/3);return[Math.round(255*f),Math.round(255*h),Math.round(255*c),a[4]?parseFloat(a[4]):1]}},c.Color.fromHsla=b.fromHsl,c.Color.fromHex=function(a){return b.fromSource(b.sourceFromHex(a))},c.Color.sourceFromHex=function(a){if(a.match(b.reHex)){var c=a.slice(a.indexOf("#")+1),d=3===c.length|| +4===c.length,f=8===c.length||4===c.length;a=d?c.charAt(0)+c.charAt(0):c.substring(0,2);var l=d?c.charAt(1)+c.charAt(1):c.substring(2,4),e=d?c.charAt(2)+c.charAt(2):c.substring(4,6),c=f?d?c.charAt(3)+c.charAt(3):c.substring(6,8):"FF";return[parseInt(a,16),parseInt(l,16),parseInt(e,16),parseFloat((parseInt(c,16)/255).toFixed(2))]}},c.Color.fromSource=function(a){var c=new b;c.setSource(a);return c})})("undefined"!==typeof exports?exports:this); +(function(){function e(c){var a=c.getAttribute("style"),b=c.getAttribute("offset")||0,d,f,b=parseFloat(b)/(/%$/.test(b)?100:1),b=0>b?0:1a.r2;h.sort(function(a,f){return a.offset-f.offset});if(!b.group||"path-group"!==b.group.type)for(var l in a)if("x1"===l||"x2"===l)a[l]+=this.offsetX-b.width/2;else if("y1"===l||"y2"===l)a[l]+=this.offsetY-b.height/2;b='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"';this.gradientTransform&&(b+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" ');"linear"===this.type?c=["\n']:"radial"===this.type&&(c=["\n']);if("radial"===this.type){if(f)for(h=h.concat(),h.reverse(),f=0;f\n');c.push("linear"===this.type?"\n":"\n");return c.join("")},toLive:function(b,a){var c,d,f=fabric.util.object.clone(this.coords);if(this.type){if(a.group&&"path-group"===a.group.type)for(d in f)if("x1"===d||"x2"===d)f[d]+=-this.offsetX+a.width/2;else if("y1"===d||"y2"===d)f[d]+=-this.offsetY+a.height/2;"linear"===this.type?c=b.createLinearGradient(f.x1,f.y1,f.x2,f.y2):"radial"=== +this.type&&(c=b.createRadialGradient(f.x1,f.y1,f.r1,f.x2,f.y2,f.r2));d=0;for(f=this.colorStops.length;d\n\n\n'},setOptions:function(b){for(var d in b)this[d]=b[d]}, +toLive:function(b){var d="function"===typeof this.source?this.source():this.source;return d&&("undefined"===typeof d.src||d.complete&&0!==d.naturalWidth&&0!==d.naturalHeight)?b.createPattern(d,this.repeat):""}})})(); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.toFixed;b.Shadow?b.warn("fabric.Shadow is already defined."):(b.Shadow=b.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(c){"string"===typeof c&&(c=this._parseShadow(c));for(var a in c)this[a]=c[a];this.id=b.Object.__uid++},_parseShadow:function(c){c=c.trim();var a=b.Shadow.reOffsetsAndBlur.exec(c)||[];return{color:(c.replace(b.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(), +offsetX:parseInt(a[1],10)||0,offsetY:parseInt(a[2],10)||0,blur:parseInt(a[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(c){var a=40,g=40,h=b.Object.NUM_FRACTION_DIGITS,f=b.util.rotateVector({x:this.offsetX,y:this.offsetY},b.util.degreesToRadians(-c.angle));c.width&&c.height&&(a=100*d((Math.abs(f.x)+this.blur)/c.width,h)+20,g=100*d((Math.abs(f.y)+this.blur)/c.height,h)+20);c.flipX&&(f.x*=-1);c.flipY&&(f.y*=-1);return'\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 c={},a=b.Shadow.prototype;["color","blur","offsetX","offsetY","affectStroke"].forEach(function(b){this[b]!==a[b]&&(c[b]=this[b])},this);return c}}),b.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/)})("undefined"!==typeof exports?exports:this); +(function(){if(fabric.StaticCanvas)fabric.warn("fabric.StaticCanvas is already defined.");else{var e=fabric.util.object.extend,b=fabric.util.getElementOffset,d=fabric.util.removeFromArray,c=fabric.util.toFixed,a=fabric.util.transformPoint,g=fabric.util.invertTransform,h=Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(a,b){b||(b={});this._initStatic(a,b)},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:!1,_initStatic:function(a,b){var f=fabric.StaticCanvas.prototype.renderAll.bind(this);this._objects=[];this._createLowerCanvas(a);this._initOptions(b);this._setImageSmoothing();this.interactive||this._initRetinaScaling(); +b.overlayImage&&this.setOverlayImage(b.overlayImage,f);b.backgroundImage&&this.setBackgroundImage(b.backgroundImage,f);b.backgroundColor&&this.setBackgroundColor(b.backgroundColor,f);b.overlayColor&&this.setOverlayColor(b.overlayColor,f);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(){this._offset=b(this.lowerCanvasEl);return this},setOverlayImage:function(a,b,c){return this.__setBgOverlayImage("overlayImage",a,b,c)},setBackgroundImage:function(a,b,c){return this.__setBgOverlayImage("backgroundImage",a,b,c)},setOverlayColor:function(a,b){return this.__setBgOverlayColor("overlayColor", +a,b)},setBackgroundColor:function(a,b){return this.__setBgOverlayColor("backgroundColor",a,b)},_setImageSmoothing:function(){var a=this.getContext();a.imageSmoothingEnabled=a.imageSmoothingEnabled||a.webkitImageSmoothingEnabled||a.mozImageSmoothingEnabled||a.msImageSmoothingEnabled||a.oImageSmoothingEnabled;a.imageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(a,b,c,d){"string"===typeof b?fabric.util.loadImage(b,function(b){b&&(this[a]=new fabric.Image(b,d));c&&c(b)},this, +d&&d.crossOrigin):(d&&b.setOptions(d),this[a]=b,c&&c(b));return this},__setBgOverlayColor:function(a,b,c){this[a]=b;this._initGradient(b,a);this._initPattern(b,a,c);return this},_createCanvasElement:function(a){a=fabric.util.createCanvasElement(a);a.style||(a.style={});if(!a)throw h;if("undefined"===typeof a.getContext)throw h;return a},_initOptions:function(a){this._setOptions(a);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(a){this.lowerCanvasEl=fabric.util.getById(a)||this._createCanvasElement(a);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(a,b){return this.setDimensions({width:a},b)},setHeight:function(a,b){return this.setDimensions({height:a},b)},setDimensions:function(a,b){var f;b=b||{};for(var c in a)f=a[c],b.cssOnly||(this._setBackstoreDimension(c,a[c]),f+="px"),b.backstoreOnly||this._setCssDimension(c,f);this._initRetinaScaling();this._setImageSmoothing();this.calcOffset();b.cssOnly||this.renderAll(); +return this},_setBackstoreDimension:function(a,b){this.lowerCanvasEl[a]=b;this.upperCanvasEl&&(this.upperCanvasEl[a]=b);this.cacheCanvasEl&&(this.cacheCanvasEl[a]=b);this[a]=b;return this},_setCssDimension:function(a,b){this.lowerCanvasEl.style[a]=b;this.upperCanvasEl&&(this.upperCanvasEl.style[a]=b);this.wrapperEl&&(this.wrapperEl.style[a]=b);return this},getZoom:function(){return this.viewportTransform[0]},setViewportTransform:function(a){var b=this._activeGroup;this.viewportTransform=a;for(var f= +0,c=this._objects.length;f");return c.join("")},_setSVGPreamble:function(a,b){b.suppressPreamble||a.push('\n','\n')},_setSVGHeader:function(a,b){var f=b.width||this.width,d= +b.height||this.height,g;g='viewBox="0 0 '+this.width+" "+this.height+'" ';var h=fabric.Object.NUM_FRACTION_DIGITS;b.viewBox?g='viewBox="'+b.viewBox.x+" "+b.viewBox.y+" "+b.viewBox.width+" "+b.viewBox.height+'" ':this.svgViewportTransformation&&(g=this.viewportTransform,g='viewBox="'+c(-g[4]/g[0],h)+" "+c(-g[5]/g[3],h)+" "+c(this.width/g[0],h)+" "+c(this.height/g[3],h)+'" ');a.push("\n',"Created with Fabric.js ",fabric.version,"\n","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),"\n")},createSVGRefElementsMarkup:function(){var a=this;return["backgroundColor","overlayColor"].map(function(b){if((b=a[b])&&b.toLive)return b.toSVG(a,!1)}).join("")},createSVGFontFacesMarkup:function(){for(var a="",b={},c,d,g,h,e,t=fabric.fontPaths,r=this.getObjects(),v=0,A=r.length;v\n',a,"]]\x3e</style>\n"].join(""));return a},_setSVGObjects:function(a,b){for(var c,f=0,d=this.getObjects(),g=d.length;f<g;f++)c=d[f],c.excludeFromExport||this._setSVGObject(a,c,b)},_setSVGObject:function(a, +b,c){a.push(b.toSVG(c))},_setSVGBgOverlayImage:function(a,b,c){this[b]&&this[b].toSVG&&a.push(this[b].toSVG(c))},_setSVGBgOverlayColor:function(a,b){var c=this[b];if(c)if(c.toLive){var f=c.repeat;a.push('<rect transform="translate(',this.width/2,",",this.height/2,')"',' x="',c.offsetX-this.width/2,'" y="',c.offsetY-this.height/2,'" ','width="',"repeat-y"===f||"no-repeat"===f?c.source.width:this.width,'" height="',"repeat-x"===f||"no-repeat"===f?c.source.height:this.height,'" fill="url(#SVGID_'+c.id+ +')"',"></rect>\n")}else a.push('<rect x="0" y="0" ','width="',this.width,'" height="',this.height,'" fill="',this[b],'"',"></rect>\n")},sendToBack:function(a){if(!a)return this;var b=this._activeGroup,c;if(a===b)for(c=b._objects,a=c.length;a--;)b=c[a],d(this._objects,b),this._objects.unshift(b);else d(this._objects,a),this._objects.unshift(a);return this.renderAll&&this.renderAll()},bringToFront:function(a){if(!a)return this;var b=this._activeGroup,c;if(a===b)for(c=b._objects,a=0;a<c.length;a++)b= +c[a],d(this._objects,b),this._objects.push(b);else d(this._objects,a),this._objects.push(a);return this.renderAll&&this.renderAll()},sendBackwards:function(a,b){if(!a)return this;var c=this._activeGroup,f,g,h,e=0;if(a===c)for(h=c._objects,c=0;c<h.length;c++)f=h[c],g=this._objects.indexOf(f),g>0+e&&(--g,d(this._objects,f),this._objects.splice(g,0,f)),e++;else g=this._objects.indexOf(a),0!==g&&(g=this._findNewLowerIndex(a,g,b),d(this._objects,a),this._objects.splice(g,0,a));this.renderAll&&this.renderAll(); +return this},_findNewLowerIndex:function(a,b,c){if(c)for(c=b,--b;0<=b;--b){if(a.intersectsWithObject(this._objects[b])||a.isContainedWithinObject(this._objects[b])||this._objects[b].isContainedWithinObject(a)){c=b;break}}else c=b-1;return c},bringForward:function(a,b){if(!a)return this;var c=this._activeGroup,f,g,h,e=0;if(a===c)for(h=c._objects,c=h.length;c--;)f=h[c],g=this._objects.indexOf(f),g<this._objects.length-1-e&&(g+=1,d(this._objects,f),this._objects.splice(g,0,f)),e++;else g=this._objects.indexOf(a), +g!==this._objects.length-1&&(g=this._findNewUpperIndex(a,g,b),d(this._objects,a),this._objects.splice(g,0,a));this.renderAll&&this.renderAll();return this},_findNewUpperIndex:function(a,b,c){if(c)for(c=b,b+=1;b<this._objects.length;++b){if(a.intersectsWithObject(this._objects[b])||a.isContainedWithinObject(this._objects[b])||this._objects[b].isContainedWithinObject(a)){c=b;break}}else c=b+1;return c},moveTo:function(a,b){d(this._objects,a);this._objects.splice(b,0,a);return this.renderAll&&this.renderAll()}, +dispose:function(){this.clear();return this},toString:function(){return"#<fabric.Canvas ("+this.complexity()+"): { objects: "+this.getObjects().length+" }>"}});e(fabric.StaticCanvas.prototype,fabric.Observable);e(fabric.StaticCanvas.prototype,fabric.Collection);e(fabric.StaticCanvas.prototype,fabric.DataURLExporter);e(fabric.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(a){var b=fabric.util.createCanvasElement();if(!b||!b.getContext)return null;var c=b.getContext("2d"); +if(!c)return null;switch(a){case "getImageData":return"undefined"!==typeof c.getImageData;case "setLineDash":return"undefined"!==typeof c.setLineDash;case "toDataURL":return"undefined"!==typeof b.toDataURL;case "toDataURLWithQuality":try{return b.toDataURL("image/jpeg",0),!0}catch(m){}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(e){this.shadow=new fabric.Shadow(e);return this},_setBrushStyles:function(){var e=this.canvas.contextTop;e.strokeStyle=this.color;e.lineWidth=this.width;e.lineCap=this.strokeLineCap;e.lineJoin=this.strokeLineJoin;this.strokeDashArray&&fabric.StaticCanvas.supports("setLineDash")&&e.setLineDash(this.strokeDashArray)},_setShadow:function(){if(this.shadow){var e= +this.canvas.contextTop,b=this.canvas.getZoom();e.shadowColor=this.shadow.color;e.shadowBlur=this.shadow.blur*b;e.shadowOffsetX=this.shadow.offsetX*b;e.shadowOffsetY=this.shadow.offsetY*b}},_resetShadow:function(){var e=this.canvas.contextTop;e.shadowColor="";e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0}}); +(function(){fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{initialize:function(e){this.canvas=e;this._points=[]},onMouseDown:function(e){this._prepareForDrawing(e);this._captureDrawingPath(e);this._render()},onMouseMove:function(e){this._captureDrawingPath(e);this.canvas.clearContext(this.canvas.contextTop);this._render()},onMouseUp:function(){this._finalizeAndAddPath()},_prepareForDrawing:function(e){e=new fabric.Point(e.x,e.y);this._reset();this._addPoint(e);this.canvas.contextTop.moveTo(e.x, +e.y)},_addPoint:function(e){1<this._points.length&&e.eq(this._points[this._points.length-1])||this._points.push(e)},_reset:function(){this._points.length=0;this._setBrushStyles();this._setShadow()},_captureDrawingPath:function(e){e=new fabric.Point(e.x,e.y);this._addPoint(e)},_render:function(){var e=this.canvas.contextTop,b,d;b=this.canvas.viewportTransform;var c=this._points[0],a=this._points[1];e.save();e.transform(b[0],b[1],b[2],b[3],b[4],b[5]);e.beginPath();2===this._points.length&&c.x===a.x&& +c.y===a.y&&(b=this.width/1E3,c=new fabric.Point(c.x,c.y),a=new fabric.Point(a.x,a.y),c.x-=b,a.x+=b);e.moveTo(c.x,c.y);b=1;for(d=this._points.length;b<d;b++)a=c.midPointFrom(a),e.quadraticCurveTo(c.x,c.y,a.x,a.y),c=this._points[b],a=this._points[b+1];e.lineTo(c.x,c.y);e.stroke();e.restore()},convertPointsToSVGPath:function(e){var b=[],d,c=this.width/1E3,a=new fabric.Point(e[0].x,e[0].y),g=new fabric.Point(e[1].x,e[1].y),h=e.length,f=1,l=1,k=2<h;k&&(f=e[2].x<g.x?-1:e[2].x===g.x?0:1,l=e[2].y<g.y?-1: +e[2].y===g.y?0:1);b.push("M ",a.x-f*c," ",a.y-l*c," ");for(d=1;d<h;d++){if(!a.eq(g)){var m=a.midPointFrom(g);b.push("Q ",a.x," ",a.y," ",m.x," ",m.y," ")}a=e[d];d+1<e.length&&(g=e[d+1])}k&&(f=a.x>e[d-2].x?1:a.x===e[d-2].x?0:-1,l=a.y>e[d-2].y?1:a.y===e[d-2].y?0:-1);b.push("L ",a.x+f*c," ",a.y+l*c);return b},createPath:function(e){e=new fabric.Path(e,{fill:null,stroke:this.color,strokeWidth:this.width,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeDashArray:this.strokeDashArray, +originX:"center",originY:"center"});var b=new fabric.Point(e.left,e.top);e.originX=fabric.Object.prototype.originX;e.originY=fabric.Object.prototype.originY;b=e.translateToGivenOrigin(b,"center","center",e.originX,e.originY);e.top=b.y;e.left=b.x;this.shadow&&(this.shadow.affectStroke=!0,e.setShadow(this.shadow));return e},_finalizeAndAddPath:function(){this.canvas.contextTop.closePath();var e=this.convertPointsToSVGPath(this._points).join("");"M 0 0 Q 0 0 0 0 L 0 0"===e?this.canvas.renderAll():(e= +this.createPath(e),this.canvas.add(e),e.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire("path:created",{path:e}))}})})(); +fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(e){this.canvas=e;this.points=[]},drawDot:function(e){e=this.addPoint(e);var b=this.canvas.contextTop,d=this.canvas.viewportTransform;b.save();b.transform(d[0],d[1],d[2],d[3],d[4],d[5]);b.fillStyle=e.fill;b.beginPath();b.arc(e.x,e.y,e.radius,0,2*Math.PI,!1);b.closePath();b.fill();b.restore()},onMouseDown:function(e){this.points.length=0;this.canvas.clearContext(this.canvas.contextTop);this._setShadow();this.drawDot(e)}, +onMouseMove:function(e){this.drawDot(e)},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var b=[],d=0,c=this.points.length;d<c;d++){var a=this.points[d],a=new fabric.Circle({radius:a.radius,left:a.x,top:a.y,originX:"center",originY:"center",fill:a.fill});this.shadow&&a.setShadow(this.shadow);b.push(a)}b=new fabric.Group(b,{originX:"center",originY:"center"});b.canvas=this.canvas;this.canvas.add(b);this.canvas.fire("path:created",{path:b});this.canvas.clearContext(this.canvas.contextTop); +this._resetShadow();this.canvas.renderOnAddRemove=e;this.canvas.renderAll()},addPoint:function(e){e=new fabric.Point(e.x,e.y);var b=fabric.util.getRandomInt(Math.max(0,this.width-20),this.width+20)/2,d=(new fabric.Color(this.color)).setAlpha(fabric.util.getRandomInt(0,100)/100).toRgba();e.radius=b;e.fill=d;this.points.push(e);return e}}); +fabric.SprayBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,density:20,dotWidth:1,dotWidthVariance:1,randomOpacity:!1,optimizeOverlapping:!0,initialize:function(e){this.canvas=e;this.sprayChunks=[]},onMouseDown:function(e){this.sprayChunks.length=0;this.canvas.clearContext(this.canvas.contextTop);this._setShadow();this.addSprayChunk(e);this.render()},onMouseMove:function(e){this.addSprayChunk(e);this.render()},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove= +!1;for(var b=[],d=0,c=this.sprayChunks.length;d<c;d++)for(var a=this.sprayChunks[d],g=0,h=a.length;g<h;g++){var f=new fabric.Rect({width:a[g].width,height:a[g].width,left:a[g].x+1,top:a[g].y+1,originX:"center",originY:"center",fill:this.color});this.shadow&&f.setShadow(this.shadow);b.push(f)}this.optimizeOverlapping&&(b=this._getOptimizedRects(b));b=new fabric.Group(b,{originX:"center",originY:"center"});b.canvas=this.canvas;this.canvas.add(b);this.canvas.fire("path:created",{path:b});this.canvas.clearContext(this.canvas.contextTop); +this._resetShadow();this.canvas.renderOnAddRemove=e;this.canvas.renderAll()},_getOptimizedRects:function(e){for(var b={},d,c=0,a=e.length;c<a;c++)d=e[c].left+""+e[c].top,b[d]||(b[d]=e[c]);e=[];for(d in b)e.push(b[d]);return e},render:function(){var e=this.canvas.contextTop;e.fillStyle=this.color;var b=this.canvas.viewportTransform;e.save();e.transform(b[0],b[1],b[2],b[3],b[4],b[5]);for(var b=0,d=this.sprayChunkPoints.length;b<d;b++){var c=this.sprayChunkPoints[b];"undefined"!==typeof c.opacity&&(e.globalAlpha= +c.opacity);e.fillRect(c.x,c.y,c.width,c.width)}e.restore()},addSprayChunk:function(e){this.sprayChunkPoints=[];for(var b,d,c,a=this.width/2,g=0;g<this.density;g++)b=fabric.util.getRandomInt(e.x-a,e.x+a),d=fabric.util.getRandomInt(e.y-a,e.y+a),c=this.dotWidthVariance?fabric.util.getRandomInt(Math.max(1,this.dotWidth-this.dotWidthVariance),this.dotWidth+this.dotWidthVariance):this.dotWidth,b=new fabric.Point(b,d),b.width=c,this.randomOpacity&&(b.opacity=fabric.util.getRandomInt(0,100)/100),this.sprayChunkPoints.push(b); +this.sprayChunks.push(this.sprayChunkPoints)}}); +fabric.PatternBrush=fabric.util.createClass(fabric.PencilBrush,{getPatternSrc:function(){var e=fabric.document.createElement("canvas"),b=e.getContext("2d");e.width=e.height=25;b.fillStyle=this.color;b.beginPath();b.arc(10,10,10,0,2*Math.PI,!1);b.closePath();b.fill();return e},getPatternSrcFunction:function(){return String(this.getPatternSrc).replace("this.color",'"'+this.color+'"')},getPattern:function(){return this.canvas.contextTop.createPattern(this.source||this.getPatternSrc(),"repeat")},_setBrushStyles:function(){this.callSuper("_setBrushStyles"); +this.canvas.contextTop.strokeStyle=this.getPattern()},createPath:function(e){e=this.callSuper("createPath",e);var b=e._getLeftTopCoords().scalarAdd(e.strokeWidth/2);e.stroke=new fabric.Pattern({source:this.source||this.getPatternSrcFunction(),offsetX:-b.x,offsetY:-b.y});return e}}); +(function(){var e=fabric.util.getPointer,b=fabric.util.degreesToRadians,d=fabric.util.radiansToDegrees,c=Math.atan2,a=Math.abs,g=fabric.StaticCanvas.supports("setLineDash");fabric.Canvas=fabric.util.createClass(fabric.StaticCanvas,{initialize:function(a,b){b||(b={});this._initStatic(a,b);this._initInteractive();this._createCacheCanvas()},uniScaleTransform:!1,uniScaleKey:"shiftKey",centeredScaling:!1,centeredRotation:!1,centeredKey:"altKey",altActionKey:"shiftKey",interactive:!0,selection:!0,selectionKey:"shiftKey", +altSelectionKey:null,selectionColor:"rgba(100, 100, 255, 0.3)",selectionDashArray:[],selectionBorderColor:"rgba(255, 255, 255, 0.3)",selectionLineWidth:1,hoverCursor:"move",moveCursor:"move",defaultCursor:"default",freeDrawingCursor:"crosshair",rotationCursor:"crosshair",containerClass:"canvas-container",perPixelTargetFind:!1,targetFindTolerance:0,skipTargetFind:!1,isDrawingMode:!1,preserveObjectStacking:!1,snapAngle:0,snapThreshold:null,stopContextMenu:!1,fireRightClick:!1,fireMiddleClick:!1,_initInteractive:function(){this._groupSelector= +this._currentTransform=null;this._initWrapperElement();this._createUpperCanvas();this._initEventListeners();this._initRetinaScaling();this.freeDrawingBrush=fabric.PencilBrush&&new fabric.PencilBrush(this);this.calcOffset()},_chooseObjectsToRender:function(){var a=this.getActiveGroup(),b=this.getActiveObject(),c,d=[],g=[];if(!a&&!b||this.preserveObjectStacking)d=this._objects;else{for(var h=0,e=this._objects.length;h<e;h++)c=this._objects[h],a&&a.contains(c)||c===b?g.push(c):d.push(c);a&&(a._set("_objects", +g),d.push(a));b&&d.push(b)}return d},renderAll:function(){!this.contextTopDirty||this._groupSelector||this.isDrawingMode||(this.clearContext(this.contextTop),this.contextTopDirty=!1);this.renderCanvas(this.contextContainer,this._chooseObjectsToRender());return this},renderTop:function(){var a=this.contextTop;this.clearContext(a);this.selection&&this._groupSelector&&this._drawSelection(a);this.fire("after:render");this.contextTopDirty=!0;return this},_resetCurrentTransform:function(){var a=this._currentTransform; +a.target.set({scaleX:a.original.scaleX,scaleY:a.original.scaleY,skewX:a.original.skewX,skewY:a.original.skewY,left:a.original.left,top:a.original.top});this._shouldCenterTransform(a.target)?"rotate"===a.action?this._setOriginToCenter(a.target):("center"!==a.originX&&(a.mouseXSign="right"===a.originX?-1:1),"center"!==a.originY&&(a.mouseYSign="bottom"===a.originY?-1:1),a.originX="center",a.originY="center"):(a.originX=a.original.originX,a.originY=a.original.originY)},containsPoint:function(a,b,c){a= +c||this.getPointer(a,!0);c=b.group&&b.group===this.getActiveGroup()?this._normalizePointer(b.group,a):{x:a.x,y:a.y};return b.containsPoint(c)||b._findTargetCorner(a)},_normalizePointer:function(a,b){var c=a.calcTransformMatrix(),c=fabric.util.invertTransform(c),f=this.restorePointerVpt(b);return fabric.util.transformPoint(f,c)},isTargetTransparent:function(a,b,c){var f=a.hasBorders,d=a.transparentCorners,g=this.contextCache,h=a.selectionBackgroundColor;a.hasBorders=a.transparentCorners=!1;a.selectionBackgroundColor= +"";g.save();g.transform.apply(g,this.viewportTransform);a.render(g);g.restore();a.active&&a._renderControls(g);a.hasBorders=f;a.transparentCorners=d;a.selectionBackgroundColor=h;a=fabric.util.isTransparent(g,b,c,this.targetFindTolerance);this.clearContext(g);return a},_shouldClearSelection:function(a,b){var c=this.getActiveGroup(),f=this.getActiveObject();return!b||b&&c&&!c.contains(b)&&c!==b&&!a[this.selectionKey]||b&&!b.evented||b&&!b.selectable&&f&&f!==b},_shouldCenterTransform:function(a){if(a){var b= +this._currentTransform,c;"scale"===b.action||"scaleX"===b.action||"scaleY"===b.action?c=this.centeredScaling||a.centeredScaling:"rotate"===b.action&&(c=this.centeredRotation||a.centeredRotation);return c?!b.altKey:b.altKey}},_getOriginFromCorner:function(a,b){var c={x:a.originX,y:a.originY};if("ml"===b||"tl"===b||"bl"===b)c.x="right";else if("mr"===b||"tr"===b||"br"===b)c.x="left";if("tl"===b||"mt"===b||"tr"===b)c.y="bottom";else if("bl"===b||"mb"===b||"br"===b)c.y="top";return c},_getActionFromCorner:function(a, +b,c){if(!b)return"drag";switch(b){case "mtr":return"rotate";case "ml":case "mr":return c[this.altActionKey]?"skewY":"scaleX";case "mt":case "mb":return c[this.altActionKey]?"skewX":"scaleY";default:return"scale"}},_setupCurrentTransform:function(a,c){if(c){var f=this.getPointer(a),d=c._findTargetCorner(this.getPointer(a,!0)),g=this._getActionFromCorner(c,d,a),h=this._getOriginFromCorner(c,d);this._currentTransform={target:c,action:g,corner:d,scaleX:c.scaleX,scaleY:c.scaleY,skewX:c.skewX,skewY:c.skewY, +offsetX:f.x-c.left,offsetY:f.y-c.top,originX:h.x,originY:h.y,ex:f.x,ey:f.y,lastX:f.x,lastY:f.y,left:c.left,top:c.top,theta:b(c.angle),width:c.width*c.scaleX,mouseXSign:1,mouseYSign:1,shiftKey:a.shiftKey,altKey:a[this.centeredKey]};this._currentTransform.original={left:c.left,top:c.top,scaleX:c.scaleX,scaleY:c.scaleY,skewX:c.skewX,skewY:c.skewY,originX:h.x,originY:h.y};this._resetCurrentTransform()}},_translateObject:function(a,b){var c=this._currentTransform,f=c.target,d=a-c.offsetX,c=b-c.offsetY, +g=!f.get("lockMovementX")&&f.left!==d,h=!f.get("lockMovementY")&&f.top!==c;g&&f.set("left",d);h&&f.set("top",c);return g||h},_changeSkewTransformOrigin:function(a,b,c){var f="originX",d={0:"center"},g=b.target.skewX,h="left",e="right",l="mt"===b.corner||"ml"===b.corner?1:-1,k=1;a=0<a?1:-1;"y"===c&&(g=b.target.skewY,h="top",e="bottom",f="originY");d[-1]=h;d[1]=e;b.target.flipX&&(k*=-1);b.target.flipY&&(k*=-1);0===g?(b.skewSign=-l*a*k,b[f]=d[-a]):(g=0<g?1:-1,b.skewSign=g,b[f]=d[g*l*k])},_skewObject:function(a, +b,c){var f=this._currentTransform,d=f.target,g=d.get("lockSkewingX"),h=d.get("lockSkewingY");if(g&&"x"===c||h&&"y"===c)return!1;var h=d.getCenterPoint(),e=d.toLocalPoint(new fabric.Point(a,b),"center","center")[c],l=d.toLocalPoint(new fabric.Point(f.lastX,f.lastY),"center","center")[c],g=d._getTransformedDimensions();this._changeSkewTransformOrigin(e-l,f,c);e=d.toLocalPoint(new fabric.Point(a,b),f.originX,f.originY)[c];h=d.translateToOriginPoint(h,f.originX,f.originY);c=this._setObjectSkew(e,f,c, +g);f.lastX=a;f.lastY=b;d.setPositionByOrigin(h,f.originX,f.originY);return c},_setObjectSkew:function(a,b,c,d){var f=b.target,g=b.skewSign,h,e,l,k;"x"===c?(b="y",l="Y",h="X",e=0,k=f.skewY):(b="x",l="X",h="Y",e=f.skewX,k=0);e=f._getTransformedDimensions(e,k);a=2*Math.abs(a)-e[c];2>=a?c=0:(c=g*Math.atan(a/f["scale"+h]/(e[b]/f["scale"+l])),c=fabric.util.radiansToDegrees(c));a=f["skew"+h]!==c;f.set("skew"+h,c);0!==f["skew"+l]&&(h=f._getTransformedDimensions(),c=d[b]/h[b]*f["scale"+l],f.set("scale"+l, +c));return a},_scaleObject:function(a,b,c){var f=this._currentTransform,d=f.target,g=d.get("lockScalingX"),h=d.get("lockScalingY"),e=d.get("lockScalingFlip");if(g&&h)return!1;var l=d.translateToOriginPoint(d.getCenterPoint(),f.originX,f.originY);a=d.toLocalPoint(new fabric.Point(a,b),f.originX,f.originY);b=d._getTransformedDimensions();this._setLocalMouse(a,f);c=this._setObjectScale(a,f,g,h,c,e,b);d.setPositionByOrigin(l,f.originX,f.originY);return c},_setObjectScale:function(a,b,c,d,g,h,e){var f= +b.target,l=!1,k=!1,m=!1,n,p,q,u;q=a.x*f.scaleX/e.x;u=a.y*f.scaleY/e.y;n=f.scaleX!==q;p=f.scaleY!==u;h&&0>=q&&q<f.scaleX&&(l=!0);h&&0>=u&&u<f.scaleY&&(k=!0);"equally"!==g||c||d?g?"x"!==g||f.get("lockUniScaling")?"y"!==g||f.get("lockUniScaling")||k||d||f.set("scaleY",u)&&(m=m||p):l||c||f.set("scaleX",q)&&(m=m||n):(l||c||f.set("scaleX",q)&&(m=m||n),k||d||f.set("scaleY",u)&&(m=m||p)):l||k||(m=this._scaleObjectEqually(a,f,b,e));b.newScaleX=q;b.newScaleY=u;l||k||this._flipObject(b,g);return m},_scaleObjectEqually:function(a, +b,c,d){var f=a.y+a.x;d=d.y*c.original.scaleY/b.scaleY+d.x*c.original.scaleX/b.scaleX;var g=a.y/Math.abs(a.y);c.newScaleX=a.x/Math.abs(a.x)*Math.abs(c.original.scaleX*f/d);c.newScaleY=g*Math.abs(c.original.scaleY*f/d);a=c.newScaleX!==b.scaleX||c.newScaleY!==b.scaleY;b.set("scaleX",c.newScaleX);b.set("scaleY",c.newScaleY);return a},_flipObject:function(a,b){0>a.newScaleX&&"y"!==b&&("left"===a.originX?a.originX="right":"right"===a.originX&&(a.originX="left"));0>a.newScaleY&&"x"!==b&&("top"===a.originY? +a.originY="bottom":"bottom"===a.originY&&(a.originY="top"))},_setLocalMouse:function(b,c){var d=c.target,f=this.getZoom(),d=d.padding/f;"right"===c.originX?b.x*=-1:"center"===c.originX&&(b.x=2*b.x*c.mouseXSign,0>b.x&&(c.mouseXSign=-c.mouseXSign));"bottom"===c.originY?b.y*=-1:"center"===c.originY&&(b.y=2*b.y*c.mouseYSign,0>b.y&&(c.mouseYSign=-c.mouseYSign));a(b.x)>d?b.x=0>b.x?b.x+d:b.x-d:b.x=0;a(b.y)>d?b.y=0>b.y?b.y+d:b.y-d:b.y=0},_rotateObject:function(a,b){var f=this._currentTransform;if(f.target.get("lockRotation"))return!1; +var g=c(f.ey-f.top,f.ex-f.left),h=c(b-f.top,a-f.left),g=d(h-g+f.theta),h=!0;if(0<f.target.snapAngle){var e=f.target.snapAngle,l=f.target.snapThreshold||e,t=Math.ceil(g/e)*e,e=Math.floor(g/e)*e;Math.abs(g-e)<l?g=e:Math.abs(g-t)<l&&(g=t)}0>g&&(g=360+g);g%=360;f.target.angle===g?h=!1:f.target.angle=g;return h},setCursor:function(a){this.upperCanvasEl.style.cursor=a},_resetObjectTransform:function(a){a.scaleX=1;a.scaleY=1;a.skewX=0;a.skewY=0;a.setAngle(0)},_drawSelection:function(b){var c=this._groupSelector, +d=c.left,f=c.top,h=a(d),e=a(f);this.selectionColor&&(b.fillStyle=this.selectionColor,b.fillRect(c.ex-(0<d?0:-d),c.ey-(0<f?0:-f),h,e));this.selectionLineWidth&&this.selectionBorderColor&&(b.lineWidth=this.selectionLineWidth,b.strokeStyle=this.selectionBorderColor,1<this.selectionDashArray.length&&!g?(d=c.ex+.5-(0<d?0:h),c=c.ey+.5-(0<f?0:e),b.beginPath(),fabric.util.drawDashedLine(b,d,c,d+h,c,this.selectionDashArray),fabric.util.drawDashedLine(b,d,c+e-1,d+h,c+e-1,this.selectionDashArray),fabric.util.drawDashedLine(b, +d,c,d,c+e,this.selectionDashArray),fabric.util.drawDashedLine(b,d+h-1,c,d+h-1,c+e,this.selectionDashArray),b.closePath(),b.stroke()):(fabric.Object.prototype._setLineDash.call(this,b,this.selectionDashArray),b.strokeRect(c.ex+.5-(0<d?0:h),c.ey+.5-(0<f?0:e),h,e)))},findTarget:function(a,b){if(!this.skipTargetFind){var c=this.getPointer(a,!0),d=this.getActiveGroup(),f=this.getActiveObject(),g,h;this.targets=[];if(d&&!b&&d===this._searchPossibleTargets([d],c))return this._fireOverOutEvents(d,a),d;if(f&& +f._findTargetCorner(c))return this._fireOverOutEvents(f,a),f;if(f&&f===this._searchPossibleTargets([f],c))if(this.preserveObjectStacking)g=f,h=this.targets,this.targets=[];else return this._fireOverOutEvents(f,a),f;c=this._searchPossibleTargets(this._objects,c);a[this.altSelectionKey]&&c&&g&&c!==g&&(c=g,this.targets=h);this._fireOverOutEvents(c,a);return c}},_fireOverOutEvents:function(a,b){var c,d,f=this._hoveredTarget;f!==a&&(c={e:b,target:a,previousTarget:this._hoveredTarget},d={e:b,target:this._hoveredTarget, +nextTarget:a},this._hoveredTarget=a);a?f!==a&&(f&&(this.fire("mouse:out",d),f.fire("mouseout",d)),this.fire("mouse:over",c),a.fire("mouseover",c)):f&&(this.fire("mouse:out",d),f.fire("mouseout",d))},_checkTarget:function(a,b){if(b&&b.visible&&b.evented&&this.containsPoint(null,b,a)&&(!this.perPixelTargetFind&&!b.perPixelTargetFind||b.isEditing||!this.isTargetTransparent(b,a.x,a.y)))return!0},_searchPossibleTargets:function(a,b){for(var c,d=a.length;d--;)if(this._checkTarget(b,a[d])){c=a[d];"group"=== +c.type&&c.subTargetCheck&&(d=this._normalizePointer(c,b),(d=this._searchPossibleTargets(c._objects,d))&&this.targets.push(d));break}return c},restorePointerVpt:function(a){return fabric.util.transformPoint(a,fabric.util.invertTransform(this.viewportTransform))},getPointer:function(a,b,c){c||(c=this.upperCanvasEl);a=e(a);var d=c.getBoundingClientRect(),f=d.width||0,g=d.height||0;f&&g||("top"in d&&"bottom"in d&&(g=Math.abs(d.top-d.bottom)),"right"in d&&"left"in d&&(f=Math.abs(d.right-d.left)));this.calcOffset(); +a.x-=this._offset.left;a.y-=this._offset.top;b||(a=this.restorePointerVpt(a));0===f||0===g?c=b=1:(b=c.width/f,c=c.height/g);return{x:a.x*b,y:a.y*c}},_createUpperCanvas:function(){var a=this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/,"");this.upperCanvasEl?this.upperCanvasEl.className="":this.upperCanvasEl=this._createCanvasElement();fabric.util.addClass(this.upperCanvasEl,"upper-canvas "+a);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(a){var b=this.getWidth()||a.width,c=this.getHeight()||a.height;fabric.util.setStyle(a,{position:"absolute",width:b+"px",height:c+"px",left:0,top:0,"touch-action":"none"});a.width=b;a.height=c;fabric.util.makeElementUnselectable(a)},_copyCanvasStyle:function(a,b){b.style.cssText=a.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl}, +_setActiveObject:function(a){var b=this._activeObject;if(b&&(b.set("active",!1),a!==b&&b.onDeselect&&"function"===typeof b.onDeselect))b.onDeselect();this._activeObject=a;a.set("active",!0)},setActiveObject:function(a,b){var c=this.getActiveObject();c&&c!==a&&c.fire("deselected",{e:b});this._setActiveObject(a);this.fire("object:selected",{target:a,e:b});a.fire("selected",{e:b});this.renderAll();return this},getActiveObject:function(){return this._activeObject},_onObjectRemoved:function(a){this.getActiveObject()=== +a&&(this.fire("before:selection:cleared",{target:a}),this._discardActiveObject(),this.fire("selection:cleared",{target:a}),a.fire("deselected"));this._hoveredTarget===a&&(this._hoveredTarget=null);this.callSuper("_onObjectRemoved",a)},_discardActiveObject:function(){var a=this._activeObject;if(a&&(a.set("active",!1),a.onDeselect&&"function"===typeof a.onDeselect))a.onDeselect();this._activeObject=null},discardActiveObject:function(a){var b=this._activeObject;b&&(this.fire("before:selection:cleared", +{target:b,e:a}),this._discardActiveObject(),this.fire("selection:cleared",{e:a}),b.fire("deselected",{e:a}));return this},_setActiveGroup:function(a){(this._activeGroup=a)&&a.set("active",!0)},setActiveGroup:function(a,b){this._setActiveGroup(a);a&&(this.fire("object:selected",{target:a,e:b}),a.fire("selected",{e:b}));return this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var a=this.getActiveGroup();a&&a.destroy();this.setActiveGroup(null)},discardActiveGroup:function(a){var b= +this.getActiveGroup();b&&(this.fire("before:selection:cleared",{e:a,target:b}),this._discardActiveGroup(),this.fire("selection:cleared",{e:a}));return this},deactivateAll:function(){for(var a=this.getObjects(),b=0,c=a.length,d;b<c;b++)(d=a[b])&&d.set("active",!1);this._discardActiveGroup();this._discardActiveObject();return this},deactivateAllWithDispatch:function(a){for(var b=this.getObjects(),c=0,d=b.length,f;c<d;c++)(f=b[c])&&f.set("active",!1);this.discardActiveGroup(a);this.discardActiveObject(a); +return this},dispose:function(){fabric.StaticCanvas.prototype.dispose.call(this);var a=this.wrapperEl;this.removeListeners();a.removeChild(this.upperCanvasEl);a.removeChild(this.lowerCanvasEl);delete this.upperCanvasEl;a.parentNode&&a.parentNode.replaceChild(this.lowerCanvasEl,this.wrapperEl);delete this.wrapperEl;return this},clear:function(){this.discardActiveGroup();this.discardActiveObject();this.clearContext(this.contextTop);return this.callSuper("clear")},drawControls:function(a){var b=this.getActiveGroup(); +b?b._renderControls(a):this._drawObjectsControls(a)},_drawObjectsControls:function(a){for(var b=0,c=this._objects.length;b<c;++b)this._objects[b]&&this._objects[b].active&&this._objects[b]._renderControls(a)},_toObject:function(a,b,c){var d=this._realizeGroupTransformOnObject(a);b=this.callSuper("_toObject",a,b,c);this._unwindGroupTransformOnObject(a,d);return b},_realizeGroupTransformOnObject:function(a){if(a.group&&a.group===this.getActiveGroup()){var b={};"angle flipX flipY left scaleX scaleY skewX skewY top".split(" ").forEach(function(c){b[c]= +a[c]});this.getActiveGroup().realizeTransform(a);return b}return null},_unwindGroupTransformOnObject:function(a,b){b&&a.set(b)},_setSVGObject:function(a,b,c){var d;d=this._realizeGroupTransformOnObject(b);this.callSuper("_setSVGObject",a,b,c);this._unwindGroupTransformOnObject(b,d)}});for(var h in fabric.StaticCanvas)"prototype"!==h&&(fabric.Canvas[h]=fabric.StaticCanvas[h]);fabric.isTouchSupported&&(fabric.Canvas.prototype._setCursorFromEvent=function(){});fabric.Element=fabric.Canvas})(); +(function(){function e(a,b){return"which"in a?a.which===b:a.button===b-1}var b={mt:0,tr:1,mr:2,br:3,mb:4,bl:5,ml:6,tl:7},d=fabric.util.addListener,c=fabric.util.removeListener;fabric.util.object.extend(fabric.Canvas.prototype,{cursorMap:"n-resize ne-resize e-resize se-resize s-resize sw-resize w-resize nw-resize".split(" "),_initEventListeners:function(){this.removeListeners();this._bindEvents();d(fabric.window,"resize",this._onResize);d(this.upperCanvasEl,"mousedown",this._onMouseDown);d(this.upperCanvasEl, +"mousemove",this._onMouseMove);d(this.upperCanvasEl,"mouseout",this._onMouseOut);d(this.upperCanvasEl,"mouseenter",this._onMouseEnter);d(this.upperCanvasEl,"wheel",this._onMouseWheel);d(this.upperCanvasEl,"contextmenu",this._onContextMenu);d(this.upperCanvasEl,"touchstart",this._onMouseDown,{passive:!1});d(this.upperCanvasEl,"touchmove",this._onMouseMove,{passive:!1});"undefined"!==typeof eventjs&&"add"in eventjs&&(eventjs.add(this.upperCanvasEl,"gesture",this._onGesture),eventjs.add(this.upperCanvasEl, +"drag",this._onDrag),eventjs.add(this.upperCanvasEl,"orientation",this._onOrientationChange),eventjs.add(this.upperCanvasEl,"shake",this._onShake),eventjs.add(this.upperCanvasEl,"longpress",this._onLongPress))},_bindEvents:function(){this.eventsBinded||(this._onMouseDown=this._onMouseDown.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseUp=this._onMouseUp.bind(this),this._onResize=this._onResize.bind(this),this._onGesture=this._onGesture.bind(this),this._onDrag=this._onDrag.bind(this), +this._onShake=this._onShake.bind(this),this._onLongPress=this._onLongPress.bind(this),this._onOrientationChange=this._onOrientationChange.bind(this),this._onMouseWheel=this._onMouseWheel.bind(this),this._onMouseOut=this._onMouseOut.bind(this),this._onMouseEnter=this._onMouseEnter.bind(this),this._onContextMenu=this._onContextMenu.bind(this),this.eventsBinded=!0)},removeListeners:function(){c(fabric.window,"resize",this._onResize);c(this.upperCanvasEl,"mousedown",this._onMouseDown);c(this.upperCanvasEl, +"mousemove",this._onMouseMove);c(this.upperCanvasEl,"mouseout",this._onMouseOut);c(this.upperCanvasEl,"mouseenter",this._onMouseEnter);c(this.upperCanvasEl,"wheel",this._onMouseWheel);c(this.upperCanvasEl,"contextmenu",this._onContextMenu);c(this.upperCanvasEl,"touchstart",this._onMouseDown);c(this.upperCanvasEl,"touchmove",this._onMouseMove);"undefined"!==typeof eventjs&&"remove"in eventjs&&(eventjs.remove(this.upperCanvasEl,"gesture",this._onGesture),eventjs.remove(this.upperCanvasEl,"drag",this._onDrag), +eventjs.remove(this.upperCanvasEl,"orientation",this._onOrientationChange),eventjs.remove(this.upperCanvasEl,"shake",this._onShake),eventjs.remove(this.upperCanvasEl,"longpress",this._onLongPress))},_onGesture:function(a,b){this.__onTransformGesture&&this.__onTransformGesture(a,b)},_onDrag:function(a,b){this.__onDrag&&this.__onDrag(a,b)},_onMouseWheel:function(a){this.__onMouseWheel(a)},_onMouseOut:function(a){var b=this._hoveredTarget;this.fire("mouse:out",{target:b,e:a});this._hoveredTarget=null; +b&&b.fire("mouseout",{e:a});this._iTextInstances&&this._iTextInstances.forEach(function(a){a.isEditing&&a.hiddenTextarea.focus()})},_onMouseEnter:function(a){this.findTarget(a)||(this.fire("mouse:over",{target:null,e:a}),this._hoveredTarget=null)},_onOrientationChange:function(a,b){this.__onOrientationChange&&this.__onOrientationChange(a,b)},_onShake:function(a,b){this.__onShake&&this.__onShake(a,b)},_onLongPress:function(a,b){this.__onLongPress&&this.__onLongPress(a,b)},_onContextMenu:function(a){this.stopContextMenu&& +(a.stopPropagation(),a.preventDefault());return!1},_onMouseDown:function(a){this.__onMouseDown(a);d(fabric.document,"touchend",this._onMouseUp,{passive:!1});d(fabric.document,"touchmove",this._onMouseMove,{passive:!1});c(this.upperCanvasEl,"mousemove",this._onMouseMove);c(this.upperCanvasEl,"touchmove",this._onMouseMove);"touchstart"===a.type?c(this.upperCanvasEl,"mousedown",this._onMouseDown):(d(fabric.document,"mouseup",this._onMouseUp),d(fabric.document,"mousemove",this._onMouseMove))},_onMouseUp:function(a){this.__onMouseUp(a); +c(fabric.document,"mouseup",this._onMouseUp);c(fabric.document,"touchend",this._onMouseUp);c(fabric.document,"mousemove",this._onMouseMove);c(fabric.document,"touchmove",this._onMouseMove);d(this.upperCanvasEl,"mousemove",this._onMouseMove);d(this.upperCanvasEl,"touchmove",this._onMouseMove,{passive:!1});if("touchend"===a.type){var b=this;setTimeout(function(){d(b.upperCanvasEl,"mousedown",b._onMouseDown)},400)}},_onMouseMove:function(a){!this.allowTouchScrolling&&a.preventDefault&&a.preventDefault(); +this.__onMouseMove(a)},_onResize:function(){this.calcOffset()},_shouldRender:function(a,b){var c=this.getActiveGroup()||this.getActiveObject();return c&&c.isEditing&&a===c?!1:!!(a&&(a.isMoving||a!==c)||!a&&c||!a&&!c&&!this._groupSelector||b&&this._previousPointer&&this.selection&&(b.x!==this._previousPointer.x||b.y!==this._previousPointer.y))},__onMouseUp:function(a){var b;if(e(a,3))this.fireRightClick&&this._handleEvent(a,"up",b,3);else if(e(a,2))this.fireMiddleClick&&this._handleEvent(a,"up",b, +2);else if(this.isDrawingMode&&this._isCurrentlyDrawing)this._onMouseUpInDrawingMode(a);else{b=!0;var c=this._currentTransform,d=this._groupSelector,d=!d||0===d.left&&0===d.top;c&&(this._finalizeCurrentTransform(a),b=!c.actionPerformed);b=b?this.findTarget(a,!0):c.target;c=this._shouldRender(b,this.getPointer(a));b||!d?this._maybeGroupObjects(a):this._currentTransform=this._groupSelector=null;b&&(b.isMoving=!1);this._setCursorFromEvent(a,b);this._handleEvent(a,"up",b?b:null,1,d);b&&(b.__corner=0); +c&&this.renderAll()}},_handleEvent:function(a,b,c,d,e){var f="undefined"===typeof c?this.findTarget(a):c;c=this.targets||[];a={e:a,target:f,subTargets:c,button:d||1,isClick:e||!1};this.fire("mouse:"+b,a);f&&f.fire("mouse"+b,a);for(d=0;d<c.length;d++)c[d].fire("mouse"+b,a)},_finalizeCurrentTransform:function(a){var b=this._currentTransform,c=b.target;c._scaling&&(c._scaling=!1);c.setCoords();this._restoreOriginXY(c);if(b.actionPerformed||this.stateful&&c.hasStateChanged())this.fire("object:modified", +{target:c,e:a}),c.fire("modified",{e:a})},_restoreOriginXY:function(a){if(this._previousOriginX&&this._previousOriginY){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX;a.originY=this._previousOriginY;a.left=b.x;a.top=b.y;this._previousOriginY=this._previousOriginX=null}},_onMouseDownInDrawingMode:function(a){this._isCurrentlyDrawing=!0;this.discardActiveObject(a).renderAll();this.clipTo&&fabric.util.clipContext(this,this.contextTop); +var b=this.getPointer(a);this.freeDrawingBrush.onMouseDown(b);this._handleEvent(a,"down")},_onMouseMoveInDrawingMode:function(a){if(this._isCurrentlyDrawing){var b=this.getPointer(a);this.freeDrawingBrush.onMouseMove(b)}this.setCursor(this.freeDrawingCursor);this._handleEvent(a,"move")},_onMouseUpInDrawingMode:function(a){this._isCurrentlyDrawing=!1;this.clipTo&&this.contextTop.restore();this.freeDrawingBrush.onMouseUp();this._handleEvent(a,"up")},__onMouseDown:function(a){var b=this.findTarget(a); +if(e(a,3))this.fireRightClick&&this._handleEvent(a,"down",b?b:null,3);else if(e(a,2))this.fireMiddleClick&&this._handleEvent(a,"down",b?b:null,2);else if(this.isDrawingMode)this._onMouseDownInDrawingMode(a);else if(!this._currentTransform){var c=this.getPointer(a,!0);this._previousPointer=c;var d=this._shouldRender(b,c),l=this._shouldGroup(a,b);this._shouldClearSelection(a,b)?this.deactivateAllWithDispatch(a):l&&(this._handleGrouping(a,b),b=this.getActiveGroup());!this.selection||b&&(b.selectable|| +b.isEditing)||(this._groupSelector={ex:c.x,ey:c.y,top:0,left:0});b&&(!b.selectable||!b.__corner&&l||(this._beforeTransform(a,b),this._setupCurrentTransform(a,b)),c=this.getActiveObject(),b!==this.getActiveGroup()&&b!==c&&(this.deactivateAll(),b.selectable&&(c&&c.fire("deselected",{e:a}),this.setActiveObject(b,a))));this._handleEvent(a,"down",b?b:null);d&&this.renderAll()}},_beforeTransform:function(a,b){this.stateful&&b.saveState();if(b._findTargetCorner(this.getPointer(a)))this.onBeforeScaleRotate(b)}, +_setOriginToCenter:function(a){this._previousOriginX=this._currentTransform.target.originX;this._previousOriginY=this._currentTransform.target.originY;var b=a.getCenterPoint();a.originX="center";a.originY="center";a.left=b.x;a.top=b.y;this._currentTransform.left=a.left;this._currentTransform.top=a.top},_setCenterToOrigin:function(a){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX;a.originY=this._previousOriginY;a.left= +b.x;a.top=b.y;this._previousOriginY=this._previousOriginX=null},__onMouseMove:function(a){var b,c;if(this.isDrawingMode)this._onMouseMoveInDrawingMode(a);else if(!("undefined"!==typeof a.touches&&1<a.touches.length)){var d=this._groupSelector;d?(c=this.getPointer(a,!0),d.left=c.x-d.ex,d.top=c.y-d.ey,this.renderTop()):this._currentTransform?this._transformObject(a):(b=this.findTarget(a),this._setCursorFromEvent(a,b));this._handleEvent(a,"move",b?b:null)}},__onMouseWheel:function(a){this._handleEvent(a, +"wheel")},_transformObject:function(a){var b=this.getPointer(a),c=this._currentTransform;c.reset=!1;c.target.isMoving=!0;c.shiftKey=a.shiftKey;c.altKey=a[this.centeredKey];this._beforeScaleTransform(a,c);this._performTransformAction(a,c,b);c.actionPerformed&&this.renderAll()},_performTransformAction:function(a,b,c){var d=c.x,g=c.y;c=b.target;var e=b.action;if("rotate"===e)(d=this._rotateObject(d,g))&&this._fire("rotating",c,a);else if("scale"===e)(d=this._onScale(a,b,d,g))&&this._fire("scaling",c, +a);else if("scaleX"===e)(d=this._scaleObject(d,g,"x"))&&this._fire("scaling",c,a);else if("scaleY"===e)(d=this._scaleObject(d,g,"y"))&&this._fire("scaling",c,a);else if("skewX"===e)(d=this._skewObject(d,g,"x"))&&this._fire("skewing",c,a);else if("skewY"===e)(d=this._skewObject(d,g,"y"))&&this._fire("skewing",c,a);else if(d=this._translateObject(d,g))this._fire("moving",c,a),this.setCursor(c.moveCursor||this.moveCursor);b.actionPerformed=b.actionPerformed||d},_fire:function(a,b,c){this.fire("object:"+ +a,{target:b,e:c});b.fire(a,{e:c})},_beforeScaleTransform:function(a,b){if("scale"===b.action||"scaleX"===b.action||"scaleY"===b.action){var c=this._shouldCenterTransform(b.target);if(c&&("center"!==b.originX||"center"!==b.originY)||!c&&"center"===b.originX&&"center"===b.originY)this._resetCurrentTransform(),b.reset=!0}},_onScale:function(a,b,c,d){if(!a[this.uniScaleKey]&&!this.uniScaleTransform||b.target.get("lockUniScaling"))return b.reset||"scale"!==b.currentAction||this._resetCurrentTransform(), +b.currentAction="scaleEqually",this._scaleObject(c,d,"equally");b.currentAction="scale";return this._scaleObject(c,d)},_setCursorFromEvent:function(a,b){if(!b)return this.setCursor(this.defaultCursor),!1;var c=b.hoverCursor||this.hoverCursor,d=this.getActiveGroup();(d=b._findTargetCorner&&(!d||!d.contains(b))&&b._findTargetCorner(this.getPointer(a,!0)))?this._setCornerCursor(d,b,a):this.setCursor(c);return!0},_setCornerCursor:function(a,c,d){if(a in b)this.setCursor(this._getRotatedCornerCursor(a, +c,d));else if("mtr"===a&&c.hasRotatingPoint)this.setCursor(this.rotationCursor);else return this.setCursor(this.defaultCursor),!1},_getRotatedCornerCursor:function(a,c,d){c=Math.round(c.getAngle()%360/45);0>c&&(c+=8);c+=b[a];d[this.altActionKey]&&0===b[a]%2&&(c+=2);return this.cursorMap[c%8]}})})(); +(function(){var e=Math.min,b=Math.max;fabric.util.object.extend(fabric.Canvas.prototype,{_shouldGroup:function(b,c){var a=this.getActiveObject();return b[this.selectionKey]&&c&&c.selectable&&(this.getActiveGroup()||a&&a!==c)&&this.selection},_handleGrouping:function(b,c){var a=this.getActiveGroup();if(c===a&&(c=this.findTarget(b,!0),!c))return;a?this._updateActiveGroup(c,b):this._createActiveGroup(c,b);this._activeGroup&&this._activeGroup.saveCoords()},_updateActiveGroup:function(b,c){var a=this.getActiveGroup(); +if(a.contains(b)){if(a.removeWithUpdate(b),b.set("active",!1),1===a.size()){this.discardActiveGroup(c);this.setActiveObject(a.item(0),c);return}}else a.addWithUpdate(b);this.fire("selection:created",{target:a,e:c});a.set("active",!0)},_createActiveGroup:function(b,c){if(this._activeObject&&b!==this._activeObject){var a=this._createGroup(b);a.addWithUpdate();this.setActiveGroup(a,c);this._activeObject=null;this.fire("selection:created",{target:a,e:c})}b.set("active",!0)},_createGroup:function(b){var c= +this.getObjects();b=c.indexOf(this._activeObject)<c.indexOf(b)?[this._activeObject,b]:[b,this._activeObject];this._activeObject.isEditing&&this._activeObject.exitEditing();return new fabric.Group(b,{canvas:this})},_groupSelectedObjects:function(b){var c=this._collectObjects();1===c.length?this.setActiveObject(c[0],b):1<c.length&&(c=new fabric.Group(c.reverse(),{canvas:this}),c.addWithUpdate(),this.setActiveGroup(c,b),c.saveCoords(),this.fire("selection:created",{target:c,e:b}),this.renderAll())}, +_collectObjects:function(){var d=[],c;c=this._groupSelector.ex;for(var a=this._groupSelector.ey,g=c+this._groupSelector.left,h=a+this._groupSelector.top,f=new fabric.Point(e(c,g),e(a,h)),l=new fabric.Point(b(c,g),b(a,h)),a=c===g&&a===h,g=this._objects.length;g--&&!((c=this._objects[g])&&c.selectable&&c.visible&&(c.intersectsWithRect(f,l)||c.isContainedWithinRect(f,l)||c.containsPoint(f)||c.containsPoint(l))&&(c.set("active",!0),d.push(c),a)););return d},_maybeGroupObjects:function(b){this.selection&& +this._groupSelector&&this._groupSelectedObjects(b);if(b=this.getActiveGroup())b.setObjectsCoords().setCoords(),b.isMoving=!1,this.setCursor(this.defaultCursor);this._currentTransform=this._groupSelector=null}})})(); +(function(){var e=fabric.StaticCanvas.supports("toDataURLWithQuality");fabric.util.object.extend(fabric.StaticCanvas.prototype,{toDataURL:function(b){b||(b={});return this.__toDataURLWithMultiplier(b.format||"png",b.quality||1,{left:b.left||0,top:b.top||0,width:b.width||0,height:b.height||0},b.multiplier||1)},__toDataURLWithMultiplier:function(b,d,c,a){var g=this.getWidth(),e=this.getHeight(),f=(c.width||this.getWidth())*a,l=(c.height||this.getHeight())*a,k=this.getZoom()*a,m=this.viewportTransform, +n=this.interactive;this.viewportTransform=[k,0,0,k,(m[4]-c.left)*a,(m[5]-c.top)*a];this.interactive&&(this.interactive=!1);g!==f||e!==l?this.setDimensions({width:f,height:l},{backstoreOnly:!0}):this.renderAll();b=this.__toDataURL(b,d,c);n&&(this.interactive=n);this.viewportTransform=m;this.setDimensions({width:g,height:e},{backstoreOnly:!0});return b},__toDataURL:function(b,d){var c=this.contextContainer.canvas;"jpg"===b&&(b="jpeg");return e?c.toDataURL("image/"+b,d):c.toDataURL("image/"+b)},toDataURLWithMultiplier:function(b, +d,c){return this.toDataURL({format:b,multiplier:d,quality:c})}})})(); +fabric.util.object.extend(fabric.StaticCanvas.prototype,{loadFromDatalessJSON:function(e,b,d){return this.loadFromJSON(e,b,d)},loadFromJSON:function(e,b,d){if(e){var c="string"===typeof e?JSON.parse(e):fabric.util.object.clone(e),a=this,g=this.renderOnAddRemove;this.renderOnAddRemove=!1;this._enlivenObjects(c.objects,function(d){a.clear();a._setBgOverlay(c,function(){d.forEach(function(b,c){a.insertAt(b,c)});a.renderOnAddRemove=g;delete c.objects;delete c.backgroundImage;delete c.overlayImage;delete c.background; +delete c.overlay;a._setOptions(c);a.renderAll();b&&b()})},d);return this}},_setBgOverlay:function(e,b){var d={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(e.backgroundImage||e.overlayImage||e.background||e.overlay){var c=function(){d.backgroundImage&&d.overlayImage&&d.backgroundColor&&d.overlayColor&&b&&b()};this.__setBgOverlay("backgroundImage",e.backgroundImage,d,c);this.__setBgOverlay("overlayImage",e.overlayImage,d,c);this.__setBgOverlay("backgroundColor",e.background, +d,c);this.__setBgOverlay("overlayColor",e.overlay,d,c)}else b&&b()},__setBgOverlay:function(e,b,d,c){var a=this;if(b)if("backgroundImage"===e||"overlayImage"===e)fabric.util.enlivenObjects([b],function(b){a[e]=b[0];d[e]=!0;c&&c()});else this["set"+fabric.util.string.capitalize(e,!0)](b,function(){d[e]=!0;c&&c()});else d[e]=!0,c&&c()},_enlivenObjects:function(e,b,d){e&&0!==e.length?fabric.util.enlivenObjects(e,function(c){b&&b(c)},null,d):b&&b([])},_toDataURL:function(e,b){this.clone(function(d){b(d.toDataURL(e))})}, +_toDataURLWithMultiplier:function(e,b,d){this.clone(function(c){d(c.toDataURLWithMultiplier(e,b))})},clone:function(e,b){var d=JSON.stringify(this.toJSON(b));this.cloneWithoutData(function(b){b.loadFromJSON(d,function(){e&&e(b)})})},cloneWithoutData:function(e){var b=fabric.document.createElement("canvas");b.width=this.getWidth();b.height=this.getHeight();var d=new fabric.Canvas(b);d.clipTo=this.clipTo;this.backgroundImage?(d.setBackgroundImage(this.backgroundImage.src,function(){d.renderAll();e&& +e(d)}),d.backgroundImageOpacity=this.backgroundImageOpacity,d.backgroundImageStretch=this.backgroundImageStretch):e&&e(d)}}); +(function(e){var b=e.fabric||(e.fabric={});e=b.util.object.extend;var d=b.util.object.clone,c=b.util.toFixed,a=b.util.string.capitalize,g=b.util.degreesToRadians,h=b.StaticCanvas.supports("setLineDash");b.Object||(b.Object=b.util.createClass(b.CommonMethods,{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,objectCaching:!b.isLikelyNode,statefullCache:!1,noScaleCache:!0,dirty:!0,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor skewX skewY fillRule".split(" "), +cacheProperties:"fill stroke strokeWidth strokeDashArray width height strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor".split(" "),initialize:function(a){a=a||{};this.setOptions(a)},_createCacheCanvas:function(){this._cacheProperties={};this._cacheCanvas=b.document.createElement("canvas");this._cacheContext=this._cacheCanvas.getContext("2d");this._updateCacheCanvas()},_limitCacheSize:function(a){var c=b.perfLimitSizeTotal,d=a.width,f=a.height,g=b.maxCacheSideLimit,e=b.minCacheSideLimit; +if(d<=g&&f<=g&&d*f<=c)return d<e&&(a.width=e),f<e&&(a.height=e),a;var h=b.util.limitDimsByArea(d/f,c),t=b.util.capValue,c=t(e,h.x,g),g=t(e,h.y,g);d>c&&(a.zoomX/=d/c,a.width=c,a.capped=!0);f>g&&(a.zoomY/=f/g,a.height=g,a.capped=!0);return a},_getCacheCanvasDimensions:function(){var a=this.canvas&&this.canvas.getZoom()||1,c=this.getObjectScaling(),d=this.canvas&&this.canvas._isRetinaScaling()?b.devicePixelRatio:1,g=this._getNonTransformedDimensions(),e=c.scaleX*a*d,a=c.scaleY*a*d;return{width:g.x*e+ +2,height:g.y*a+2,zoomX:e,zoomY:a,x:g.x,y:g.y}},_updateCacheCanvas:function(){if(this.noScaleCache&&this.canvas&&this.canvas._currentTransform){var a=this.canvas._currentTransform.action;if(this===this.canvas._currentTransform.target&&a.slice&&"scale"===a.slice(0,5))return!1}var a=this._cacheCanvas,c=this._limitCacheSize(this._getCacheCanvasDimensions()),d=b.minCacheSideLimit,g=c.width,e=c.height,h=c.zoomX,q=c.zoomY,t=g!==this.cacheWidth||e!==this.cacheHeight,r=this.zoomX!==h||this.zoomY!==q,v=0,A= +0,w=!1;if(t){var w=this._cacheCanvas.width,y=this._cacheCanvas.height,x=g>w||e>y,w=x||(g<.9*w||e<.9*y)&&w>d&&y>d;x&&!c.capped&&(g>d||e>d)&&(v=.1*g,A=.1*e)}return t||r?(w?(a.width=Math.ceil(g+v),a.height=Math.ceil(e+A)):(this._cacheContext.setTransform(1,0,0,1,0,0),this._cacheContext.clearRect(0,0,a.width,a.height)),d=c.x*h/2,c=c.y*q/2,this.cacheTranslationX=Math.round(a.width/2-d)+d,this.cacheTranslationY=Math.round(a.height/2-c)+c,this.cacheWidth=g,this.cacheHeight=e,this._cacheContext.translate(this.cacheTranslationX, +this.cacheTranslationY),this._cacheContext.scale(h,q),this.zoomX=h,this.zoomY=q,!0):!1},setOptions:function(a){this._setOptions(a);this._initGradient(a.fill,"fill");this._initGradient(a.stroke,"stroke");this._initClipping(a);this._initPattern(a.fill,"fill");this._initPattern(a.stroke,"stroke")},transform:function(a,b){this.group&&!this.group._transformDone&&this.group===this.canvas._activeGroup&&this.group.transform(a);var c=b?this._getLeftTopCoords():this.getCenterPoint();a.translate(c.x,c.y);this.angle&& +a.rotate(g(this.angle));a.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1));this.skewX&&a.transform(1,0,Math.tan(g(this.skewX)),1,0,0);this.skewY&&a.transform(1,Math.tan(g(this.skewY)),0,1,0,0)},toObject:function(a){var d=b.Object.NUM_FRACTION_DIGITS,d={type:this.type,originX:this.originX,originY:this.originY,left:c(this.left,d),top:c(this.top,d),width:c(this.width,d),height:c(this.height,d),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject? +this.stroke.toObject():this.stroke,strokeWidth:c(this.strokeWidth,d),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:c(this.strokeMiterLimit,d),scaleX:c(this.scaleX,d),scaleY:c(this.scaleY,d),angle:c(this.getAngle(),d),flipX:this.flipX,flipY:this.flipY,opacity:c(this.opacity,d),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():null,skewX:c(this.skewX,d),skewY:c(this.skewY,d)};b.util.populateWithProperties(this,d,a);this.includeDefaultValues||(d=this._removeDefaultValues(d));return d},toDatalessObject:function(a){return this.toObject(a)},_removeDefaultValues:function(a){var c=b.util.getKlass(a.type).prototype; +c.stateProperties.forEach(function(b){a[b]===c[b]&&delete a[b];"[object Array]"===Object.prototype.toString.call(a[b])&&"[object Array]"===Object.prototype.toString.call(c[b])&&0===a[b].length&&0===c[b].length&&delete a[b]});return a},toString:function(){return"#<fabric."+a(this.type)+">"},getObjectScaling:function(){var a=this.scaleX,b=this.scaleY;if(this.group)var c=this.group.getObjectScaling(),a=a*c.scaleX,b=b*c.scaleY;return{scaleX:a,scaleY:b}},_set:function(a,c){var d=this[a]!==c;if("scaleX"=== +a||"scaleY"===a)c=this._constrainScale(c);"scaleX"===a&&0>c?(this.flipX=!this.flipX,c*=-1):"scaleY"===a&&0>c?(this.flipY=!this.flipY,c*=-1):"shadow"!==a||!c||c instanceof b.Shadow?"dirty"===a&&this.group&&this.group.set("dirty",c):c=new b.Shadow(c);this[a]=c;d&&-1<this.cacheProperties.indexOf(a)&&(this.group&&this.group.set("dirty",!0),this.dirty=!0);d&&this.group&&-1<this.stateProperties.indexOf(a)&&this.group.set("dirty",!0);if("width"===a||"height"===a)this.minScaleLimit=Math.min(.1,1/Math.max(this.width, +this.height));return this},setOnGroup:function(){},setSourcePath:function(a){this.sourcePath=a;return this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:b.iMatrix.concat()},isNotVisible:function(){return 0===this.opacity||0===this.width&&0===this.height||!this.visible},render:function(a,c){this.isNotVisible()||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(a.save(),this._setupCompositeOperation(a),this.drawSelectionBackground(a), +c||this.transform(a),this._setOpacity(a),this._setShadow(a),this.transformMatrix&&a.transform.apply(a,this.transformMatrix),this.clipTo&&b.util.clipContext(this,a),this.shouldCache(c)?(this._cacheCanvas||this._createCacheCanvas(),this.isCacheDirty(c)&&(this.statefullCache&&this.saveState({propertySet:"cacheProperties"}),this.drawObject(this._cacheContext,c),this.dirty=!1),this.drawCacheOnCanvas(a)):(this._removeCacheCanvas(),this.dirty=!1,this.drawObject(a,c),c&&this.objectCaching&&this.statefullCache&& +this.saveState({propertySet:"cacheProperties"})),this.clipTo&&a.restore(),a.restore())},_removeCacheCanvas:function(){this._cacheCanvas=null;this.cacheHeight=this.cacheWidth=0},needsItsOwnCache:function(){return!1},shouldCache:function(a){return!a&&this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching())},willDrawShadow:function(){return!!this.shadow&&(0!==this.shadow.offsetX||0!==this.shadow.offsetY)},drawObject:function(a,b){this._renderBackground(a);this._setStrokeStyles(a); +this._setFillStyles(a);this._render(a,b)},drawCacheOnCanvas:function(a){a.scale(1/this.zoomX,1/this.zoomY);a.drawImage(this._cacheCanvas,-this.cacheTranslationX,-this.cacheTranslationY)},isCacheDirty:function(a){if(this.isNotVisible())return!1;if(this._cacheCanvas&&!a&&this._updateCacheCanvas())return!0;if(this.dirty||this.statefullCache&&this.hasStateChanged("cacheProperties")){if(this._cacheCanvas&&!a){a=this.cacheWidth/this.zoomX;var b=this.cacheHeight/this.zoomY;this._cacheContext.clearRect(-a/ +2,-b/2,a,b)}return!0}return!1},_renderBackground:function(a){if(this.backgroundColor){var b=this._getNonTransformedDimensions();a.fillStyle=this.backgroundColor;a.fillRect(-b.x/2,-b.y/2,b.x,b.y);this._removeShadow(a)}},_setOpacity:function(a){a.globalAlpha*=this.opacity},_setStrokeStyles:function(a){this.stroke&&(a.lineWidth=this.strokeWidth,a.lineCap=this.strokeLineCap,a.lineJoin=this.strokeLineJoin,a.miterLimit=this.strokeMiterLimit,a.strokeStyle=this.stroke.toLive?this.stroke.toLive(a,this):this.stroke)}, +_setFillStyles:function(a){this.fill&&(a.fillStyle=this.fill.toLive?this.fill.toLive(a,this):this.fill)},_setLineDash:function(a,b,c){b&&(1&b.length&&b.push.apply(b,b),h?a.setLineDash(b):c&&c(a))},_renderControls:function(a){if(this.active&&(!this.group||this.group===this.canvas.getActiveGroup())){var c=this.getViewportTransform(),d=this.calcTransformMatrix(),d=b.util.multiplyTransformMatrices(c,d),c=b.util.qrDecompose(d);a.save();a.translate(c.translateX,c.translateY);a.lineWidth=1*this.borderScaleFactor; +this.group||(a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1);this.group&&this.group===this.canvas.getActiveGroup()?(a.rotate(g(c.angle)),this.drawBordersInGroup(a,c)):(a.rotate(g(this.angle)),this.drawBorders(a));this.drawControls(a);a.restore()}},_setShadow:function(a){if(this.shadow){var c=this.canvas&&this.canvas.viewportTransform[0]||1,d=this.canvas&&this.canvas.viewportTransform[3]||1,f=this.getObjectScaling();this.canvas&&this.canvas._isRetinaScaling()&&(c*=b.devicePixelRatio,d*= +b.devicePixelRatio);a.shadowColor=this.shadow.color;a.shadowBlur=this.shadow.blur*(c+d)*(f.scaleX+f.scaleY)/4;a.shadowOffsetX=this.shadow.offsetX*c*f.scaleX;a.shadowOffsetY=this.shadow.offsetY*d*f.scaleY}},_removeShadow:function(a){this.shadow&&(a.shadowColor="",a.shadowBlur=a.shadowOffsetX=a.shadowOffsetY=0)},_applyPatternGradientTransform:function(a,b){if(b.toLive){var c=b.gradientTransform||b.patternTransform;c&&a.transform.apply(a,c);a.translate(-this.width/2+b.offsetX||0,-this.height/2+b.offsetY|| +0)}},_renderFill:function(a){this.fill&&(a.save(),this._applyPatternGradientTransform(a,this.fill),"evenodd"===this.fillRule?a.fill("evenodd"):a.fill(),a.restore())},_renderStroke:function(a){this.stroke&&0!==this.strokeWidth&&(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(a),a.save(),this._setLineDash(a,this.strokeDashArray,this._renderDashedStroke),this._applyPatternGradientTransform(a,this.stroke),a.stroke(),a.restore())},clone:function(a,c){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(c), +a):new b.Object(this.toObject(c))},cloneAsImage:function(a,c){var d=this.toDataURL(c);b.util.loadImage(d,function(c){a&&a(new b.Image(c))});return this},toDataURL:function(a){a||(a={});var c=b.util.createCanvasElement(),d=this.getBoundingRect();c.width=d.width;c.height=d.height;b.util.wrapElement(c,"div");c=new b.StaticCanvas(c,{enableRetinaScaling:a.enableRetinaScaling});"jpg"===a.format&&(a.format="jpeg");"jpeg"===a.format&&(c.backgroundColor="#fff");d={active:this.get("active"),left:this.getLeft(), +top:this.getTop()};this.set("active",!1);this.setPositionByOrigin(new b.Point(c.getWidth()/2,c.getHeight()/2),"center","center");var f=this.canvas;c.add(this);a=c.toDataURL(a);this.set(d).setCoords();this.canvas=f;c.dispose();return a},isType:function(a){return this.type===a},complexity:function(){return 1},toJSON:function(a){return this.toObject(a)},setGradient:function(a,c){c||(c={});var d={colorStops:[]};d.type=c.type||(c.r1||c.r2?"radial":"linear");d.coords={x1:c.x1,y1:c.y1,x2:c.x2,y2:c.y2};if(c.r1|| +c.r2)d.coords.r1=c.r1,d.coords.r2=c.r2;d.gradientTransform=c.gradientTransform;b.Gradient.prototype.addColorStop.call(d,c.colorStops);return this.set(a,b.Gradient.forObject(this,d))},setPatternFill:function(a){return this.set("fill",new b.Pattern(a))},setShadow:function(a){return this.set("shadow",a?new b.Shadow(a):null)},setColor:function(a){this.set("fill",a);return this},setAngle:function(a){var b=("center"!==this.originX||"center"!==this.originY)&&this.centeredRotation;b&&this._setOriginToCenter(); +this.set("angle",a);b&&this._resetOrigin();return this},centerH:function(){this.canvas&&this.canvas.centerObjectH(this);return this},viewportCenterH:function(){this.canvas&&this.canvas.viewportCenterObjectH(this);return this},centerV:function(){this.canvas&&this.canvas.centerObjectV(this);return this},viewportCenterV:function(){this.canvas&&this.canvas.viewportCenterObjectV(this);return this},center:function(){this.canvas&&this.canvas.centerObject(this);return this},viewportCenter:function(){this.canvas&& +this.canvas.viewportCenterObject(this);return this},remove:function(){this.canvas&&(this.group&&this.group===this.canvas._activeGroup&&this.group.remove(this),this.canvas.remove(this));return this},getLocalPointer:function(a,c){c=c||this.canvas.getPointer(a);var d=new b.Point(c.x,c.y),f=this._getLeftTopCoords();this.angle&&(d=b.util.rotatePoint(d,f,g(-this.angle)));return{x:d.x-f.x,y:d.y-f.y}},_setupCompositeOperation:function(a){this.globalCompositeOperation&&(a.globalCompositeOperation=this.globalCompositeOperation)}}), +b.util.createAccessors(b.Object),b.Object.prototype.rotate=b.Object.prototype.setAngle,e(b.Object.prototype,b.Observable),b.Object.NUM_FRACTION_DIGITS=2,b.Object._fromObject=function(a,c,g,e,h){var f=b[a];c=d(c,!0);if(e)b.util.enlivenPatterns([c.fill,c.stroke],function(a){"undefined"!==typeof a[0]&&(c.fill=a[0]);"undefined"!==typeof a[1]&&(c.stroke=a[1]);a=h?new f(c[h],c):new f(c);g&&g(a)});else return a=h?new f(c[h],c):new f(c),g&&g(a),a},b.Object.__uid=0)})("undefined"!==typeof exports?exports: +this); +(function(){var e=fabric.util.degreesToRadians,b={left:-.5,center:0,right:.5},d={top:-.5,center:0,bottom:.5};fabric.util.object.extend(fabric.Object.prototype,{translateToGivenOrigin:function(c,a,g,e,f){var h=c.x,k=c.y;a="string"===typeof a?b[a]:a-.5;e="string"===typeof e?b[e]:e-.5;a=e-a;g="string"===typeof g?d[g]:g-.5;f="string"===typeof f?d[f]:f-.5;g=f-g;if(a||g)k=this._getTransformedDimensions(),h=c.x+a*k.x,k=c.y+g*k.y;return new fabric.Point(h,k)},translateToCenterPoint:function(b,a,d){a=this.translateToGivenOrigin(b, +a,d,"center","center");return this.angle?fabric.util.rotatePoint(a,b,e(this.angle)):a},translateToOriginPoint:function(b,a,d){a=this.translateToGivenOrigin(b,"center","center",a,d);return this.angle?fabric.util.rotatePoint(a,b,e(this.angle)):a},getCenterPoint:function(){var b=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(b,this.originX,this.originY)},getPointByOrigin:function(b,a){var c=this.getCenterPoint();return this.translateToOriginPoint(c,b,a)},toLocalPoint:function(b, +a,d){var c=this.getCenterPoint();a="undefined"!==typeof a&&"undefined"!==typeof d?this.translateToGivenOrigin(c,"center","center",a,d):new fabric.Point(this.left,this.top);b=new fabric.Point(b.x,b.y);this.angle&&(b=fabric.util.rotatePoint(b,c,-e(this.angle)));return b.subtractEquals(a)},setPositionByOrigin:function(b,a,d){b=this.translateToCenterPoint(b,a,d);b=this.translateToOriginPoint(b,this.originX,this.originY);this.set("left",b.x);this.set("top",b.y)},adjustPosition:function(c){var a=e(this.angle), +d=this.getWidth(),h=Math.cos(a)*d,a=Math.sin(a)*d,f,d="string"===typeof this.originX?b[this.originX]:this.originX-.5;f="string"===typeof c?b[c]:c-.5;this.left+=h*(f-d);this.top+=a*(f-d);this.setCoords();this.originX=c},_setOriginToCenter:function(){this._originalOriginX=this.originX;this._originalOriginY=this.originY;var b=this.getCenterPoint();this.originY=this.originX="center";this.left=b.x;this.top=b.y},_resetOrigin:function(){var b=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX, +this._originalOriginY);this.originX=this._originalOriginX;this.originY=this._originalOriginY;this.left=b.x;this.top=b.y;this._originalOriginY=this._originalOriginX=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),"left","top")},onDeselect:function(){}})})(); +(function(){var e=fabric.util.degreesToRadians,b=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,aCoords:null,getCoords:function(b,c){this.oCoords||this.setCoords();var a=b?this.aCoords:this.oCoords,a=c?this.calcCoords(b):a;return[new fabric.Point(a.tl.x,a.tl.y),new fabric.Point(a.tr.x,a.tr.y),new fabric.Point(a.br.x,a.br.y),new fabric.Point(a.bl.x,a.bl.y)]},intersectsWithRect:function(b,c,a,e){a=this.getCoords(a,e);return"Intersection"===fabric.Intersection.intersectPolygonRectangle(a, +b,c).status},intersectsWithObject:function(b,c,a){return"Intersection"===fabric.Intersection.intersectPolygonPolygon(this.getCoords(c,a),b.getCoords(c,a)).status||b.isContainedWithinObject(this,c,a)||this.isContainedWithinObject(b,c,a)},isContainedWithinObject:function(b,c,a){var d=this.getCoords(c,a),e=0;for(c=b._getImageLines(a?b.calcCoords(c):c?b.aCoords:b.oCoords);4>e;e++)if(!b.containsPoint(d[e],c))return!1;return!0},isContainedWithinRect:function(b,c,a,e){a=this.getBoundingRect(a,e);return a.left>= +b.x&&a.left+a.width<=c.x&&a.top>=b.y&&a.top+a.height<=c.y},containsPoint:function(b,c,a,e){c=c||this._getImageLines(e?this.calcCoords(a):a?this.aCoords:this.oCoords);b=this._findCrossPoints(b,c);return 0!==b&&1===b%2},isOnScreen:function(b){if(!this.canvas)return!1;var c=this.canvas.vptCoords.tl,a=this.canvas.vptCoords.br;b=this.getCoords(!0,b);for(var d,e=0;4>e;e++)if(d=b[e],d.x<=a.x&&d.x>=c.x&&d.y<=a.y&&d.y>=c.y)return!0;return this.intersectsWithRect(c,a,!0)||this.containsPoint({x:(c.x+a.x)/2, +y:(c.y+a.y)/2},null,!0)?!0:!1},_getImageLines:function(b){return{topline:{o:b.tl,d:b.tr},rightline:{o:b.tr,d:b.br},bottomline:{o:b.br,d:b.bl},leftline:{o:b.bl,d:b.tl}}},_findCrossPoints:function(b,c){var a,d,e,f=0,l;for(l in c)if(e=c[l],!(e.o.y<b.y&&e.d.y<b.y||e.o.y>=b.y&&e.d.y>=b.y)&&(e.o.x===e.d.x&&e.o.x>=b.x?a=e.o.x:(a=(e.d.y-e.o.y)/(e.d.x-e.o.x),d=b.y-0*b.x,e=e.o.y-a*e.o.x,a=-(d-e)/(0-a)),a>=b.x&&(f+=1),2===f))break;return f},getBoundingRectWidth:function(){return this.getBoundingRect().width}, +getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(b,c){var a=this.getCoords(b,c);return fabric.util.makeBoundingBoxFromPoints(a)},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(b){return Math.abs(b)<this.minScaleLimit?0>b?-this.minScaleLimit:this.minScaleLimit:b!==b?this.minScaleLimit:0===b?1E-4:b},scale:function(b){b=this._constrainScale(b);0>b&&(this.flipX= +!this.flipX,this.flipY=!this.flipY,b*=-1);this.scaleY=this.scaleX=b;return this.setCoords()},scaleToWidth:function(b){var c=this.getBoundingRect().width/this.getWidth();return this.scale(b/this.width/c)},scaleToHeight:function(b){var c=this.getBoundingRect().height/this.getHeight();return this.scale(b/this.height/c)},calcCoords:function(b){var c=e(this.angle),a=this.getViewportTransform(),d=b?this._getTransformedDimensions():this._calculateCurrentDimensions(),h=d.x,f=d.y,d=Math.sin(c),l=Math.cos(c), +k=0<h?Math.atan(f/h):0,m=h/Math.cos(k)/2,n=Math.cos(k+c)*m,c=Math.sin(k+c)*m,k=this.getCenterPoint(),k=b?k:fabric.util.transformPoint(k,a),a=new fabric.Point(k.x-n,k.y-c),h=new fabric.Point(a.x+h*l,a.y+h*d),f=new fabric.Point(a.x-f*d,a.y+f*l),n=new fabric.Point(k.x+n,k.y+c);if(!b)var p=new fabric.Point((a.x+f.x)/2,(a.y+f.y)/2),q=new fabric.Point((h.x+a.x)/2,(h.y+a.y)/2),t=new fabric.Point((n.x+h.x)/2,(n.y+h.y)/2),r=new fabric.Point((n.x+f.x)/2,(n.y+f.y)/2),v=new fabric.Point(q.x+d*this.rotatingPointOffset, +q.y-l*this.rotatingPointOffset);k={tl:a,tr:h,br:n,bl:f};b||(k.ml=p,k.mt=q,k.mr=t,k.mb=r,k.mtr=v);return k},setCoords:function(b,c){this.oCoords=this.calcCoords(b);c||(this.aCoords=this.calcCoords(!0));b||this._setCornerCoords&&this._setCornerCoords();return this},_calcRotateMatrix:function(){if(this.angle){var b=e(this.angle),c=Math.cos(b),b=Math.sin(b);if(6.123233995736766E-17===c||-1.8369701987210297E-16===c)c=0;return[c,b,-b,c,0,0]}return fabric.iMatrix.concat()},calcTransformMatrix:function(d){var c= +this.getCenterPoint(),a=[1,0,0,1,c.x,c.y],c=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0),a=this.group&&!d?b(this.group.calcTransformMatrix(),a):a;this.angle&&(d=this._calcRotateMatrix(),a=b(a,d));return a=b(a,c)},_calcDimensionsTransformMatrix:function(d,c,a){a=[this.scaleX*(a&&this.flipX?-1:1),0,0,this.scaleY*(a&&this.flipY?-1:1),0,0];d&&(d=[1,0,Math.tan(e(d)),1],a=b(a,d,!0));c&&(d=[1,Math.tan(e(c)),0,1],a=b(a,d,!0));return a},_getNonTransformedDimensions:function(){var b=this.strokeWidth; +return{x:this.width+b,y:this.height+b}},_getTransformedDimensions:function(b,c){"undefined"===typeof b&&(b=this.skewX);"undefined"===typeof c&&(c=this.skewY);for(var a=this._getNonTransformedDimensions(),d=a.x/2,a=a.y/2,d=[{x:-d,y:-a},{x:d,y:-a},{x:-d,y:a},{x:d,y:a}],e=this._calcDimensionsTransformMatrix(b,c,!1),a=0;a<d.length;a++)d[a]=fabric.util.transformPoint(d[a],e);d=fabric.util.makeBoundingBoxFromPoints(d);return{x:d.width,y:d.height}},_calculateCurrentDimensions:function(){var b=this.getViewportTransform(), +c=this._getTransformedDimensions();return fabric.util.transformPoint(c,b,!0).scalarAdd(2*this.padding)}})})(); +fabric.util.object.extend(fabric.Object.prototype,{sendToBack:function(){this.group?fabric.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this);return this},bringToFront:function(){this.group?fabric.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this);return this},sendBackwards:function(e){this.group?fabric.StaticCanvas.prototype.sendBackwards.call(this.group,this,e):this.canvas.sendBackwards(this,e);return this},bringForward:function(e){this.group? +fabric.StaticCanvas.prototype.bringForward.call(this.group,this,e):this.canvas.bringForward(this,e);return this},moveTo:function(e){this.group?fabric.StaticCanvas.prototype.moveTo.call(this.group,this,e):this.canvas.moveTo(this,e);return this}}); +(function(){function e(b,d){if(d){if(d.toLive)return b+": url(#SVGID_"+d.id+"); ";var c=new fabric.Color(d),a=b+": "+c.toRgb()+"; ",c=c.getAlpha();1!==c&&(a+=b+"-opacity: "+c.toString()+"; ");return a}return b+": none; "}fabric.util.object.extend(fabric.Object.prototype,{getSvgStyles:function(b){var d=this.fillRule,c=this.strokeWidth?this.strokeWidth:"0",a=this.strokeDashArray?this.strokeDashArray.join(" "):"none",g=this.strokeLineCap?this.strokeLineCap:"butt",h=this.strokeLineJoin?this.strokeLineJoin: +"miter",f=this.strokeMiterLimit?this.strokeMiterLimit:"4",l="undefined"!==typeof this.opacity?this.opacity:"1",k=this.visible?"":" visibility: hidden;";b=b?"":this.getSvgFilter();var m=e("fill",this.fill);return[e("stroke",this.stroke),"stroke-width: ",c,"; stroke-dasharray: ",a,"; stroke-linecap: ",g,"; stroke-linejoin: ",h,"; stroke-miterlimit: ",f,"; ",m,"fill-rule: ",d,"; opacity: ",l,";",b,k].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 b=fabric.util.toFixed,d=this.getAngle(),c=this.getSkewX()%360,a=this.getSkewY()%360,e=this.getCenterPoint(),h=fabric.Object.NUM_FRACTION_DIGITS,e="path-group"===this.type?"":"translate("+b(e.x,h)+" "+b(e.y,h)+")",d=0!==d?" rotate("+b(d,h)+")":"",f=1===this.scaleX&&1===this.scaleY?"":" scale("+b(this.scaleX,h)+" "+b(this.scaleY,h)+")",c=0!==c?" skewX("+b(c,h)+")":"",b=0!==a?" skewY("+b(a,h)+ +")":"",a="path-group"===this.type?this.width:0,h="path-group"===this.type?this.height:0;return[e,d,f,this.flipX?" matrix(-1 0 0 1 "+a+" 0) ":"",this.flipY?" matrix(1 0 0 -1 0 "+h+")":"",c,b].join("")},getSvgTransformMatrix:function(){return this.transformMatrix?" matrix("+this.transformMatrix.join(" ")+") ":""},_createBaseSVGMarkup:function(){var b=[];this.fill&&this.fill.toLive&&b.push(this.fill.toSVG(this,!1));this.stroke&&this.stroke.toLive&&b.push(this.stroke.toSVG(this,!1));this.shadow&&b.push(this.shadow.toSVG(this)); +return b}})})(); +(function(){function e(b,a,e){var c={};e.forEach(function(a){c[a]=b[a]});d(b[a],c,!0)}function b(c,a,d){if(c===a)return!0;if(Array.isArray(c)){if(c.length!==a.length)return!1;d=0;for(var e=c.length;d<e;d++)if(!b(c[d],a[d]))return!1;return!0}if(c&&"object"===typeof c){var f=Object.keys(c),g;if(!d&&f.length!==Object.keys(a).length)return!1;d=0;for(e=f.length;d<e;d++)if(g=f[d],!b(c[g],a[g]))return!1;return!0}}var d=fabric.util.object.extend;fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(c){c= +c||"stateProperties";var a="_"+c;return Object.keys(this[a]).length<this[c].length?!0:!b(this[a],this,!0)},saveState:function(b){var a=b&&b.propertySet||"stateProperties",c="_"+a;if(!this[c])return this.setupState(b);e(this,c,this[a]);b&&b.stateProperties&&e(this,c,b.stateProperties);return this},setupState:function(b){b=b||{};var a=b.propertySet||"stateProperties";b.propertySet=a;this["_"+a]={};this.saveState(b);return this}})})(); +(function(){var e=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(b){if(!this.hasControls||!this.active)return!1;var d=b.x;b=b.y;var c;this.__corner=0;for(var a in this.oCoords)if(this.isControlVisible(a)&&("mtr"!==a||this.hasRotatingPoint)&&(!this.get("lockUniScaling")||"mt"!==a&&"mr"!==a&&"mb"!==a&&"ml"!==a)&&(c=this._getImageLines(this.oCoords[a].corner),c=this._findCrossPoints({x:d,y:b},c),0!==c&&1===c%2))return this.__corner= +a;return!1},_setCornerCoords:function(){var b=this.oCoords,d=e(45-this.angle),c=.707106*this.cornerSize,a=c*Math.cos(d),d=c*Math.sin(d),g,h;for(h in b)c=b[h].x,g=b[h].y,b[h].corner={tl:{x:c-d,y:g-a},tr:{x:c+a,y:g-d},bl:{x:c-a,y:g+d},br:{x:c+d,y:g+a}}},drawSelectionBackground:function(b){if(!this.selectionBackgroundColor||this.group||!this.active||this.canvas&&!this.canvas.interactive)return this;b.save();var d=this.getCenterPoint(),c=this._calculateCurrentDimensions(),a=this.canvas.viewportTransform; +b.translate(d.x,d.y);b.scale(1/a[0],1/a[3]);b.rotate(e(this.angle));b.fillStyle=this.selectionBackgroundColor;b.fillRect(-c.x/2,-c.y/2,c.x,c.y);b.restore();return this},drawBorders:function(b){if(!this.hasBorders)return this;var d=this._calculateCurrentDimensions(),c=1/this.borderScaleFactor,a=d.x+c,d=d.y+c;b.save();b.strokeStyle=this.borderColor;this._setLineDash(b,this.borderDashArray,null);b.strokeRect(-a/2,-d/2,a,d);this.hasRotatingPoint&&this.isControlVisible("mtr")&&!this.get("lockRotation")&& +this.hasControls&&(a=-d/2,b.beginPath(),b.moveTo(0,a),b.lineTo(0,a-this.rotatingPointOffset),b.closePath(),b.stroke());b.restore();return this},drawBordersInGroup:function(b,d){if(!this.hasBorders)return this;var c=this._getNonTransformedDimensions(),a=fabric.util.customTransformMatrix(d.scaleX,d.scaleY,d.skewX),a=fabric.util.transformPoint(c,a),e=1/this.borderScaleFactor,c=a.x+e,a=a.y+e;b.save();this._setLineDash(b,this.borderDashArray,null);b.strokeStyle=this.borderColor;b.strokeRect(-c/2,-a/2, +c,a);b.restore();return this},drawControls:function(b){if(!this.hasControls)return this;var d=this._calculateCurrentDimensions(),c=d.x,d=d.y,a=this.cornerSize,e=-(c+a)/2,a=-(d+a)/2,h=this.transparentCorners?"stroke":"fill";b.save();b.strokeStyle=b.fillStyle=this.cornerColor;this.transparentCorners||(b.strokeStyle=this.cornerStrokeColor);this._setLineDash(b,this.cornerDashArray,null);this._drawControl("tl",b,h,e,a);this._drawControl("tr",b,h,e+c,a);this._drawControl("bl",b,h,e,a+d);this._drawControl("br", +b,h,e+c,a+d);this.get("lockUniScaling")||(this._drawControl("mt",b,h,e+c/2,a),this._drawControl("mb",b,h,e+c/2,a+d),this._drawControl("mr",b,h,e+c,a+d/2),this._drawControl("ml",b,h,e,a+d/2));this.hasRotatingPoint&&this._drawControl("mtr",b,h,e+c/2,a-this.rotatingPointOffset);b.restore();return this},_drawControl:function(b,d,c,a,e){if(this.isControlVisible(b)){b=this.cornerSize;var g=!this.transparentCorners&&this.cornerStrokeColor;switch(this.cornerStyle){case "circle":d.beginPath();d.arc(a+b/2, +e+b/2,b/2,0,2*Math.PI,!1);d[c]();g&&d.stroke();break;default:"undefined"!==typeof G_vmlCanvasManager||this.transparentCorners||d.clearRect(a,e,b,b),d[c+"Rect"](a,e,b,b),g&&d.strokeRect(a,e,b,b)}}},isControlVisible:function(b){return this._getControlsVisibility()[b]},setControlVisible:function(b,d){this._getControlsVisibility()[b]=d;return this},setControlsVisibility:function(b){b||(b={});for(var d in b)this.setControlVisible(d,b[d]);return this},_getControlsVisibility:function(){this._controlsVisibility|| +(this._controlsVisibility={tl:!0,tr:!0,br:!0,bl:!0,ml:!0,mt:!0,mr:!0,mb:!0,mtr:!0});return this._controlsVisibility}})})(); +fabric.util.object.extend(fabric.StaticCanvas.prototype,{FX_DURATION:500,fxCenterObjectH:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("left"),endValue:this.getCenter().left,duration:this.FX_DURATION,onChange:function(b){e.set("left",b);g.renderAll();a()},onComplete:function(){e.setCoords();c()}});return this},fxCenterObjectV:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("top"), +endValue:this.getCenter().top,duration:this.FX_DURATION,onChange:function(b){e.set("top",b);g.renderAll();a()},onComplete:function(){e.setCoords();c()}});return this},fxRemove:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("opacity"),endValue:0,duration:this.FX_DURATION,onStart:function(){e.set("active",!1)},onChange:function(b){e.set("opacity",b);g.renderAll();a()},onComplete:function(){g.remove(e);c()}});return this}}); +fabric.util.object.extend(fabric.Object.prototype,{animate:function(){if(arguments[0]&&"object"===typeof arguments[0]){var e=[],b,d;for(b in arguments[0])e.push(b);for(var c=0,a=e.length;c<a;c++)b=e[c],d=c!==a-1,this._animate(b,arguments[0][b],arguments[1],d)}else this._animate.apply(this,arguments);return this},_animate:function(e,b,d,c){var a=this,g;b=b.toString();d=d?fabric.util.object.clone(d):{};~e.indexOf(".")&&(g=e.split("."));var h=g?this.get(g[0])[g[1]]:this.get(e);"from"in d||(d.from=h); +b=~b.indexOf("=")?h+parseFloat(b.replace("=","")):parseFloat(b);fabric.util.animate({startValue:d.from,endValue:b,byValue:d.by,easing:d.easing,duration:d.duration,abort:d.abort&&function(){return d.abort.call(a)},onChange:function(b,h,k){g?a[g[0]][g[1]]=b:a.set(e,b);c||d.onChange&&d.onChange(b,h,k)},onComplete:function(b,e,g){c||(a.setCoords(),d.onComplete&&d.onComplete(b,e,g))}})}}); +(function(e){function b(a,b){var c=a.origin,d=a.axis1,f=a.axis2,e=a.dimension,g=b.nearest,h=b.center,l=b.farthest;return function(){switch(this.get(c)){case g:return Math.min(this.get(d),this.get(f));case h:return Math.min(this.get(d),this.get(f))+.5*this.get(e);case l:return Math.max(this.get(d),this.get(f))}}}var d=e.fabric||(e.fabric={}),c=d.util.object.extend,a=d.util.object.clone,g={x1:1,x2:1,y1:1,y2:1},h=d.StaticCanvas.supports("setLineDash");d.Line?d.warn("fabric.Line is already defined"): +(d.Line=d.util.createClass(d.Object,{type:"line",x1:0,y1:0,x2:0,y2:0,cacheProperties:d.Object.prototype.cacheProperties.concat("x1","x2","y1","y2"),initialize:function(a,b){a||(a=[0,0,0,0]);this.callSuper("initialize",b);this.set("x1",a[0]);this.set("y1",a[1]);this.set("x2",a[2]);this.set("y2",a[3]);this._setWidthHeight(b)},_setWidthHeight:function(a){a||(a={});this.width=Math.abs(this.x2-this.x1);this.height=Math.abs(this.y2-this.y1);this.left="left"in a?a.left:this._getLeftToOriginX();this.top= +"top"in a?a.top:this._getTopToOriginY()},_set:function(a,b){this.callSuper("_set",a,b);"undefined"!==typeof g[a]&&this._setWidthHeight();return this},_getLeftToOriginX:b({origin:"originX",axis1:"x1",axis2:"x2",dimension:"width"},{nearest:"left",center:"center",farthest:"right"}),_getTopToOriginY:b({origin:"originY",axis1:"y1",axis2:"y2",dimension:"height"},{nearest:"top",center:"center",farthest:"bottom"}),_render:function(a,b){a.beginPath();if(b){var c=this.getCenterPoint(),d=this.strokeWidth/2; +a.translate(c.x-("butt"===this.strokeLineCap&&0===this.height?0:d),c.y-("butt"===this.strokeLineCap&&0===this.width?0:d))}if(!this.strokeDashArray||this.strokeDashArray&&h)c=this.calcLinePoints(),a.moveTo(c.x1,c.y1),a.lineTo(c.x2,c.y2);a.lineWidth=this.strokeWidth;c=a.strokeStyle;a.strokeStyle=this.stroke||a.fillStyle;this.stroke&&this._renderStroke(a);a.strokeStyle=c},_renderDashedStroke:function(a){var b=this.calcLinePoints();a.beginPath();d.util.drawDashedLine(a,b.x1,b.y1,b.x2,b.y2,this.strokeDashArray); +a.closePath()},toObject:function(a){return c(this.callSuper("toObject",a),this.calcLinePoints())},_getNonTransformedDimensions:function(){var a=this.callSuper("_getNonTransformedDimensions");"butt"===this.strokeLineCap&&(0===this.width&&(a.y-=this.strokeWidth),0===this.height&&(a.x-=this.strokeWidth));return a},calcLinePoints:function(){var a=this.x1<=this.x2?-1:1,b=this.y1<=this.y2?-1:1;return{x1:a*this.width*.5,x2:a*this.width*-.5,y1:b*this.height*.5,y2:b*this.height*-.5}},toSVG:function(a){var b= +this._createBaseSVGMarkup(),c={x1:this.x1,x2:this.x2,y1:this.y1,y2:this.y2};this.group&&"path-group"===this.group.type||(c=this.calcLinePoints());b.push("<line ",this.getSvgId(),'x1="',c.x1,'" y1="',c.y1,'" x2="',c.x2,'" y2="',c.y2,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")}}),d.Line.ATTRIBUTE_NAMES=d.SHARED_ATTRIBUTES.concat(["x1","y1","x2","y2"]),d.Line.fromElement=function(a,b){b=b||{};var f=d.parseAttributes(a, +d.Line.ATTRIBUTE_NAMES),e=[f.x1||0,f.y1||0,f.x2||0,f.y2||0];b.originX="left";b.originY="top";return new d.Line(e,c(f,b))},d.Line.fromObject=function(b,c,e){var f=a(b,!0);f.points=[b.x1,b.y1,b.x2,b.y2];(b=d.Object._fromObject("Line",f,function(a){delete a.points;c&&c(a)},e,"points"))&&delete b.points;return b})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=Math.PI,c=b.util.object.extend;b.Circle?b.warn("fabric.Circle is already defined."):(b.Circle=b.util.createClass(b.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*d,cacheProperties:b.Object.prototype.cacheProperties.concat("radius"),initialize:function(a){this.callSuper("initialize",a);this.set("radius",a&&a.radius||0)},_set:function(a,b){this.callSuper("_set",a,b);"radius"===a&&this.setRadius(b);return this},toObject:function(a){return this.callSuper("toObject", +["radius","startAngle","endAngle"].concat(a))},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=0,f=0,e=(this.endAngle-this.startAngle)%(2*d);0===e?(this.group&&"path-group"===this.group.type&&(c=this.left+this.radius,f=this.top+this.radius),b.push("<circle ",this.getSvgId(),'cx="'+c+'" cy="'+f+'" ','r="',this.radius,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n')):b.push('<path d="M '+Math.cos(this.startAngle)*this.radius+" "+ +Math.sin(this.startAngle)*this.radius," A "+this.radius+" "+this.radius," 0 ",+(e>d?1:0)+" 1"," "+Math.cos(this.endAngle)*this.radius+" "+Math.sin(this.endAngle)*this.radius,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")},_render:function(a,b){a.beginPath();a.arc(b?this.left+this.radius:0,b?this.top+this.radius:0,this.radius,this.startAngle,this.endAngle,!1);this._renderFill(a);this._renderStroke(a)}, +getRadiusX:function(){return this.get("radius")*this.get("scaleX")},getRadiusY:function(){return this.get("radius")*this.get("scaleY")},setRadius:function(a){this.radius=a;return this.set("width",2*a).set("height",2*a)}}),b.Circle.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["cx","cy","r"]),b.Circle.fromElement=function(a,d){d||(d={});var e=b.parseAttributes(a,b.Circle.ATTRIBUTE_NAMES);if(!("radius"in e&&0<=e.radius))throw Error("value of `r` attribute is required and can not be negative");e.left= +e.left||0;e.top=e.top||0;e=new b.Circle(c(e,d));e.left-=e.radius;e.top-=e.radius;return e},b.Circle.fromObject=function(a,c,d){return b.Object._fromObject("Circle",a,c,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});b.Triangle?b.warn("fabric.Triangle is already defined"):(b.Triangle=b.util.createClass(b.Object,{type:"triangle",initialize:function(b){this.callSuper("initialize",b);this.set("width",b&&b.width||100).set("height",b&&b.height||100)},_render:function(b){var c=this.width/2,a=this.height/2;b.beginPath();b.moveTo(-c,a);b.lineTo(0,-a);b.lineTo(c,a);b.closePath();this._renderFill(b);this._renderStroke(b)},_renderDashedStroke:function(d){var c=this.width/2,a=this.height/ +2;d.beginPath();b.util.drawDashedLine(d,-c,a,0,-a,this.strokeDashArray);b.util.drawDashedLine(d,0,-a,c,a,this.strokeDashArray);b.util.drawDashedLine(d,c,a,-c,a,this.strokeDashArray);d.closePath()},toSVG:function(b){var c=this._createBaseSVGMarkup(),a=this.width/2,d=this.height/2,a=[-a+" "+d,"0 "+-d,a+" "+d].join();c.push("<polygon ",this.getSvgId(),'points="',a,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),'"/>');return b?b(c.join("")):c.join("")}}),b.Triangle.fromObject= +function(d,c,a){return b.Object._fromObject("Triangle",d,c,a)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=2*Math.PI,c=b.util.object.extend;b.Ellipse?b.warn("fabric.Ellipse is already defined."):(b.Ellipse=b.util.createClass(b.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:b.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(a){this.callSuper("initialize",a);this.set("rx",a&&a.rx||0);this.set("ry",a&&a.ry||0)},_set:function(a,b){this.callSuper("_set",a,b);switch(a){case "rx":this.rx=b;this.set("width",2*b);break;case "ry":this.ry=b,this.set("height", +2*b)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(a){return this.callSuper("toObject",["rx","ry"].concat(a))},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=0,d=0;this.group&&"path-group"===this.group.type&&(c=this.left+this.rx,d=this.top+this.ry);b.push("<ellipse ",this.getSvgId(),'cx="',c,'" cy="',d,'" ','rx="',this.rx,'" ry="',this.ry,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(), +this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")},_render:function(a,b){a.beginPath();a.save();a.transform(1,0,0,this.ry/this.rx,0,0);a.arc(b?this.left+this.rx:0,b?(this.top+this.ry)*this.rx/this.ry:0,this.rx,0,d,!1);a.restore();this._renderFill(a);this._renderStroke(a)}}),b.Ellipse.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["cx","cy","rx","ry"]),b.Ellipse.fromElement=function(a,d){d||(d={});var e=b.parseAttributes(a,b.Ellipse.ATTRIBUTE_NAMES);e.left=e.left||0;e.top=e.top|| +0;e=new b.Ellipse(c(e,d));e.top-=e.ry;e.left-=e.rx;return e},b.Ellipse.fromObject=function(a,c,d){return b.Object._fromObject("Ellipse",a,c,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.Rect?b.warn("fabric.Rect is already defined"):(b.Rect=b.util.createClass(b.Object,{stateProperties:b.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:b.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(b){this.callSuper("initialize",b);this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(b,a){if(1=== +this.width&&1===this.height)b.fillRect(-.5,-.5,1,1);else{var c=this.rx?Math.min(this.rx,this.width/2):0,d=this.ry?Math.min(this.ry,this.height/2):0,f=this.width,e=this.height,k=a?this.left:-this.width/2,m=a?this.top:-this.height/2,n=0!==c||0!==d;b.beginPath();b.moveTo(k+c,m);b.lineTo(k+f-c,m);n&&b.bezierCurveTo(k+f-.4477152502*c,m,k+f,m+.4477152502*d,k+f,m+d);b.lineTo(k+f,m+e-d);n&&b.bezierCurveTo(k+f,m+e-.4477152502*d,k+f-.4477152502*c,m+e,k+f-c,m+e);b.lineTo(k+c,m+e);n&&b.bezierCurveTo(k+.4477152502* +c,m+e,k,m+e-.4477152502*d,k,m+e-d);b.lineTo(k,m+d);n&&b.bezierCurveTo(k,m+.4477152502*d,k+.4477152502*c,m,k+c,m);b.closePath();this._renderFill(b);this._renderStroke(b)}},_renderDashedStroke:function(c){var a=-this.width/2,d=-this.height/2,e=this.width,f=this.height;c.beginPath();b.util.drawDashedLine(c,a,d,a+e,d,this.strokeDashArray);b.util.drawDashedLine(c,a+e,d,a+e,d+f,this.strokeDashArray);b.util.drawDashedLine(c,a+e,d+f,a,d+f,this.strokeDashArray);b.util.drawDashedLine(c,a,d+f,a,d,this.strokeDashArray); +c.closePath()},toObject:function(b){return this.callSuper("toObject",["rx","ry"].concat(b))},toSVG:function(b){var a=this._createBaseSVGMarkup(),c=this.left,d=this.top;this.group&&"path-group"===this.group.type||(c=-this.width/2,d=-this.height/2);a.push("<rect ",this.getSvgId(),'x="',c,'" y="',d,'" rx="',this.get("rx"),'" ry="',this.get("ry"),'" width="',this.width,'" height="',this.height,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'"/>\n'); +return b?b(a.join("")):a.join("")}}),b.Rect.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),b.Rect.fromElement=function(c,a){if(!c)return null;a=a||{};var e=b.parseAttributes(c,b.Rect.ATTRIBUTE_NAMES);e.left=e.left||0;e.top=e.top||0;e=new b.Rect(d(a?b.util.object.clone(a):{},e));e.visible=e.visible&&0<e.width&&0<e.height;return e},b.Rect.fromObject=function(c,a,d){return b.Object._fromObject("Rect",c,a,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend,c=b.util.array.min,a=b.util.array.max,g=b.util.toFixed,h=b.Object.NUM_FRACTION_DIGITS;b.Polyline?b.warn("fabric.Polyline is already defined"):(b.Polyline=b.util.createClass(b.Object,{type:"polyline",points:null,minX:0,minY:0,cacheProperties:b.Object.prototype.cacheProperties.concat("points"),initialize:function(a,b){b=b||{};this.points=a||[];this.callSuper("initialize",b);this._calcDimensions();"top"in b||(this.top=this.minY);"left"in +b||(this.left=this.minX);this.pathOffset={x:this.minX+this.width/2,y:this.minY+this.height/2}},_calcDimensions:function(){var b=this.points,d=c(b,"x"),e=c(b,"y"),g=a(b,"x"),b=a(b,"y");this.width=g-d||0;this.height=b-e||0;this.minX=d||0;this.minY=e||0},toObject:function(a){return d(this.callSuper("toObject",a),{points:this.points.concat()})},toSVG:function(a){var b=[],c=0,d=0,f=this._createBaseSVGMarkup();this.group&&"path-group"===this.group.type||(c=this.pathOffset.x,d=this.pathOffset.y);for(var e= +0,q=this.points.length;e<q;e++)b.push(g(this.points[e].x-c,h),",",g(this.points[e].y-d,h)," ");f.push("<",this.type," ",this.getSvgId(),'points="',b.join(""),'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n');return a?a(f.join("")):f.join("")},commonRender:function(a,b){var c,d=this.points.length,f=b?0:this.pathOffset.x,e=b?0:this.pathOffset.y;if(!d||isNaN(this.points[d-1].y))return!1;a.beginPath();a.moveTo(this.points[0].x-f,this.points[0].y- +e);for(var g=0;g<d;g++)c=this.points[g],a.lineTo(c.x-f,c.y-e);return!0},_render:function(a,b){this.commonRender(a,b)&&(this._renderFill(a),this._renderStroke(a))},_renderDashedStroke:function(a){var c,d;a.beginPath();for(var f=0,e=this.points.length;f<e;f++)c=this.points[f],d=this.points[f+1]||c,b.util.drawDashedLine(a,c.x,c.y,d.x,d.y,this.strokeDashArray)},complexity:function(){return this.get("points").length}}),b.Polyline.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polyline.fromElement=function(a, +c){if(!a)return null;c||(c={});var d=b.parsePointsAttribute(a.getAttribute("points")),f=b.parseAttributes(a,b.Polyline.ATTRIBUTE_NAMES);return new b.Polyline(d,b.util.object.extend(f,c))},b.Polyline.fromObject=function(a,c,d){return b.Object._fromObject("Polyline",a,c,d,"points")})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.Polygon?b.warn("fabric.Polygon is already defined"):(b.Polygon=b.util.createClass(b.Polyline,{type:"polygon",_render:function(b,a){this.commonRender(b,a)&&(b.closePath(),this._renderFill(b),this._renderStroke(b))},_renderDashedStroke:function(b){this.callSuper("_renderDashedStroke",b);b.closePath()}}),b.Polygon.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polygon.fromElement=function(c,a){if(!c)return null;a||(a={});var e=b.parsePointsAttribute(c.getAttribute("points")), +h=b.parseAttributes(c,b.Polygon.ATTRIBUTE_NAMES);return new b.Polygon(e,d(h,a))},b.Polygon.fromObject=function(c,a,d){return b.Object._fromObject("Polygon",c,a,d,"points")})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.array.min,c=b.util.array.max,a=b.util.object.extend,g=Object.prototype.toString,h=b.util.drawArc,f={m:2,l:2,h:1,v:1,c:6,s:4,q:4,t:2,a:7},l={m:"l",M:"L"};b.Path?b.warn("fabric.Path is already defined"):(b.Path=b.util.createClass(b.Object,{type:"path",path:null,minX:0,minY:0,cacheProperties:b.Object.prototype.cacheProperties.concat("path","fillRule"),stateProperties:b.Object.prototype.stateProperties.concat("path"),initialize:function(a,b){b=b||{}; +this.callSuper("initialize",b);a||(a=[]);var c="[object Array]"===g.call(a);if(this.path=c?a:a.match&&a.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi))c||(this.path=this._parsePath()),this._setPositionDimensions(b)},_setPositionDimensions:function(a){var b=this._parseDimensions();this.minX=b.left;this.minY=b.top;this.width=b.width;this.height=b.height;"undefined"===typeof a.left&&(this.left=b.left+("center"===this.originX?this.width/2:"right"===this.originX?this.width:0));"undefined"===typeof a.top&&(this.top= +b.top+("center"===this.originY?this.height/2:"bottom"===this.originY?this.height:0));this.pathOffset=this.pathOffset||{x:this.minX+this.width/2,y:this.minY+this.height/2}},_renderPathCommands:function(a){var b,c=null,d=0,f=0,e=0,g=0,l=0,k=0,w,y,x=-this.pathOffset.x,u=-this.pathOffset.y;this.group&&"path-group"===this.group.type&&(u=x=0);a.beginPath();for(var C=0,D=this.path.length;C<D;++C){b=this.path[C];switch(b[0]){case "l":e+=b[1];g+=b[2];a.lineTo(e+x,g+u);break;case "L":e=b[1];g=b[2];a.lineTo(e+ +x,g+u);break;case "h":e+=b[1];a.lineTo(e+x,g+u);break;case "H":e=b[1];a.lineTo(e+x,g+u);break;case "v":g+=b[1];a.lineTo(e+x,g+u);break;case "V":g=b[1];a.lineTo(e+x,g+u);break;case "m":e+=b[1];g+=b[2];d=e;f=g;a.moveTo(e+x,g+u);break;case "M":e=b[1];g=b[2];d=e;f=g;a.moveTo(e+x,g+u);break;case "c":w=e+b[5];y=g+b[6];l=e+b[3];k=g+b[4];a.bezierCurveTo(e+b[1]+x,g+b[2]+u,l+x,k+u,w+x,y+u);e=w;g=y;break;case "C":e=b[5];g=b[6];l=b[3];k=b[4];a.bezierCurveTo(b[1]+x,b[2]+u,l+x,k+u,e+x,g+u);break;case "s":w=e+b[3]; +y=g+b[4];null===c[0].match(/[CcSs]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.bezierCurveTo(l+x,k+u,e+b[1]+x,g+b[2]+u,w+x,y+u);l=e+b[1];k=g+b[2];e=w;g=y;break;case "S":w=b[3];y=b[4];null===c[0].match(/[CcSs]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.bezierCurveTo(l+x,k+u,b[1]+x,b[2]+u,w+x,y+u);e=w;g=y;l=b[1];k=b[2];break;case "q":w=e+b[3];y=g+b[4];l=e+b[1];k=g+b[2];a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "Q":w=b[3];y=b[4];a.quadraticCurveTo(b[1]+x,b[2]+u,w+x,y+u);e=w;g=y;l=b[1];k=b[2];break;case "t":w= +e+b[1];y=g+b[2];null===c[0].match(/[QqTt]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "T":w=b[1];y=b[2];null===c[0].match(/[QqTt]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "a":h(a,e+x,g+u,[b[1],b[2],b[3],b[4],b[5],b[6]+e+x,b[7]+g+u]);e+=b[6];g+=b[7];break;case "A":h(a,e+x,g+u,[b[1],b[2],b[3],b[4],b[5],b[6]+x,b[7]+u]);e=b[6];g=b[7];break;case "z":case "Z":e=d,g=f,a.closePath()}c=b}},_render:function(a){this._renderPathCommands(a); +this._renderFill(a);this._renderStroke(a)},toString:function(){return"#<fabric.Path ("+this.complexity()+'): { "top": '+this.top+', "left": '+this.left+" }>"},toObject:function(b){return a(this.callSuper("toObject",["sourcePath","pathOffset"].concat(b)),{path:this.path.map(function(a){return a.slice()}),top:this.top,left:this.left})},toDatalessObject:function(a){a=this.toObject(a);this.sourcePath&&(a.path=this.sourcePath);delete a.sourcePath;return a},toSVG:function(a){for(var b=[],c=this._createBaseSVGMarkup(), +d="",f=0,e=this.path.length;f<e;f++)b.push(this.path[f].join(" "));b=b.join(" ");this.group&&"path-group"===this.group.type||(d=" translate("+-this.pathOffset.x+", "+-this.pathOffset.y+") ");c.push("<path ",this.getSvgId(),'d="',b,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),d,this.getSvgTransformMatrix(),'" stroke-linecap="round" ',"/>\n");return a?a(c.join("")):c.join("")},complexity:function(){return this.path.length},_parsePath:function(){for(var a=[],b=[],c,d,e=/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig, +g,h=0,v=this.path.length;h<v;h++){c=this.path[h];g=c.slice(1).trim();for(b.length=0;d=e.exec(g);)b.push(d[0]);c=[c.charAt(0)];g=0;for(var A=b.length;g<A;g++)d=parseFloat(b[g]),isNaN(d)||c.push(d);d=c[0];g=f[d.toLowerCase()];A=l[d]||d;if(c.length-1>g)for(var w=1,y=c.length;w<y;w+=g)a.push([d].concat(c.slice(w,w+g))),d=A;else a.push(c)}return a},_parseDimensions:function(){for(var a=[],f=[],e,g=null,h=0,l=0,r=0,v=0,A=0,w=0,y,x,u,C=0,D=this.path.length;C<D;++C){e=this.path[C];switch(e[0]){case "l":r+= +e[1];v+=e[2];u=[];break;case "L":r=e[1];v=e[2];u=[];break;case "h":r+=e[1];u=[];break;case "H":r=e[1];u=[];break;case "v":v+=e[1];u=[];break;case "V":v=e[1];u=[];break;case "m":r+=e[1];v+=e[2];h=r;l=v;u=[];break;case "M":r=e[1];v=e[2];h=r;l=v;u=[];break;case "c":y=r+e[5];x=v+e[6];A=r+e[3];w=v+e[4];u=b.util.getBoundsOfCurve(r,v,r+e[1],v+e[2],A,w,y,x);r=y;v=x;break;case "C":A=e[3];w=e[4];u=b.util.getBoundsOfCurve(r,v,e[1],e[2],A,w,e[5],e[6]);r=e[5];v=e[6];break;case "s":y=r+e[3];x=v+e[4];null===g[0].match(/[CcSs]/)? +(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,r+e[1],v+e[2],y,x);A=r+e[1];w=v+e[2];r=y;v=x;break;case "S":y=e[3];x=e[4];null===g[0].match(/[CcSs]/)?(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,e[1],e[2],y,x);r=y;v=x;A=e[1];w=e[2];break;case "q":y=r+e[3];x=v+e[4];A=r+e[1];w=v+e[2];u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "Q":A=e[1];w=e[2];u=b.util.getBoundsOfCurve(r,v,A,w,A,w,e[3],e[4]);r=e[3];v=e[4];break;case "t":y=r+e[1];x=v+e[2];null===g[0].match(/[QqTt]/)? +(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "T":y=e[1];x=e[2];null===g[0].match(/[QqTt]/)?(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "a":u=b.util.getBoundsOfArc(r,v,e[1],e[2],e[3],e[4],e[5],e[6]+r,e[7]+v);r+=e[6];v+=e[7];break;case "A":u=b.util.getBoundsOfArc(r,v,e[1],e[2],e[3],e[4],e[5],e[6],e[7]);r=e[6];v=e[7];break;case "z":case "Z":r=h,v=l}g=e;u.forEach(function(b){a.push(b.x);f.push(b.y)});a.push(r); +f.push(v)}e=d(a)||0;g=d(f)||0;h=c(a)||0;l=c(f)||0;return{left:e,top:g,width:h-e,height:l-g}}}),b.Path.fromObject=function(a,c,d){var e;if("string"===typeof a.path)b.loadSVGFromURL(a.path,function(b){var d=a.path;e=b[0];delete a.path;e.setOptions(a);e.setSourcePath(d);c&&c(e)});else return b.Object._fromObject("Path",a,c,d,"path")},b.Path.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["d"]),b.Path.fromElement=function(c,d,e){c=b.parseAttributes(c,b.Path.ATTRIBUTE_NAMES);d&&d(new b.Path(c.d,a(c,e)))}, +b.Path.async=!0)})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.PathGroup?b.warn("fabric.PathGroup is already defined"):(b.PathGroup=b.util.createClass(b.Object,{type:"path-group",fill:"",cacheProperties:[],initialize:function(b,a){a=a||{};this.paths=b||[];for(var c=this.paths.length;c--;)this.paths[c].group=this;a.toBeParsed&&(this.parseDimensionsFromPaths(a),delete a.toBeParsed);this.setOptions(a);this.setCoords()},parseDimensionsFromPaths:function(c){for(var a,d,e=[],f=[],l,k=this.paths.length;k--;){a= +this.paths[k];d=a.height+a.strokeWidth;l=a.width+a.strokeWidth;a=[{x:a.left,y:a.top},{x:a.left+l,y:a.top},{x:a.left,y:a.top+d},{x:a.left+l,y:a.top+d}];l=this.paths[k].transformMatrix;for(var m=0;m<a.length;m++)d=a[m],l&&(d=b.util.transformPoint(d,l,!1)),e.push(d.x),f.push(d.y)}c.width=Math.max.apply(null,e);c.height=Math.max.apply(null,f)},drawObject:function(b){b.save();b.translate(-this.width/2,-this.height/2);for(var a=0,c=this.paths.length;a<c;++a)this.paths[a].render(b,!0);b.restore()},shouldCache:function(){var b= +this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching());if(this.caching=b)for(var a=0,d=this.paths.length;a<d;a++)if(this.paths[a].willDrawShadow())return this.caching=!1;return b},willDrawShadow:function(){if(this.shadow)return!0;for(var b=0,a=this.paths.length;b<a;b++)if(this.paths[b].willDrawShadow())return!0;return!1},isCaching:function(){return this.caching||this.group&&this.group.isCaching()},isCacheDirty:function(){if(this.callSuper("isCacheDirty"))return!0;if(!this.statefullCache)return!1; +for(var b=0,a=this.paths.length;b<a;b++)if(this.paths[b].isCacheDirty(!0))return this._cacheCanvas&&(b=this.cacheWidth/this.zoomX,a=this.cacheHeight/this.zoomY,this._cacheContext.clearRect(-b/2,-a/2,b,a)),!0;return!1},_set:function(b,a){if("fill"===b&&a&&this.isSameColor())for(var c=this.paths.length;c--;)this.paths[c]._set(b,a);return this.callSuper("_set",b,a)},toObject:function(b){var a=this.paths.map(function(a){var c=a.includeDefaultValues;a.includeDefaultValues=a.group.includeDefaultValues; +var d=a.toObject(b);a.includeDefaultValues=c;return d});return d(this.callSuper("toObject",["sourcePath"].concat(b)),{paths:a})},toDatalessObject:function(b){b=this.toObject(b);this.sourcePath&&(b.paths=this.sourcePath);return b},toSVG:function(b){var a=this.getObjects(),c=this.getPointByOrigin("left","top"),d="translate("+c.x+" "+c.y+")",c=this._createBaseSVGMarkup();c.push("<g ",this.getSvgId(),'style="',this.getSvgStyles(),'" ','transform="',this.getSvgTransformMatrix(),d,this.getSvgTransform(), +'" ',">\n");for(var d=0,e=a.length;d<e;d++)c.push("\t",a[d].toSVG(b));c.push("</g>\n");return b?b(c.join("")):c.join("")},toString:function(){return"#<fabric.PathGroup ("+this.complexity()+"): { top: "+this.top+", left: "+this.left+" }>"},isSameColor:function(){var b=this.getObjects()[0].get("fill")||"";if("string"!==typeof b)return!1;b=b.toLowerCase();return this.getObjects().every(function(a){a=a.get("fill")||"";return"string"===typeof a&&a.toLowerCase()===b})},complexity:function(){return this.paths.reduce(function(b, +a){return b+(a&&a.complexity?a.complexity():0)},0)},getObjects:function(){return this.paths}}),b.PathGroup.fromObject=function(c,a){var d=c.paths;delete c.paths;"string"===typeof d?b.loadSVGFromURL(d,function(e){e=b.util.groupSVGElements(e,c,d);c.paths=d;a(e)}):b.util.enlivenObjects(d,function(e){e=new b.PathGroup(e,c);c.paths=d;a(e)})},b.PathGroup.async=!0)})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend,c=b.util.array.min,a=b.util.array.max;if(!b.Group){var g={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};b.Group=b.util.createClass(b.Object,b.Collection,{type:"group",strokeWidth:0,subTargetCheck:!1,cacheProperties:[],initialize:function(a,b,c){b=b||{};this._objects=[];c&&this.callSuper("initialize",b);this._objects=a||[];for(a=this._objects.length;a--;)this._objects[a].group=this; +b.originX&&(this.originX=b.originX);b.originY&&(this.originY=b.originY);c?(this._updateObjectsCoords(!0),this._updateObjectsACoords()):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",b));this.setCoords();this.saveCoords()},_updateObjectsACoords:function(){for(var a=this._objects.length;a--;)this._objects[a].setCoords(!0,!0)},_updateObjectsCoords:function(a){for(var b=this.getCenterPoint(),c=this._objects.length;c--;)this._updateObjectCoords(this._objects[c],b,a)},_updateObjectCoords:function(a, +b,c){a.__origHasControls=a.hasControls;a.hasControls=!1;if(!c){c=a.getLeft();var d=a.getTop();a.set({left:c-b.x,top:d-b.y});a.setCoords(!0,!0)}},toString:function(){return"#<fabric.Group: ("+this.complexity()+")>"},addWithUpdate:function(a){this._restoreObjectsState();b.util.resetObjectTransform(this);a&&(this._objects.push(a),a.group=this,a._set("canvas",this.canvas));this.forEachObject(this._setObjectActive,this);this._calcBounds();this._updateObjectsCoords();this.setCoords();this.dirty=!0;return this}, +_setObjectActive:function(a){a.set("active",!0);a.group=this},removeWithUpdate:function(a){this._restoreObjectsState();b.util.resetObjectTransform(this);this.forEachObject(this._setObjectActive,this);this.remove(a);this._calcBounds();this._updateObjectsCoords();this.setCoords();this.dirty=!0;return this},_onObjectAdded:function(a){this.dirty=!0;a.group=this;a._set("canvas",this.canvas)},_onObjectRemoved:function(a){this.dirty=!0;delete a.group;a.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(a,b){var c=this._objects.length;if(this.delegatedProperties[a]||"canvas"===a)for(;c--;)this._objects[c].set(a,b);else for(;c--;)this._objects[c].setOnGroup(a,b);this.callSuper("_set",a,b)},toObject:function(a){var b=this.getObjects().map(function(b){var c=b.includeDefaultValues;b.includeDefaultValues=b.group.includeDefaultValues;var d=b.toObject(a);b.includeDefaultValues= +c;return d});return d(this.callSuper("toObject",a),{objects:b})},toDatalessObject:function(a){var b=this.getObjects().map(function(b){var c=b.includeDefaultValues;b.includeDefaultValues=b.group.includeDefaultValues;var d=b.toDatalessObject(a);b.includeDefaultValues=c;return d});return d(this.callSuper("toDatalessObject",a),{objects:b})},render:function(a){this._transformDone=!0;this.callSuper("render",a);this._transformDone=!1},shouldCache:function(){var a=this.objectCaching&&(!this.group||this.needsItsOwnCache()|| +!this.group.isCaching());if(this.caching=a)for(var b=0,c=this._objects.length;b<c;b++)if(this._objects[b].willDrawShadow())return this.caching=!1;return a},willDrawShadow:function(){if(this.callSuper("willDrawShadow"))return!0;for(var a=0,b=this._objects.length;a<b;a++)if(this._objects[a].willDrawShadow())return!0;return!1},isCaching:function(){return this.caching||this.group&&this.group.isCaching()},drawObject:function(a){for(var b=0,c=this._objects.length;b<c;b++)this._renderObject(this._objects[b], +a)},isCacheDirty:function(){if(this.callSuper("isCacheDirty"))return!0;if(!this.statefullCache)return!1;for(var a=0,b=this._objects.length;a<b;a++)if(this._objects[a].isCacheDirty(!0))return this._cacheCanvas&&(a=this.cacheWidth/this.zoomX,b=this.cacheHeight/this.zoomY,this._cacheContext.clearRect(-a/2,-b/2,a,b)),!0;return!1},_renderControls:function(a,b){a.save();a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1;this.callSuper("_renderControls",a,b);for(var c=0,d=this._objects.length;c< +d;c++)this._objects[c]._renderControls(a);a.restore()},_renderObject:function(a,b){if(a.visible){var c=a.hasRotatingPoint;a.hasRotatingPoint=!1;a.render(b);a.hasRotatingPoint=c}},_restoreObjectsState:function(){this._objects.forEach(this._restoreObjectState,this);return this},realizeTransform:function(a){var c=a.calcTransformMatrix(),c=b.util.qrDecompose(c),d=new b.Point(c.translateX,c.translateY);a.flipX=!1;a.flipY=!1;a.set("scaleX",c.scaleX);a.set("scaleY",c.scaleY);a.skewX=c.skewX;a.skewY=c.skewY; +a.angle=c.angle;a.setPositionByOrigin(d,"center","center");return a},_restoreObjectState:function(a){this.realizeTransform(a);a.setCoords();a.hasControls=a.__origHasControls;delete a.__origHasControls;a.set("active",!1);delete a.group;return this},destroy:function(){this._objects.forEach(function(a){a.set("dirty",!0)});return this._restoreObjectsState()},saveCoords:function(){this._originalLeft=this.get("left");this._originalTop=this.get("top");return this},hasMoved:function(){return this._originalLeft!== +this.get("left")||this._originalTop!==this.get("top")},setObjectsCoords:function(){this.forEachObject(function(a){a.setCoords(!0,!0)});return this},_calcBounds:function(a){for(var b=[],c=[],d,e,g=["tr","br","bl","tl"],h=0,q=this._objects.length,t,r=g.length;h<q;++h)for(d=this._objects[h],d.setCoords(!0),t=0;t<r;t++)e=g[t],b.push(d.oCoords[e].x),c.push(d.oCoords[e].y);this.set(this._getBounds(b,c,a))},_getBounds:function(d,e,g){var f=new b.Point(c(d),c(e));d=new b.Point(a(d),a(e));d={width:d.x-f.x|| +0,height:d.y-f.y||0};g||(d.left=f.x||0,d.top=f.y||0,"center"===this.originX&&(d.left+=d.width/2),"right"===this.originX&&(d.left+=d.width),"center"===this.originY&&(d.top+=d.height/2),"bottom"===this.originY&&(d.top+=d.height));return d},toSVG:function(a){var b=this._createBaseSVGMarkup();b.push("<g ",this.getSvgId(),'transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'" style="',this.getSvgFilter(),'">\n');for(var c=0,d=this._objects.length;c<d;c++)b.push("\t",this._objects[c].toSVG(a)); +b.push("</g>\n");return a?a(b.join("")):b.join("")},get:function(a){if(a in g){if(this[a])return this[a];for(var b=0,c=this._objects.length;b<c;b++)if(this._objects[b][a])return!0;return!1}return a in this.delegatedProperties?this._objects[0]&&this._objects[0].get(a):this[a]}});b.Group.fromObject=function(a,c){b.util.enlivenObjects(a.objects,function(d){var e=b.util.object.clone(a,!0);delete e.objects;c&&c(new b.Group(d,e,!0))})};b.Group.async=!0}})("undefined"!==typeof exports?exports:this); +(function(e){var b=fabric.util.object.extend;e.fabric||(e.fabric={});e.fabric.Image?fabric.warn("fabric.Image is already defined."):(fabric.Image=fabric.util.createClass(fabric.Object,{type:"image",crossOrigin:"",alignX:"none",alignY:"none",meetOrSlice:"meet",strokeWidth:0,_lastScaleX:1,_lastScaleY:1,minimumScaleTrigger:.5,stateProperties:fabric.Object.prototype.stateProperties.concat("alignX","alignY","meetOrSlice"),objectCaching:!1,initialize:function(b,c,a){c||(c={});this.filters=[];this.resizeFilters= +[];this.callSuper("initialize",c);this._initElement(b,c,a)},getElement:function(){return this._element},setElement:function(b,c,a){var d;this._originalElement=this._element=b;this._initConfig(a);0===this.resizeFilters.length?b=c:(d=this,b=function(){d.applyFilters(c,d.resizeFilters,d._filteredEl||d._originalElement,!0)});0!==this.filters.length?this.applyFilters(b):b&&b(this);return this},setCrossOrigin:function(b){this.crossOrigin=b;this._element.crossOrigin=b;return this},getOriginalSize:function(){var b= +this.getElement();return{width:b.width,height:b.height}},_stroke:function(b){if(this.stroke&&0!==this.strokeWidth){var c=this.width/2,a=this.height/2;b.beginPath();b.moveTo(-c,-a);b.lineTo(c,-a);b.lineTo(c,a);b.lineTo(-c,a);b.lineTo(-c,-a);b.closePath()}},_renderDashedStroke:function(b){var c=-this.width/2,a=-this.height/2,d=this.width,e=this.height;b.save();this._setStrokeStyles(b);b.beginPath();fabric.util.drawDashedLine(b,c,a,c+d,a,this.strokeDashArray);fabric.util.drawDashedLine(b,c+d,a,c+d,a+ +e,this.strokeDashArray);fabric.util.drawDashedLine(b,c+d,a+e,c,a+e,this.strokeDashArray);fabric.util.drawDashedLine(b,c,a+e,c,a,this.strokeDashArray);b.closePath();b.restore()},toObject:function(d){var c=[],a=[],e=1,h=1;this.filters.forEach(function(a){a&&("Resize"===a.type&&(e*=a.scaleX,h*=a.scaleY),c.push(a.toObject()))});this.resizeFilters.forEach(function(b){b&&a.push(b.toObject())});d=b(this.callSuper("toObject",["crossOrigin","alignX","alignY","meetOrSlice"].concat(d)),{src:this.getSrc(),filters:c, +resizeFilters:a});d.width/=e;d.height/=h;return d},toSVG:function(b){var c=this._createBaseSVGMarkup(),a=-this.width/2,d=-this.height/2,e="none";this.group&&"path-group"===this.group.type&&(a=this.left,d=this.top);"none"!==this.alignX&&"none"!==this.alignY&&(e="x"+this.alignX+"Y"+this.alignY+" "+this.meetOrSlice);c.push('<g transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'">\n',"<image ",this.getSvgId(),'xlink:href="',this.getSvgSrc(!0),'" x="',a,'" y="',d,'" style="',this.getSvgStyles(), +'" width="',this.width,'" height="',this.height,'" preserveAspectRatio="',e,'"',"></image>\n");if(this.stroke||this.strokeDashArray)e=this.fill,this.fill=null,c.push("<rect ",'x="',a,'" y="',d,'" width="',this.width,'" height="',this.height,'" style="',this.getSvgStyles(),'"/>\n'),this.fill=e;c.push("</g>\n");return b?b(c.join("")):c.join("")},getSrc:function(b){return(b=b?this._element:this._originalElement)?fabric.isLikelyNode?b._src:b.src:this.src||""},setSrc:function(b,c,a){fabric.util.loadImage(b, +function(b){return this.setElement(b,c,a)},this,a&&a.crossOrigin)},toString:function(){return'#<fabric.Image: { src: "'+this.getSrc()+'" }>'},applyFilters:function(b,c,a,e){c=c||this.filters;if(a=a||this._originalElement){var d=fabric.util.createImage(),f=this.canvas?this.canvas.getRetinaScaling():fabric.devicePixelRatio,g=this.minimumScaleTrigger/f,k=this,m,n;if(0===c.length)return this._element=a,b&&b(this),a;var p=fabric.util.createCanvasElement();p.width=a.width;p.height=a.height;p.getContext("2d").drawImage(a, +0,0,a.width,a.height);c.forEach(function(a){a&&(e?(m=k.scaleX<g?k.scaleX:1,n=k.scaleY<g?k.scaleY:1,1>m*f&&(m*=f),1>n*f&&(n*=f)):(m=a.scaleX,n=a.scaleY),a.applyTo(p,m,n),e||"Resize"!==a.type||(k.width*=a.scaleX,k.height*=a.scaleY))});d.width=p.width;d.height=p.height;fabric.isLikelyNode?(d.src=p.toBuffer(void 0,fabric.Image.pngCompression),k._element=d,!e&&(k._filteredEl=d),b&&b(k)):(d.onload=function(){k._element=d;!e&&(k._filteredEl=d);b&&b(k);d.onload=p=null},d.src=p.toDataURL("image/png"));return p}}, +_render:function(b,c){var a,d,e=this._findMargins(),f;a=c?this.left:-this.width/2;d=c?this.top:-this.height/2;"slice"===this.meetOrSlice&&(b.beginPath(),b.rect(a,d,this.width,this.height),b.clip());!1===this.isMoving&&this.resizeFilters.length&&this._needsResize()?(this._lastScaleX=this.scaleX,this._lastScaleY=this.scaleY,f=this.applyFilters(null,this.resizeFilters,this._filteredEl||this._originalElement,!0)):f=this._element;f&&b.drawImage(f,a+e.marginX,d+e.marginY,e.width,e.height);this._stroke(b); +this._renderStroke(b)},_needsResize:function(){return this.scaleX!==this._lastScaleX||this.scaleY!==this._lastScaleY},_findMargins:function(){var b=this.width,c=this.height,a=0,e=0;if("none"!==this.alignX||"none"!==this.alignY)b=[this.width/this._element.width,this.height/this._element.height],c="meet"===this.meetOrSlice?Math.min.apply(null,b):Math.max.apply(null,b),b=this._element.width*c,c*=this._element.height,"Mid"===this.alignX&&(a=(this.width-b)/2),"Max"===this.alignX&&(a=this.width-b),"Mid"=== +this.alignY&&(e=(this.height-c)/2),"Max"===this.alignY&&(e=this.height-c);return{width:b,height:c,marginX:a,marginY:e}},_resetWidthHeight:function(){var b=this.getElement();this.set("width",b.width);this.set("height",b.height)},_initElement:function(b,c,a){this.setElement(fabric.util.getById(b),a,c);fabric.util.addClass(this.getElement(),fabric.Image.CSS_CANVAS)},_initConfig:function(b){b||(b={});this.setOptions(b);this._setWidthHeight(b);this._element&&this.crossOrigin&&(this._element.crossOrigin= +this.crossOrigin)},_initFilters:function(b,c){b&&b.length?fabric.util.enlivenObjects(b,function(a){c&&c(a)},"fabric.Image.filters"):c&&c()},_setWidthHeight:function(b){this.width="width"in b?b.width:this.getElement()?this.getElement().width||0:0;this.height="height"in b?b.height:this.getElement()?this.getElement().height||0:0}}),fabric.Image.CSS_CANVAS="canvas-img",fabric.Image.prototype.getSvgSrc=fabric.Image.prototype.getSrc,fabric.Image.fromObject=function(b,c){fabric.util.loadImage(b.src,function(a, +d){d?c&&c(null,d):fabric.Image.prototype._initFilters.call(b,b.filters,function(d){b.filters=d||[];fabric.Image.prototype._initFilters.call(b,b.resizeFilters,function(d){b.resizeFilters=d||[];return new fabric.Image(a,b,c)})})},null,b.crossOrigin)},fabric.Image.fromURL=function(b,c,a){fabric.util.loadImage(b,function(b){c&&c(new fabric.Image(b,a))},null,a&&a.crossOrigin)},fabric.Image.ATTRIBUTE_NAMES=fabric.SHARED_ATTRIBUTES.concat("x y width height preserveAspectRatio xlink:href crossOrigin".split(" ")), +fabric.Image.fromElement=function(d,c,a){d=fabric.parseAttributes(d,fabric.Image.ATTRIBUTE_NAMES);var e;d.preserveAspectRatio&&(e=fabric.util.parsePreserveAspectRatioAttribute(d.preserveAspectRatio),b(d,e));fabric.Image.fromURL(d["xlink:href"],c,b(a?fabric.util.object.clone(a):{},d))},fabric.Image.async=!0,fabric.Image.pngCompression=1)})("undefined"!==typeof exports?exports:this); +fabric.util.object.extend(fabric.Object.prototype,{_getAngleValueForStraighten:function(){var e=this.getAngle()%360;return 0<e?90*Math.round((e-1)/90):90*Math.round(e/90)},straighten:function(){this.setAngle(this._getAngleValueForStraighten());return this},fxStraighten:function(e){e=e||{};var b=function(){},d=e.onComplete||b,c=e.onChange||b,a=this;fabric.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(b){a.setAngle(b); +c()},onComplete:function(){a.setCoords();d()},onStart:function(){a.set("active",!1)}});return this}});fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(e){e.straighten();this.renderAll();return this},fxStraightenObject:function(e){e.fxStraighten({onChange:this.renderAll.bind(this)});return this}});fabric.Image.filters=fabric.Image.filters||{}; +fabric.Image.filters.BaseFilter=fabric.util.createClass({type:"BaseFilter",initialize:function(e){e&&this.setOptions(e)},setOptions:function(e){for(var b in e)this[b]=e[b]},toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}});fabric.Image.filters.BaseFilter.fromObject=function(e,b){var d=new fabric.Image.filters[e.type](e);b&&b(d);return d}; +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Brightness=c(d.BaseFilter,{type:"Brightness",initialize:function(a){a=a||{};this.brightness=a.brightness||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.brightness,e=0,k=c.length;e<k;e+=4)c[e]+=d,c[e+1]+=d,c[e+2]+=d;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{brightness:this.brightness})}});e.Image.filters.Brightness.fromObject= +e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Convolute=c(d.BaseFilter,{type:"Convolute",initialize:function(a){a=a||{};this.opaque=a.opaque;this.matrix=a.matrix||[0,0,0,0,1,0,0,0,0]},applyTo:function(a){var b=this.matrix,c=a.getContext("2d"),d=c.getImageData(0,0,a.width,a.height);a=Math.round(Math.sqrt(b.length));for(var e=Math.floor(a/2),k=d.data,m=d.width,d=d.height,n=c.createImageData(m,d),p=n.data,q=this.opaque?1:0,t,r,v,A,w,y,x,u= +0;u<d;u++)for(var C=0;C<m;C++){w=4*(u*m+C);for(var D=A=v=r=t=0;D<a;D++)for(var z=0;z<a;z++)x=u+D-e,y=C+z-e,0>x||x>d||0>y||y>m||(y=4*(x*m+y),x=b[D*a+z],t+=k[y]*x,r+=k[y+1]*x,v+=k[y+2]*x,A+=k[y+3]*x);p[w]=t;p[w+1]=r;p[w+2]=v;p[w+3]=A+q*(255-A)}c.putImageData(n,0,0)},toObject:function(){return b(this.callSuper("toObject"),{opaque:this.opaque,matrix:this.matrix})}});e.Image.filters.Convolute.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.GradientTransparency=c(d.BaseFilter,{type:"GradientTransparency",initialize:function(a){a=a||{};this.threshold=a.threshold||100},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.threshold,e=c.length,k=0,m=c.length;k<m;k+=4)c[k+3]=d+255*(e-k)/e;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{threshold:this.threshold})}}); +e.Image.filters.GradientTransparency.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Grayscale=d(e.BaseFilter,{type:"Grayscale",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);for(var c=b.data,d=b.width*b.height*4,e=0,l;e<d;)l=(c[e]+c[e+1]+c[e+2])/3,c[e]=l,c[e+1]=l,c[e+2]=l,e+=4;a.putImageData(b,0,0)}});b.Image.filters.Grayscale.fromObject=function(c,a){c=c||{};c.type="Grayscale";return b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports? +exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Invert=d(e.BaseFilter,{type:"Invert",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e;for(e=0;e<d;e+=4)c[e]=255-c[e],c[e+1]=255-c[e+1],c[e+2]=255-c[e+2];a.putImageData(b,0,0)}});b.Image.filters.Invert.fromObject=function(c,a){c=c||{};c.type="Invert";return b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Mask=c(e.BaseFilter,{type:"Mask",initialize:function(a){a=a||{};this.mask=a.mask;this.channel=-1<[0,1,2,3].indexOf(a.channel)?a.channel:0},applyTo:function(a){if(this.mask){var c=a.getContext("2d"),d=c.getImageData(0,0,a.width,a.height),e=d.data,l=this.mask.getElement(),k=b.util.createCanvasElement(),m=this.channel,n=d.width*d.height*4;k.width=a.width;k.height=a.height;k.getContext("2d").drawImage(l, +0,0,a.width,a.height);l=k.getContext("2d").getImageData(0,0,a.width,a.height).data;for(a=0;a<n;a+=4)e[a+3]=l[a+m];c.putImageData(d,0,0)}},toObject:function(){return d(this.callSuper("toObject"),{mask:this.mask.toObject(),channel:this.channel})}});b.Image.filters.Mask.fromObject=function(a,c){b.util.loadImage(a.mask.src,function(d){a.mask=new b.Image(d,a.mask);return b.Image.filters.BaseFilter.fromObject(a,c)})};b.Image.filters.Mask.async=!0})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Noise=c(d.BaseFilter,{type:"Noise",initialize:function(a){a=a||{};this.noise=a.noise||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.noise,e,k=0,m=c.length;k<m;k+=4)e=(.5-Math.random())*d,c[k]+=e,c[k+1]+=e,c[k+2]+=e;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{noise:this.noise})}});e.Image.filters.Noise.fromObject= +e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Pixelate=c(d.BaseFilter,{type:"Pixelate",initialize:function(a){a=a||{};this.blocksize=a.blocksize||4},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);var c=a.data,d=a.height,e=a.width,k,m,n,p,q,t,r;for(m=0;m<d;m+=this.blocksize)for(n=0;n<e;n+=this.blocksize){k=4*m*e+4*n;p=c[k];q=c[k+1];t=c[k+2];r=c[k+3];for(var v=m,A=m+this.blocksize;v<A;v++)for(var w=n,y= +n+this.blocksize;w<y;w++)k=4*v*e+4*w,c[k]=p,c[k+1]=q,c[k+2]=t,c[k+3]=r}b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{blocksize:this.blocksize})}});e.Image.filters.Pixelate.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.RemoveWhite=c(d.BaseFilter,{type:"RemoveWhite",initialize:function(a){a=a||{};this.threshold=a.threshold||30;this.distance=a.distance||20},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.distance,e=255-this.threshold,k=Math.abs,m,n,p,q=0,t=c.length;q<t;q+=4)m=c[q],n=c[q+1],p=c[q+2],m>e&&n>e&&p>e&&k(m-n)<d&&k(m-p)<d&&k(n-p)<d&&(c[q+3]= +0);b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{threshold:this.threshold,distance:this.distance})}});e.Image.filters.RemoveWhite.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Sepia=d(e.BaseFilter,{type:"Sepia",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e,l;for(e=0;e<d;e+=4)l=.3*c[e]+.59*c[e+1]+.11*c[e+2],c[e]=l+100,c[e+1]=l+50,c[e+2]=l+255;a.putImageData(b,0,0)}});b.Image.filters.Sepia.fromObject=function(c,a){c=c||{};c.type="Sepia";return new b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports? +exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Sepia2=d(e.BaseFilter,{type:"Sepia2",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e,l,k,m;for(e=0;e<d;e+=4)l=c[e],k=c[e+1],m=c[e+2],c[e]=(.393*l+.769*k+.189*m)/1.351,c[e+1]=(.349*l+.686*k+.168*m)/1.203,c[e+2]=(.272*l+.534*k+.131*m)/2.14;a.putImageData(b,0,0)}});b.Image.filters.Sepia2.fromObject=function(c,a){c=c||{};c.type="Sepia2";return new b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!== +typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Tint=c(e.BaseFilter,{type:"Tint",initialize:function(a){a=a||{};this.color=a.color||"#000000";this.opacity="undefined"!==typeof a.opacity?a.opacity:(new b.Color(this.color)).getAlpha()},applyTo:function(a){var c=a.getContext("2d");a=c.getImageData(0,0,a.width,a.height);var d=a.data,e=d.length,l,k,m,n,p,q,t,r;l=(new b.Color(this.color)).getSource();k=l[0]*this.opacity;m=l[1]*this.opacity; +n=l[2]*this.opacity;r=1-this.opacity;for(l=0;l<e;l+=4)p=d[l],q=d[l+1],t=d[l+2],d[l]=k+p*r,d[l+1]=m+q*r,d[l+2]=n+t*r;c.putImageData(a,0,0)},toObject:function(){return d(this.callSuper("toObject"),{color:this.color,opacity:this.opacity})}});b.Image.filters.Tint.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Multiply=c(e.BaseFilter,{type:"Multiply",initialize:function(a){a=a||{};this.color=a.color||"#000000"},applyTo:function(a){var c=a.getContext("2d");a=c.getImageData(0,0,a.width,a.height);var d=a.data,e=d.length,l,k;k=(new b.Color(this.color)).getSource();for(l=0;l<e;l+=4)d[l]*=k[0]/255,d[l+1]*=k[1]/255,d[l+2]*=k[2]/255;c.putImageData(a,0,0)},toObject:function(){return d(this.callSuper("toObject"), +{color:this.color})}});b.Image.filters.Multiply.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric;e=b.Image.filters;var d=b.util.createClass;e.Blend=d(e.BaseFilter,{type:"Blend",initialize:function(b){b=b||{};this.color=b.color||"#000";this.image=b.image||!1;this.mode=b.mode||"multiply";this.alpha=b.alpha||1},applyTo:function(c){var a=c.getContext("2d");c=a.getImageData(0,0,c.width,c.height);var d=c.data,e,f,l,k,m,n,p,q=!1;this.image?(q=!0,p=b.util.createCanvasElement(),p.width=this.image.width,p.height=this.image.height,p=new b.StaticCanvas(p),p.add(this.image),p= +p.getContext("2d").getImageData(0,0,p.width,p.height).data):(p=(new b.Color(this.color)).getSource(),e=p[0]*this.alpha,f=p[1]*this.alpha,l=p[2]*this.alpha);for(var t=0,r=d.length;t<r;t+=4)switch(k=d[t],m=d[t+1],n=d[t+2],q&&(e=p[t]*this.alpha,f=p[t+1]*this.alpha,l=p[t+2]*this.alpha),this.mode){case "multiply":d[t]=k*e/255;d[t+1]=m*f/255;d[t+2]=n*l/255;break;case "screen":d[t]=1-(1-k)*(1-e);d[t+1]=1-(1-m)*(1-f);d[t+2]=1-(1-n)*(1-l);break;case "add":d[t]=Math.min(255,k+e);d[t+1]=Math.min(255,m+f);d[t+ +2]=Math.min(255,n+l);break;case "diff":case "difference":d[t]=Math.abs(k-e);d[t+1]=Math.abs(m-f);d[t+2]=Math.abs(n-l);break;case "subtract":k-=e;m-=f;n-=l;d[t]=0>k?0:k;d[t+1]=0>m?0:m;d[t+2]=0>n?0:n;break;case "darken":d[t]=Math.min(k,e);d[t+1]=Math.min(m,f);d[t+2]=Math.min(n,l);break;case "lighten":d[t]=Math.max(k,e),d[t+1]=Math.max(m,f),d[t+2]=Math.max(n,l)}a.putImageData(c,0,0)},toObject:function(){return{color:this.color,image:this.image,mode:this.mode,alpha:this.alpha}}});b.Image.filters.Blend.fromObject= +b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=Math.pow,c=Math.floor,a=Math.sqrt,g=Math.abs,h=Math.max,f=Math.round,l=Math.sin,k=Math.ceil;e=b.Image.filters;var m=b.util.createClass;e.Resize=m(e.BaseFilter,{type:"Resize",resizeType:"hermite",scaleX:0,scaleY:0,lanczosLobes:3,applyTo:function(a,b,c){if(1!==b||1!==c){this.rcpScaleX=1/b;this.rcpScaleY=1/c;var d=a.width,e=a.height;b=f(d*b);c=f(e*c);var g;"sliceHack"===this.resizeType&&(g=this.sliceByTwo(a,d,e,b,c));"hermite"===this.resizeType&&(g=this.hermiteFastResize(a, +d,e,b,c));"bilinear"===this.resizeType&&(g=this.bilinearFiltering(a,d,e,b,c));"lanczos"===this.resizeType&&(g=this.lanczosResize(a,d,e,b,c));a.width=b;a.height=c;a.getContext("2d").putImageData(g,0,0)}},sliceByTwo:function(a,d,e,f,g){var k=a.getContext("2d"),l,m=.5,n=.5,p=1,q=1,t=!1,r=!1,z=d,E=e,B=b.util.createCanvasElement(),F=B.getContext("2d");f=c(f);g=c(g);B.width=h(f,d);B.height=h(g,e);f>d&&(m=2,p=-1);g>e&&(n=2,q=-1);l=k.getImageData(0,0,d,e);a.width=h(f,d);a.height=h(g,e);for(k.putImageData(l, +0,0);!t||!r;)d=z,e=E,f*p<c(z*m*p)?z=c(z*m):(z=f,t=!0),g*q<c(E*n*q)?E=c(E*n):(E=g,r=!0),l=k.getImageData(0,0,d,e),F.putImageData(l,0,0),k.clearRect(0,0,z,E),k.drawImage(B,0,0,d,e,0,0,z,E);return k.getImageData(0,0,f,g)},lanczosResize:function(b,e,f,h,m){var n,p,q,t;function r(b){var k,l,u,v,w,x,A,y,J,M;q=(b+.5)*B;n=c(q);for(k=0;k<m;k++){t=(k+.5)*F;p=c(t);J=y=A=x=w=0;for(l=n-L;l<=n+L;l++)if(!(0>l||l>=e)){M=c(1E3*g(l-q));H[M]||(H[M]={});for(var N=p-O;N<=p+O;N++)0>N||N>=f||(u=c(1E3*g(N-t)),H[M][u]||(H[M][u]= +E(a(d(M*G,2)+d(u*K,2))/1E3)),u=H[M][u],0<u&&(v=4*(N*e+l),w+=u,x+=u*D[v],A+=u*D[v+1],y+=u*D[v+2],J+=u*D[v+3]))}v=4*(k*h+b);z[v]=x/w;z[v+1]=A/w;z[v+2]=y/w;z[v+3]=J/w}return++b<h?r(b):C}b=b.getContext("2d");var u=b.getImageData(0,0,e,f),C=b.getImageData(0,0,h,m),D=u.data,z=C.data,E=function(a){return function(b){if(b>a)return 0;b*=Math.PI;if(1E-16>g(b))return 1;var c=b/a;return l(b)*l(c)/b/c}}(this.lanczosLobes),B=this.rcpScaleX,F=this.rcpScaleY,G=2/this.rcpScaleX,K=2/this.rcpScaleY,L=k(B*this.lanczosLobes/ +2),O=k(F*this.lanczosLobes/2),H={};p=n=t=q=void 0;return r(0)},bilinearFiltering:function(a,b,d,e,f){var g,h,k,l,m,n,p,q,t,r,B=0,F=this.rcpScaleX,G=this.rcpScaleY;p=a.getContext("2d");a=4*(b-1);d=p.getImageData(0,0,b,d).data;var K=p.getImageData(0,0,e,f),L=K.data;for(p=0;p<f;p++)for(q=0;q<e;q++)for(m=c(F*q),n=c(G*p),t=F*q-m,r=G*p-n,n=4*(n*b+m),m=0;4>m;m++)g=d[n+m],h=d[n+4+m],k=d[n+a+m],l=d[n+a+4+m],g=g*(1-t)*(1-r)+h*t*(1-r)+k*r*(1-t)+l*t*r,L[B++]=g;return K},hermiteFastResize:function(b,d,e,f,h){var l= +this.rcpScaleX,m=this.rcpScaleY,n=k(l/2),p=k(m/2);b=b.getContext("2d");e=b.getImageData(0,0,d,e).data;b=b.getImageData(0,0,f,h);for(var q=b.data,t=0;t<h;t++)for(var r=0;r<f;r++){for(var D=4*(r+t*f),z,E=0,B=0,F=0,G=0,K=0,L=0,O=(t+.5)*m,H=c(t*m);H<(t+1)*m;H++)for(var J=g(O-(H+.5))/p,Q=(r+.5)*l,J=J*J,P=c(r*l);P<(r+1)*l;P++){var I=g(Q-(P+.5))/n;z=a(J+I*I);1<z&&-1>z||(z=2*z*z*z-3*z*z+1,0<z&&(I=4*(P+H*d),L+=z*e[I+3],B+=z,255>e[I+3]&&(z=z*e[I+3]/250),F+=z*e[I],G+=z*e[I+1],K+=z*e[I+2],E+=z))}q[D]=F/E;q[D+ +1]=G/E;q[D+2]=K/E;q[D+3]=L/B}return b},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}});b.Image.filters.Resize.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.ColorMatrix=c(d.BaseFilter,{type:"ColorMatrix",initialize:function(a){a||(a={});this.matrix=a.matrix||[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0]},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);var c=a.data,d=c.length,e,k,m,n,p,q=this.matrix;for(e=0;e<d;e+=4)k=c[e],m=c[e+1],n=c[e+2],p=c[e+3],c[e]=k*q[0]+m*q[1]+n*q[2]+p*q[3]+q[4],c[e+1]=k*q[5]+m*q[6]+n*q[7]+ +p*q[8]+q[9],c[e+2]=k*q[10]+m*q[11]+n*q[12]+p*q[13]+q[14],c[e+3]=k*q[15]+m*q[16]+n*q[17]+p*q[18]+q[19];b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{type:this.type,matrix:this.matrix})}});e.Image.filters.ColorMatrix.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Contrast=c(d.BaseFilter,{type:"Contrast",initialize:function(a){a=a||{};this.contrast=a.contrast||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=259*(this.contrast+255)/(255*(259-this.contrast)),e=0,k=c.length;e<k;e+=4)c[e]=d*(c[e]-128)+128,c[e+1]=d*(c[e+1]-128)+128,c[e+2]=d*(c[e+2]-128)+128;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"), +{contrast:this.contrast})}});e.Image.filters.Contrast.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Saturate=c(d.BaseFilter,{type:"Saturate",initialize:function(a){a=a||{};this.saturate=a.saturate||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d,e=.01*-this.saturate,k=0,m=c.length;k<m;k+=4)d=Math.max(c[k],c[k+1],c[k+2]),c[k]+=d!==c[k]?(d-c[k])*e:0,c[k+1]+=d!==c[k+1]?(d-c[k+1])*e:0,c[k+2]+=d!==c[k+2]?(d-c[k+2])*e:0;b.putImageData(a,0, +0)},toObject:function(){return b(this.callSuper("toObject"),{saturate:this.saturate})}});e.Image.filters.Saturate.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.toFixed,c=b.Object.NUM_FRACTION_DIGITS;b.Text?b.warn("fabric.Text is already defined"):(b.Text=b.util.createClass(b.Object,{_dimensionAffectingProps:"fontSize fontWeight fontFamily fontStyle lineHeight text charSpacing textAlign".split(" "),_reNewline:/\r?\n/,_reSpacesAndTabs:/[ \t\r]+/g,type:"text",fontSize:40,fontWeight:"normal",fontFamily:"Times New Roman",textDecoration:"",textAlign:"left",fontStyle:"",lineHeight:1.16,textBackgroundColor:"", +stateProperties:b.Object.prototype.stateProperties.concat("fontFamily","fontWeight","fontSize","text","textDecoration","textAlign","fontStyle","lineHeight","textBackgroundColor","charSpacing"),cacheProperties:b.Object.prototype.cacheProperties.concat("fontFamily","fontWeight","fontSize","text","textDecoration","textAlign","fontStyle","lineHeight","textBackgroundColor","charSpacing","styles"),stroke:null,shadow:null,_fontSizeFraction:.25,_fontSizeMult:1.13,charSpacing:0,initialize:function(a,b){b= +b||{};this.text=a;this.__skipDimension=!0;this.callSuper("initialize",b);this.__skipDimension=!1;this._initDimensions();this.setCoords();this.setupState({propertySet:"_dimensionAffectingProps"})},_initDimensions:function(a){this.__skipDimension||(a||(a=b.util.createCanvasElement().getContext("2d"),this._setTextStyles(a)),this._textLines=this._splitTextIntoLines(),this._clearCache(),this.width=this._getTextWidth(a)||this.cursorWidth||2,this.height=this._getTextHeight(a),this.setCoords())},toString:function(){return"#<fabric.Text ("+ +this.complexity()+'): { "text": "'+this.text+'", "fontFamily": "'+this.fontFamily+'" }>'},_getCacheCanvasDimensions:function(){var a=this.callSuper("_getCacheCanvasDimensions"),b=this.fontSize;a.width+=b*a.zoomX;a.height+=b*a.zoomY;return a},_render:function(a){this._setTextStyles(a);this.group&&"path-group"===this.group.type&&a.translate(this.left,this.top);this._renderTextLinesBackground(a);this._renderText(a);this._renderTextDecoration(a)},_renderText:function(a){this._renderTextFill(a);this._renderTextStroke(a)}, +_setTextStyles:function(a){a.textBaseline="alphabetic";a.font=this._getFontDeclaration()},_getTextHeight:function(){return this._getHeightOfSingleLine()+(this._textLines.length-1)*this._getHeightOfLine()},_getTextWidth:function(a){for(var b=this._getLineWidth(a,0),c=1,d=this._textLines.length;c<d;c++){var e=this._getLineWidth(a,c);e>b&&(b=e)}return b},_renderChars:function(a,b,c,d,e){var f=a.slice(0,-4),g,h;this[f].toLive&&(g=-this.width/2+this[f].offsetX||0,h=-this.height/2+this[f].offsetY||0,b.save(), +b.translate(g,h),d-=g,e-=h);if(0!==this.charSpacing){var l=this._getWidthOfCharSpacing();c=c.split("");for(var q=0,t=c.length;q<t;q++)g=c[q],h=b.measureText(g).width+l,b[a](g,d,e),d+=0<h?h:0}else b[a](c,d,e);this[f].toLive&&b.restore()},_renderTextLine:function(a,b,c,d,e,k){e-=this.fontSize*this._fontSizeFraction;var f=this._getLineWidth(b,k);if("justify"!==this.textAlign||this.width<f)this._renderChars(a,b,c,d,e,k);else for(var f=c.split(/\s+/),g=0,h=this._getWidthOfWords(b,f.join(" "),k,0),h=this.width- +h,l=f.length-1,h=0<l?h/l:0,l=0,t,r=0,v=f.length;r<v;r++){for(;" "===c[g]&&g<c.length;)g++;t=f[r];this._renderChars(a,b,t,d+l,e,k,g);l+=this._getWidthOfWords(b,t,k,g)+h;g+=t.length}},_getWidthOfWords:function(a,b){var c=a.measureText(b).width,d;0!==this.charSpacing&&(d=b.split("").length,d*=this._getWidthOfCharSpacing(),c+=d);return 0<c?c:0},_getLeftOffset:function(){return-this.width/2},_getTopOffset:function(){return-this.height/2},isEmptyStyles:function(){return!0},_renderTextCommon:function(a, +b){for(var c=0,d=this._getLeftOffset(),e=this._getTopOffset(),g=0,m=this._textLines.length;g<m;g++){var n=this._getHeightOfLine(a,g),p=n/this.lineHeight,q=this._getLineWidth(a,g),q=this._getLineLeftOffset(q);this._renderTextLine(b,a,this._textLines[g],d+q,e+c+p,g);c+=n}},_renderTextFill:function(a){!this.fill&&this.isEmptyStyles()||this._renderTextCommon(a,"fillText")},_renderTextStroke:function(a){if(this.stroke&&0!==this.strokeWidth||!this.isEmptyStyles())this.shadow&&!this.shadow.affectStroke&& +this._removeShadow(a),a.save(),this._setLineDash(a,this.strokeDashArray),a.beginPath(),this._renderTextCommon(a,"strokeText"),a.closePath(),a.restore()},_getHeightOfLine:function(){return this._getHeightOfSingleLine()*this.lineHeight},_getHeightOfSingleLine:function(){return this.fontSize*this._fontSizeMult},_renderTextLinesBackground:function(a){if(this.textBackgroundColor){var b=0,c,d,e,k=a.fillStyle;a.fillStyle=this.textBackgroundColor;for(var m=0,n=this._textLines.length;m<n;m++)c=this._getHeightOfLine(a, +m),d=this._getLineWidth(a,m),0<d&&(e=this._getLineLeftOffset(d),a.fillRect(this._getLeftOffset()+e,this._getTopOffset()+b,d,c/this.lineHeight)),b+=c;a.fillStyle=k;this._removeShadow(a)}},_getLineLeftOffset:function(a){return"center"===this.textAlign?(this.width-a)/2:"right"===this.textAlign?this.width-a:0},_clearCache:function(){this.__lineWidths=[];this.__lineHeights=[]},_shouldClearDimensionCache:function(){var a=this._forceClearCache;a||(a=this.hasStateChanged("_dimensionAffectingProps"));a&&(this.saveState({propertySet:"_dimensionAffectingProps"}), +this.dirty=!0);return a},_getLineWidth:function(a,b){if(this.__lineWidths[b])return-1===this.__lineWidths[b]?this.width:this.__lineWidths[b];var c,d;d=this._textLines[b];c=""===d?0:this._measureLine(a,b);(this.__lineWidths[b]=c)&&"justify"===this.textAlign&&(d=d.split(/\s+/),1<d.length&&(this.__lineWidths[b]=-1));return c},_getWidthOfCharSpacing:function(){return 0!==this.charSpacing?this.fontSize*this.charSpacing/1E3:0},_measureLine:function(a,b){var c=this._textLines[b],d=a.measureText(c).width, +e=0;0!==this.charSpacing&&(c=c.split("").length,e=(c-1)*this._getWidthOfCharSpacing());d+=e;return 0<d?d:0},_renderTextDecoration:function(a){if(this.textDecoration){var b=this.height/2,c=[];-1<this.textDecoration.indexOf("underline")&&c.push(.85);-1<this.textDecoration.indexOf("line-through")&&c.push(.43);-1<this.textDecoration.indexOf("overline")&&c.push(-.12);if(0<c.length){var d,e=0,k,m,n,p,q,t;d=0;for(k=this._textLines.length;d<k;d++){p=this._getLineWidth(a,d);q=this._getLineLeftOffset(p);t= +this._getHeightOfLine(a,d);m=0;for(n=c.length;m<n;m++)a.fillRect(this._getLeftOffset()+q,e+(this._fontSizeMult-1+c[m])*this.fontSize-b,p,this.fontSize/15);e+=t}}}},_getFontDeclaration:function(){return[b.isLikelyNode?this.fontWeight:this.fontStyle,b.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+"px",b.isLikelyNode?'"'+this.fontFamily+'"':this.fontFamily].join(" ")},render:function(a,b){!this.visible||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(this._shouldClearDimensionCache()&& +(this._setTextStyles(a),this._initDimensions(a)),this.callSuper("render",a,b))},_splitTextIntoLines:function(){return this.text.split(this._reNewline)},toObject:function(a){a="text fontSize fontWeight fontFamily fontStyle lineHeight textDecoration textAlign textBackgroundColor charSpacing".split(" ").concat(a);return this.callSuper("toObject",a)},toSVG:function(a){this.ctx||(this.ctx=b.util.createCanvasElement().getContext("2d"));var c=this._createBaseSVGMarkup(),d=this._getSVGLeftTopOffsets(this.ctx), +d=this._getSVGTextAndBg(d.textTop,d.textLeft);this._wrapSVGTextAndBg(c,d);return a?a(c.join("")):c.join("")},_getSVGLeftTopOffsets:function(a){a=this._getHeightOfLine(a,0);return{textLeft:-this.width/2+(this.group&&"path-group"===this.group.type?this.left:0),textTop:0+(this.group&&"path-group"===this.group.type?-this.top:0),lineTop:a}},_wrapSVGTextAndBg:function(a,b){var c=this.getSvgFilter(),c=""===c?"":' style="'+c+'"';a.push("\t<g ",this.getSvgId(),'transform="',this.getSvgTransform(),this.getSvgTransformMatrix(), +'"',c,">\n",b.textBgRects.join(""),'\t\t<text xml:space="preserve" ',this.fontFamily?'font-family="'+this.fontFamily.replace(/"/g,"'")+'" ':"",this.fontSize?'font-size="'+this.fontSize+'" ':"",this.fontStyle?'font-style="'+this.fontStyle+'" ':"",this.fontWeight?'font-weight="'+this.fontWeight+'" ':"",this.textDecoration?'text-decoration="'+this.textDecoration+'" ':"",'style="',this.getSvgStyles(!0),'" >\n',b.textSpans.join(""),"\t\t</text>\n","\t</g>\n")},getSvgStyles:function(a){return b.Object.prototype.getSvgStyles.call(this, +a)+" white-space: pre;"},_getSVGTextAndBg:function(a,b){var c=[],d=[],e=0;this._setSVGBg(d);for(var g=0,m=this._textLines.length;g<m;g++)this.textBackgroundColor&&this._setSVGTextLineBg(d,g,b,a,e),this._setSVGTextLineText(g,c,e,b,a,d),e+=this._getHeightOfLine(this.ctx,g);return{textSpans:c,textBgRects:d}},_setSVGTextLineText:function(a,e,h,f,l){h=this.fontSize*(this._fontSizeMult-this._fontSizeFraction)-l+h-this.height/2;"justify"===this.textAlign?this._setSVGTextLineJustifed(a,e,h,f):e.push('\t\t\t<tspan x="', +d(f+this._getLineLeftOffset(this._getLineWidth(this.ctx,a)),c),'" ','y="',d(h,c),'" ',this._getFillAttributes(this.fill),">",b.util.string.escapeXml(this._textLines[a]),"</tspan>\n")},_setSVGTextLineJustifed:function(a,e,h,f){var g=b.util.createCanvasElement().getContext("2d");this._setTextStyles(g);var k=this._textLines[a].split(/\s+/),m=this._getWidthOfWords(g,k.join("")),m=this.width-m,n=k.length-1,m=0<n?m/n:0,p=this._getFillAttributes(this.fill),q;f+=this._getLineLeftOffset(this._getLineWidth(g, +a));a=0;for(q=k.length;a<q;a++)n=k[a],e.push('\t\t\t<tspan x="',d(f,c),'" ','y="',d(h,c),'" ',p,">",b.util.string.escapeXml(n),"</tspan>\n"),f+=this._getWidthOfWords(g,n)+m},_setSVGTextLineBg:function(a,b,e,f,l){a.push("\t\t<rect ",this._getFillAttributes(this.textBackgroundColor),' x="',d(e+this._getLineLeftOffset(this._getLineWidth(this.ctx,b)),c),'" y="',d(l-this.height/2,c),'" width="',d(this._getLineWidth(this.ctx,b),c),'" height="',d(this._getHeightOfLine(this.ctx,b)/this.lineHeight,c),'"></rect>\n')}, +_setSVGBg:function(a){this.backgroundColor&&a.push("\t\t<rect ",this._getFillAttributes(this.backgroundColor),' x="',d(-this.width/2,c),'" y="',d(-this.height/2,c),'" width="',d(this.width,c),'" height="',d(this.height,c),'"></rect>\n')},_getFillAttributes:function(a){var c=a&&"string"===typeof a?new b.Color(a):"";return c&&c.getSource()&&1!==c.getAlpha()?'opacity="'+c.getAlpha()+'" fill="'+c.setAlpha(1).toRgb()+'"':'fill="'+a+'"'},_set:function(a,b){this.callSuper("_set",a,b);-1<this._dimensionAffectingProps.indexOf(a)&& +(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),b.Text.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat("x y dx dy font-family font-style font-weight font-size text-decoration text-anchor".split(" ")),b.Text.DEFAULT_SVG_FONT_SIZE=16,b.Text.fromElement=function(a,c){if(!a)return null;var d=b.parseAttributes(a,b.Text.ATTRIBUTE_NAMES);c=b.util.object.extend(c?b.util.object.clone(c):{},d);c.top=c.top||0;c.left=c.left||0;"dx"in d&&(c.left+=d.dx);"dy"in d&&(c.top+=d.dy);"fontSize"in +c||(c.fontSize=b.Text.DEFAULT_SVG_FONT_SIZE);c.originX||(c.originX="left");d="";"textContent"in a?d=a.textContent:"firstChild"in a&&null!==a.firstChild&&"data"in a.firstChild&&null!==a.firstChild.data&&(d=a.firstChild.data);var d=d.replace(/^\s+|\s+$|\n+/g,"").replace(/\s+/g," "),d=new b.Text(d,c),e=d.getHeight()/d.height,e=((d.height+d.strokeWidth)*d.lineHeight-d.height)*e,e=d.getHeight()+e,g=0;"left"===d.originX&&(g=d.getWidth()/2);"right"===d.originX&&(g=-d.getWidth()/2);d.set({left:d.getLeft()+ +g,top:d.getTop()-e/2+d.fontSize*(.18+d._fontSizeFraction)/d.lineHeight});return d},b.Text.fromObject=function(a,c,d){return b.Object._fromObject("Text",a,c,d,"text")},b.util.createAccessors(b.Text))})("undefined"!==typeof exports?exports:this); +(function(){var e=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(b,d){this.styles= +d?d.styles||{}:{};this.callSuper("initialize",b,d);this.initBehavior()},_clearCache:function(){this.callSuper("_clearCache");this.__widthOfSpace=[]},isEmptyStyles:function(){if(!this.styles)return!0;var b=this.styles,d;for(d in b)for(var c in b[d])for(var a in b[d][c])return!1;return!0},setSelectionStart:function(b){b=Math.max(b,0);this._updateAndFire("selectionStart",b)},setSelectionEnd:function(b){b=Math.min(b,this.text.length);this._updateAndFire("selectionEnd",b)},_updateAndFire:function(b,d){this[b]!== +d&&(this._fireSelectionChanged(),this[b]=d);this._updateTextarea()},_fireSelectionChanged:function(){this.fire("selection:changed");this.canvas&&this.canvas.fire("text:selection:changed",{target:this})},getSelectionStyles:function(b,d){if(2===arguments.length){for(var c=[],a=b;a<d;a++)c.push(this.getSelectionStyles(a));return c}c=this.get2DCursorLocation(b);return this._getStyleDeclaration(c.lineIndex,c.charIndex)||{}},setSelectionStyles:function(b){if(this.selectionStart===this.selectionEnd)this._extendStyles(this.selectionStart, +b);else for(var d=this.selectionStart;d<this.selectionEnd;d++)this._extendStyles(d,b);this._forceClearCache=!0;return this},_extendStyles:function(b,d){var c=this.get2DCursorLocation(b);this._getLineStyle(c.lineIndex)||this._setLineStyle(c.lineIndex,{});this._getStyleDeclaration(c.lineIndex,c.charIndex)||this._setStyleDeclaration(c.lineIndex,c.charIndex,{});fabric.util.object.extend(this._getStyleDeclaration(c.lineIndex,c.charIndex),d)},_initDimensions:function(b){b||this.clearContextTop();this.callSuper("_initDimensions", +b)},render:function(b,d){this.clearContextTop();this.callSuper("render",b,d);this.cursorOffsetCache={};this.renderCursorOrSelection()},_render:function(b){this.callSuper("_render",b);this.ctx=b},clearContextTop:function(){if(this.active&&this.isEditing&&this.canvas&&this.canvas.contextTop){var b=this.canvas.contextTop;b.save();b.transform.apply(b,this.canvas.viewportTransform);this.transform(b);this.transformMatrix&&b.transform.apply(b,this.transformMatrix);this._clearTextArea(b);b.restore()}},renderCursorOrSelection:function(){if(this.active&& +this.isEditing){var b=this.text.split(""),d,c;this.canvas&&this.canvas.contextTop?(c=this.canvas.contextTop,c.save(),c.transform.apply(c,this.canvas.viewportTransform),this.transform(c),this.transformMatrix&&c.transform.apply(c,this.transformMatrix),this._clearTextArea(c)):(c=this.ctx,c.save());this.selectionStart===this.selectionEnd?(d=this._getCursorBoundaries(b,"cursor"),this.renderCursor(d,c)):(d=this._getCursorBoundaries(b,"selection"),this.renderSelection(b,d,c));c.restore()}},_clearTextArea:function(b){var d= +this.width+4,c=this.height+4;b.clearRect(-d/2,-c/2,d,c)},get2DCursorLocation:function(b){"undefined"===typeof b&&(b=this.selectionStart);for(var d=this._textLines.length,c=0;c<d;c++){if(b<=this._textLines[c].length)return{lineIndex:c,charIndex:b};b-=this._textLines[c].length+1}return{lineIndex:c-1,charIndex:this._textLines[c-1].length<b?this._textLines[c-1].length:b}},getCurrentCharStyle:function(b,d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return{fontSize:c&&c.fontSize||this.fontSize,fill:c&& +c.fill||this.fill,textBackgroundColor:c&&c.textBackgroundColor||this.textBackgroundColor,textDecoration:c&&c.textDecoration||this.textDecoration,fontFamily:c&&c.fontFamily||this.fontFamily,fontWeight:c&&c.fontWeight||this.fontWeight,fontStyle:c&&c.fontStyle||this.fontStyle,stroke:c&&c.stroke||this.stroke,strokeWidth:c&&c.strokeWidth||this.strokeWidth}},getCurrentCharFontSize:function(b,d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return c&&c.fontSize?c.fontSize:this.fontSize},getCurrentCharColor:function(b, +d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return c&&c.fill?c.fill:this.cursorColor},_getCursorBoundaries:function(b,d){var c=Math.round(this._getLeftOffset()),a=this._getTopOffset(),e=this._getCursorBoundariesOffsets(b,d);return{left:c,top:a,leftOffset:e.left+e.lineLeft,topOffset:e.top}},_getCursorBoundariesOffsets:function(b,d){if(this.cursorOffsetCache&&"top"in this.cursorOffsetCache)return this.cursorOffsetCache;for(var c=0,a=0,e=0,h=0,f=0,l=0;l<this.selectionStart;l++)"\n"===b[l]?(f=0, +h+=this._getHeightOfLine(this.ctx,a),a++,e=0):(f+=this._getWidthOfChar(this.ctx,b[l],a,e),e++),c=this._getLineLeftOffset(this._getLineWidth(this.ctx,a));"cursor"===d&&(h+=(1-this._fontSizeFraction)*this._getHeightOfLine(this.ctx,a)/this.lineHeight-this.getCurrentCharFontSize(a,e)*(1-this._fontSizeFraction));0!==this.charSpacing&&e===this._textLines[a].length&&(f-=this._getWidthOfCharSpacing());return this.cursorOffsetCache={top:h,left:0<f?f:0,lineLeft:c}},renderCursor:function(b,d){var c=this.get2DCursorLocation(), +a=c.lineIndex,c=c.charIndex,e=this.getCurrentCharFontSize(a,c),h=b.leftOffset,f=this.scaleX*this.canvas.getZoom(),f=this.cursorWidth/f;d.fillStyle=this.getCurrentCharColor(a,c);d.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity;d.fillRect(b.left+h-f/2,b.top+b.topOffset,f,e)},renderSelection:function(b,d,c){c.fillStyle=this.selectionColor;b=this.get2DCursorLocation(this.selectionStart);for(var a=this.get2DCursorLocation(this.selectionEnd),e=b.lineIndex,h=a.lineIndex,f=e;f<=h;f++){var l= +this._getLineLeftOffset(this._getLineWidth(c,f))||0,k=this._getHeightOfLine(this.ctx,f),m,n=0;m=this._textLines[f];if(f===e){for(var p=0,q=m.length;p<q;p++)p>=b.charIndex&&(f!==h||p<a.charIndex)&&(n+=this._getWidthOfChar(c,m[p],f,p)),p<b.charIndex&&(l+=this._getWidthOfChar(c,m[p],f,p));p===m.length&&(n-=this._getWidthOfCharSpacing())}else if(f>e&&f<h)n+=this._getLineWidth(c,f)||5;else if(f===h){p=0;for(q=a.charIndex;p<q;p++)n+=this._getWidthOfChar(c,m[p],f,p);a.charIndex===m.length&&(n-=this._getWidthOfCharSpacing())}m= +k;if(1>this.lineHeight||f===h&&1<this.lineHeight)k/=this.lineHeight;c.fillRect(d.left+l,d.top+d.topOffset,0<n?n:0,k);d.topOffset+=m}},_renderChars:function(b,d,c,a,e,h,f){if(this.isEmptyStyles())return this._renderCharsFast(b,d,c,a,e);f=f||0;var g=this._getHeightOfLine(d,h),k,m,n="";d.save();e-=g/this.lineHeight*this._fontSizeFraction;for(var p=f,q=c.length+f;p<=q;p++){k=k||this.getCurrentCharStyle(h,p);m=this.getCurrentCharStyle(h,p+1);if(this._hasStyleChanged(k,m)||p===q)this._renderChar(b,d,h, +p-1,n,a,e,g),n="",k=m;n+=c[p-f]}d.restore()},_renderCharsFast:function(b,d,c,a,e){"fillText"===b&&this.fill&&this.callSuper("_renderChars",b,d,c,a,e);"strokeText"===b&&(this.stroke&&0<this.strokeWidth||this.skipFillStrokeCheck)&&this.callSuper("_renderChars",b,d,c,a,e)},_renderChar:function(b,d,c,a,e,h,f,l){var g,m,n,p=this._getStyleDeclaration(c,a),q,t;p?(g=this._getHeightOfChar(d,e,c,a),n=p.stroke,m=p.fill,q=p.textDecoration):g=this.fontSize;n=(n||this.stroke)&&"strokeText"===b;m=(m||this.fill)&& +"fillText"===b;p&&d.save();b=this._applyCharStylesGetWidth(d,e,c,a,p||null);q=q||this.textDecoration;p&&p.textBackgroundColor&&this._removeShadow(d);if(0!==this.charSpacing){c=this._getWidthOfCharSpacing();e=e.split("");a=b=0;for(var r=e.length;a<r;a++)t=e[a],m&&d.fillText(t,h+b,f),n&&d.strokeText(t,h+b,f),t=d.measureText(t).width+c,b+=0<t?t:0}else m&&d.fillText(e,h,f),n&&d.strokeText(e,h,f);if(q||""!==q)l=this._fontSizeFraction*l/this.lineHeight,this._renderCharDecoration(d,q,h,f,l,b,g);p&&d.restore(); +d.translate(b,0)},_hasStyleChanged:function(b,d){return b.fill!==d.fill||b.fontSize!==d.fontSize||b.textBackgroundColor!==d.textBackgroundColor||b.textDecoration!==d.textDecoration||b.fontFamily!==d.fontFamily||b.fontWeight!==d.fontWeight||b.fontStyle!==d.fontStyle||b.stroke!==d.stroke||b.strokeWidth!==d.strokeWidth},_renderCharDecoration:function(b,d,c,a,e,h,f){if(d){e=f/15;a={underline:a+f/10,"line-through":a-f*(this._fontSizeFraction+this._fontSizeMult-1)+e,overline:a-(this._fontSizeMult-this._fontSizeFraction)* +f};f=["underline","line-through","overline"];var g,k;for(g=0;g<f.length;g++)k=f[g],-1<d.indexOf(k)&&b.fillRect(c,a[k],h,e)}},_renderTextLine:function(b,d,c,a,e,h){this.isEmptyStyles()||(e+=this.fontSize*(this._fontSizeFraction+.03));this.callSuper("_renderTextLine",b,d,c,a,e,h)},_renderTextDecoration:function(b){if(this.isEmptyStyles())return this.callSuper("_renderTextDecoration",b)},_renderTextLinesBackground:function(b){this.callSuper("_renderTextLinesBackground",b);var d=0,c,a,e=this._getLeftOffset(), +h=this._getTopOffset(),f="",l,k,m,n,p,q,t;b.save();for(var r=0,v=this._textLines.length;r<v;r++){c=this._getHeightOfLine(b,r);l=this._textLines[r];if(""!==l&&this.styles&&this._getLineStyle(r)){a=this._getLineWidth(b,r);a=this._getLineLeftOffset(a);for(var A=n=p=q=t=0,w=l.length;A<w;A++)m=this._getStyleDeclaration(r,A)||{},f!==m.textBackgroundColor&&(t&&q&&(b.fillStyle=f,b.fillRect(n,p,q,t)),n=p=q=t=0,f=m.textBackgroundColor||""),m.textBackgroundColor?(k=l[A],f===m.textBackgroundColor&&(f=m.textBackgroundColor, +n||(n=e+a+this._getWidthOfCharsAt(b,r,A)),p=h+d,q+=this._getWidthOfChar(b,k,r,A),t=c/this.lineHeight)):f="";t&&q&&(b.fillStyle=f,b.fillRect(n,p,q,t))}d+=c}b.restore()},_getCacheProp:function(b,d){return b+d.fontSize+d.fontWeight+d.fontStyle},_getFontCache:function(b){fabric.charWidthsCache[b]||(fabric.charWidthsCache[b]={});return fabric.charWidthsCache[b]},_applyCharStylesGetWidth:function(b,d,c,a,g){var h=g||this._getStyleDeclaration(c,a);g=e(h);this._applyFontStyles(g);a=this._getFontCache(g.fontFamily); +c=this._getCacheProp(d,g);if(!h&&a[c]&&this.caching)return a[c];"string"===typeof g.shadow&&(g.shadow=new fabric.Shadow(g.shadow));h=g.fill||this.fill;b.fillStyle=h.toLive?h.toLive(b,this):h;g.stroke&&(b.strokeStyle=g.stroke&&g.stroke.toLive?g.stroke.toLive(b,this):g.stroke);b.lineWidth=g.strokeWidth||this.strokeWidth;b.font=this._getFontDeclaration.call(g);g.shadow&&(g.scaleX=this.scaleX,g.scaleY=this.scaleY,g.canvas=this.canvas,g.getObjectScaling=this.getObjectScaling,this._setShadow.call(g,b)); +return this.caching&&a[c]?a[c]:(b=b.measureText(d).width,this.caching&&(a[c]=b),b)},_applyFontStyles:function(b){b.fontFamily||(b.fontFamily=this.fontFamily);b.fontSize||(b.fontSize=this.fontSize);b.fontWeight||(b.fontWeight=this.fontWeight);b.fontStyle||(b.fontStyle=this.fontStyle)},_getStyleDeclaration:function(b,d,c){return c?this.styles[b]&&this.styles[b][d]?e(this.styles[b][d]):{}:this.styles[b]&&this.styles[b][d]?this.styles[b][d]:null},_setStyleDeclaration:function(b,d,c){this.styles[b][d]= +c},_deleteStyleDeclaration:function(b,d){delete this.styles[b][d]},_getLineStyle:function(b){return this.styles[b]},_setLineStyle:function(b,d){this.styles[b]=d},_deleteLineStyle:function(b){delete this.styles[b]},_getWidthOfChar:function(b,d,c,a){if(!this._isMeasuring&&"justify"===this.textAlign&&this._reSpacesAndTabs.test(d))return this._getWidthOfSpace(b,c);b.save();d=this._applyCharStylesGetWidth(b,d,c,a);0!==this.charSpacing&&(d+=this._getWidthOfCharSpacing());b.restore();return 0<d?d:0},_getHeightOfChar:function(b, +d,c){return(b=this._getStyleDeclaration(d,c))&&b.fontSize?b.fontSize:this.fontSize},_getWidthOfCharsAt:function(b,d,c){var a=0,e,h;for(e=0;e<c;e++)h=this._textLines[d][e],a+=this._getWidthOfChar(b,h,d,e);return a},_measureLine:function(b,d){this._isMeasuring=!0;var c=this._getWidthOfCharsAt(b,d,this._textLines[d].length);0!==this.charSpacing&&(c-=this._getWidthOfCharSpacing());this._isMeasuring=!1;return 0<c?c:0},_getWidthOfSpace:function(b,d){if(this.__widthOfSpace[d])return this.__widthOfSpace[d]; +var c=this._textLines[d],a=this._getWidthOfWords(b,c,d,0),a=this.width-a,c=c.length-c.replace(this._reSpacesAndTabs,"").length,c=Math.max(a/c,b.measureText(" ").width);return this.__widthOfSpace[d]=c},_getWidthOfWords:function(b,d,c,a){for(var e=0,h=0;h<d.length;h++){var f=d[h];f.match(/\s/)||(e+=this._getWidthOfChar(b,f,c,h+a))}return e},_getHeightOfLine:function(b,d){if(this.__lineHeights[d])return this.__lineHeights[d];for(var c=this._textLines[d],a=this._getHeightOfChar(b,d,0),e=1,c=c.length;e< +c;e++){var h=this._getHeightOfChar(b,d,e);h>a&&(a=h)}this.__lineHeights[d]=a*this.lineHeight*this._fontSizeMult;return this.__lineHeights[d]},_getTextHeight:function(b){for(var d,c=0,a=0,e=this._textLines.length;a<e;a++)d=this._getHeightOfLine(b,a),c+=a===e-1?d/this.lineHeight:d;return c},toObject:function(b){return fabric.util.object.extend(this.callSuper("toObject",b),{styles:e(this.styles,!0)})}});fabric.IText.fromObject=function(b,d,c){return fabric.Object._fromObject("IText",b,d,c,"text")}})(); +(function(){var e=fabric.util.object.clone;fabric.util.object.extend(fabric.IText.prototype,{initBehavior:function(){this.initAddedHandler();this.initRemovedHandler();this.initCursorSelectionHandlers();this.initDoubleClickSimulation();this.mouseMoveHandler=this.mouseMoveHandler.bind(this)},onDeselect:function(){this.isEditing&&this.exitEditing();this.selected=!1;this.callSuper("onDeselect")},initAddedHandler:function(){var b=this;this.on("added",function(){var d=b.canvas;d&&(d._hasITextHandlers|| +(d._hasITextHandlers=!0,b._initCanvasHandlers(d)),d._iTextInstances=d._iTextInstances||[],d._iTextInstances.push(b))})},initRemovedHandler:function(){var b=this;this.on("removed",function(){var d=b.canvas;d&&(d._iTextInstances=d._iTextInstances||[],fabric.util.removeFromArray(d._iTextInstances,b),0===d._iTextInstances.length&&(d._hasITextHandlers=!1,b._removeCanvasHandlers(d)))})},_initCanvasHandlers:function(b){b._mouseUpITextHandler=function(){b._iTextInstances&&b._iTextInstances.forEach(function(b){b.__isMousedown= +!1})}.bind(this);b.on("mouse:up",b._mouseUpITextHandler)},_removeCanvasHandlers:function(b){b.off("mouse:up",b._mouseUpITextHandler)},_tick:function(){this._currentTickState=this._animateCursor(this,1,this.cursorDuration,"_onTickComplete")},_animateCursor:function(b,d,c,a){var e;e={isAborted:!1,abort:function(){this.isAborted=!0}};b.animate("_currentCursorOpacity",d,{duration:c,onComplete:function(){if(!e.isAborted)b[a]()},onChange:function(){b.canvas&&b.selectionStart===b.selectionEnd&&b.renderCursorOrSelection()}, +abort:function(){return e.isAborted}});return e},_onTickComplete:function(){var b=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1);this._cursorTimeout1=setTimeout(function(){b._currentTickCompleteState=b._animateCursor(b,0,this.cursorDuration/2,"_tick")},100)},initDelayedCursor:function(b){var d=this;b=b?0:this.cursorDelay;this.abortCursorAnimation();this._currentCursorOpacity=1;this._cursorTimeout2=setTimeout(function(){d._tick()},b)},abortCursorAnimation:function(){var b=this._currentTickState|| +this._currentTickCompleteState;this._currentTickState&&this._currentTickState.abort();this._currentTickCompleteState&&this._currentTickCompleteState.abort();clearTimeout(this._cursorTimeout1);clearTimeout(this._cursorTimeout2);this._currentCursorOpacity=0;b&&this.canvas&&this.canvas.clearContext(this.canvas.contextTop||this.ctx)},selectAll:function(){this.selectionStart=0;this.selectionEnd=this.text.length;this._fireSelectionChanged();this._updateTextarea()},getSelectedText:function(){return this.text.slice(this.selectionStart, +this.selectionEnd)},findWordBoundaryLeft:function(b){var d=0,c=b-1;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)d++,c--;for(;/\S/.test(this.text.charAt(c))&&-1<c;)d++,c--;return b-d},findWordBoundaryRight:function(b){var d=0,c=b;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)d++,c++;for(;/\S/.test(this.text.charAt(c))&&c<this.text.length;)d++,c++;return b+d},findLineBoundaryLeft:function(b){for(var d=0,c=b-1;!/\n/.test(this.text.charAt(c))&& +-1<c;)d++,c--;return b-d},findLineBoundaryRight:function(b){for(var d=0,c=b;!/\n/.test(this.text.charAt(c))&&c<this.text.length;)d++,c++;return b+d},getNumNewLinesInSelectedText:function(){for(var b=this.getSelectedText(),d=0,c=0,a=b.length;c<a;c++)"\n"===b[c]&&d++;return d},searchWordBoundary:function(b,d){for(var c=this._reSpace.test(this.text.charAt(b))?b-1:b,a=this.text.charAt(c),e=/[ \n\.,;!\?\-]/;!e.test(a)&&0<c&&c<this.text.length;)c+=d,a=this.text.charAt(c);e.test(a)&&"\n"!==a&&(c+=1===d? +0:1);return c},selectWord:function(b){b=b||this.selectionStart;var d=this.searchWordBoundary(b,-1);b=this.searchWordBoundary(b,1);this.selectionStart=d;this.selectionEnd=b;this._fireSelectionChanged();this._updateTextarea();this.renderCursorOrSelection()},selectLine:function(b){b=b||this.selectionStart;var d=this.findLineBoundaryLeft(b);b=this.findLineBoundaryRight(b);this.selectionStart=d;this.selectionEnd=b;this._fireSelectionChanged();this._updateTextarea()},enterEditing:function(b){if(!this.isEditing&& +this.editable){this.canvas&&this.exitEditingOnOthers(this.canvas);this.selected=this.isEditing=!0;this.initHiddenTextarea(b);this.hiddenTextarea.focus();this._updateTextarea();this._saveEditingProps();this._setEditingProps();this._textBeforeEdit=this.text;this._tick();this.fire("editing:entered");this._fireSelectionChanged();if(!this.canvas)return this;this.canvas.fire("text:editing:entered",{target:this});this.initMouseMoveHandler();this.canvas.renderAll();return this}},exitEditingOnOthers:function(b){b._iTextInstances&& +b._iTextInstances.forEach(function(b){b.selected=!1;b.isEditing&&b.exitEditing()})},initMouseMoveHandler:function(){this.canvas.on("mouse:move",this.mouseMoveHandler)},mouseMoveHandler:function(b){if(this.__isMousedown&&this.isEditing){b=this.getSelectionStartFromPointer(b.e);var d=this.selectionStart,c=this.selectionEnd;if(b===this.__selectionStartOnMouseDown&&d!==c||d!==b&&c!==b)if(b>this.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=b):(this.selectionStart= +b,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart!==d||this.selectionEnd!==c)this.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()}},_setEditingProps:function(){this.hoverCursor="text";this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text");this.borderColor=this.editingBorderColor;this.hasControls=this.selectable=!1;this.lockMovementX=this.lockMovementY=!0},_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 b=this._calcTextareaPosition();this.hiddenTextarea.style.left=b.left;this.hiddenTextarea.style.top=b.top;this.hiddenTextarea.style.fontSize=b.fontSize}},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var b=this.text.split(""),d=this._getCursorBoundaries(b, +"cursor"),b=this.get2DCursorLocation(),b=this.getCurrentCharFontSize(b.lineIndex,b.charIndex),c=d.leftOffset,a=this.calcTransformMatrix(),d={x:d.left+c,y:d.top+d.topOffset+b},e=this.canvas.upperCanvasEl,c=e.width-b,e=e.height-b,d=fabric.util.transformPoint(d,a),d=fabric.util.transformPoint(d,this.canvas.viewportTransform);0>d.x&&(d.x=0);d.x>c&&(d.x=c);0>d.y&&(d.y=0);d.y>e&&(d.y=e);d.x+=this.canvas._offset.left;d.y+=this.canvas._offset.top;return{left:d.x+"px",top:d.y+"px",fontSize:b}},_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 b=this._textBeforeEdit!==this.text;this.isEditing=this.selected=!1;this.selectable=!0;this.selectionEnd=this.selectionStart;this.hiddenTextarea&&(this.hiddenTextarea.blur&&this.hiddenTextarea.blur(),this.canvas&&this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea),this.hiddenTextarea=null);this.abortCursorAnimation(); +this._restoreEditingProps();this._currentCursorOpacity=0;this.fire("editing:exited");b&&this.fire("modified");this.canvas&&(this.canvas.off("mouse:move",this.mouseMoveHandler),this.canvas.fire("text:editing:exited",{target:this}),b&&this.canvas.fire("object:modified",{target:this}));return this},_removeExtraneousStyles:function(){for(var b in this.styles)this._textLines[b]||delete this.styles[b]},_removeCharsFromTo:function(b,d){for(;d!==b;)this._removeSingleCharAndStyle(b+1),d--;this.selectionEnd= +this.selectionStart=b},_removeSingleCharAndStyle:function(b){var d="\n"===this.text[b-1];this.removeStyleObject(d,d?b:b-1);this.text=this.text.slice(0,b-1)+this.text.slice(b);this._textLines=this._splitTextIntoLines()},insertChars:function(b,d){var c;1<this.selectionEnd-this.selectionStart&&this._removeCharsFromTo(this.selectionStart,this.selectionEnd);if(!d&&this.isEmptyStyles())this.insertChar(b,!1);else for(var a=0,e=b.length;a<e;a++)d&&(c=fabric.util.object.clone(fabric.copiedTextStyle[a],!0)), +this.insertChar(b[a],a<e-1,c)},insertChar:function(b,d,c){var a="\n"===this.text[this.selectionStart];this.text=this.text.slice(0,this.selectionStart)+b+this.text.slice(this.selectionEnd);this._textLines=this._splitTextIntoLines();this.insertStyleObjects(b,a,c);this.selectionEnd=this.selectionStart+=b.length;d||(this._updateTextarea(),this.setCoords(),this._fireSelectionChanged(),this.fire("changed"),this.restartCursorIfNeeded(),this.canvas&&(this.canvas.fire("text:changed",{target:this}),this.canvas.renderAll()))}, +restartCursorIfNeeded:function(){this._currentTickState&&!this._currentTickState.isAborted&&this._currentTickCompleteState&&!this._currentTickCompleteState.isAborted||this.initDelayedCursor()},insertNewlineStyleObject:function(b,d,c){this.shiftLineStyles(b,1);var a={},g={};this.styles[b]&&this.styles[b][d-1]&&(a=this.styles[b][d-1]);if(c&&a)g[0]=e(a),this.styles[b+1]=g;else{c=!1;for(var h in this.styles[b])a=parseInt(h,10),a>=d&&(c=!0,g[a-d]=this.styles[b][h],delete this.styles[b][h]);c&&(this.styles[b+ +1]=g)}this._forceClearCache=!0},insertCharStyleObject:function(b,d,c){var a=this.styles[b],g=e(a);0!==d||c||(d=1);for(var h in g){var f=parseInt(h,10);f>=d&&(a[f+1]=g[f],g[f-1]||delete a[f])}(c=c||e(a[d-1]))&&(this.styles[b][d]=c);this._forceClearCache=!0},insertStyleObjects:function(b,d,c){var a=this.get2DCursorLocation(),e=a.lineIndex,a=a.charIndex;this._getLineStyle(e)||this._setLineStyle(e,{});"\n"===b?this.insertNewlineStyleObject(e,a,d):this.insertCharStyleObject(e,a,c)},shiftLineStyles:function(b, +d){var c=e(this.styles),a;for(a in c){var g=parseInt(a,10);g<=b&&delete c[g]}for(a in this.styles)g=parseInt(a,10),g>b&&(this.styles[g+d]=c[g],c[g-d]||delete this.styles[g])},removeStyleObject:function(b,d){var c=this.get2DCursorLocation(d);this._removeStyleObject(b,c,c.lineIndex,c.charIndex)},_getTextOnPreviousLine:function(b){return this._textLines[b-1]},_removeStyleObject:function(b,d,c,a){if(b){var g=this._getTextOnPreviousLine(d.lineIndex),g=g?g.length:0;this.styles[c-1]||(this.styles[c-1]={}); +for(a in this.styles[c])this.styles[c-1][parseInt(a,10)+g]=this.styles[c][a];this.shiftLineStyles(d.lineIndex,-1)}else for(g in(d=this.styles[c])&&delete d[a],c=e(d),c)b=parseInt(g,10),b>=a&&0!==b&&(d[b-1]=c[b],delete d[b])},insertNewline:function(){this.insertChars("\n")},setSelectionStartEndWithShift:function(b,d,c){c<=b?(d===b?this._selectionDirection="left":"right"===this._selectionDirection&&(this._selectionDirection="left",this.selectionEnd=b),this.selectionStart=c):c>b&&c<d?"right"===this._selectionDirection? +this.selectionEnd=c:this.selectionStart=c:(d===b?this._selectionDirection="right":"left"===this._selectionDirection&&(this._selectionDirection="right",this.selectionStart=d),this.selectionEnd=c)},setSelectionInBoundaries:function(){var b=this.text.length;this.selectionStart>b?this.selectionStart=b:0>this.selectionStart&&(this.selectionStart=0);this.selectionEnd>b?this.selectionEnd=b:0>this.selectionEnd&&(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(e){this.__newClickTime=+new Date;var b=this.canvas.getPointer(e.e);this.isTripleClick(b,e.e)?(this.fire("tripleclick",e),this._stopEvent(e.e)):this.isDoubleClick(b)&&(this.fire("dblclick",e),this._stopEvent(e.e));this.__lastLastClickTime=this.__lastClickTime; +this.__lastClickTime=this.__newClickTime;this.__lastPointer=b;this.__lastIsEditing=this.isEditing;this.__lastSelected=this.selected},isDoubleClick:function(e){return 500>this.__newClickTime-this.__lastClickTime&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y&&this.__lastIsEditing},isTripleClick:function(e){return 500>this.__newClickTime-this.__lastClickTime&&500>this.__lastClickTime-this.__lastLastClickTime&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y},_stopEvent:function(e){e.preventDefault&& +e.preventDefault();e.stopPropagation&&e.stopPropagation()},initCursorSelectionHandlers:function(){this.initMousedownHandler();this.initMouseupHandler();this.initClicks()},initClicks:function(){this.on("dblclick",function(e){this.selectWord(this.getSelectionStartFromPointer(e.e))});this.on("tripleclick",function(e){this.selectLine(this.getSelectionStartFromPointer(e.e))})},initMousedownHandler:function(){this.on("mousedown",function(e){if(this.editable&&(!e.e.button||1===e.e.button)){var b=this.canvas.getPointer(e.e); +this.__mousedownX=b.x;this.__mousedownY=b.y;this.__isMousedown=!0;this.selected&&this.setCursorByClick(e.e);this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection())}})},_isObjectMoved:function(e){e=this.canvas.getPointer(e);return this.__mousedownX!==e.x||this.__mousedownY!==e.y},initMouseupHandler:function(){this.on("mouseup",function(e){this.__isMousedown=!1;!this.editable||this._isObjectMoved(e.e)|| +e.e.button&&1!==e.e.button||(this.__lastSelected&&!this.__corner&&(this.enterEditing(e.e),this.selectionStart===this.selectionEnd?this.initDelayedCursor(!0):this.renderCursorOrSelection()),this.selected=!0)})},setCursorByClick:function(e){var b=this.getSelectionStartFromPointer(e),d=this.selectionStart,c=this.selectionEnd;e.shiftKey?this.setSelectionStartEndWithShift(d,c,b):this.selectionEnd=this.selectionStart=b;this.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(e){e= +this.getLocalPointer(e);for(var b=0,d,c=0,a=0,g,h=0,f=this._textLines.length;h<f;h++){g=this._textLines[h];c+=this._getHeightOfLine(this.ctx,h)*this.scaleY;d=this._getLineWidth(this.ctx,h);d=this._getLineLeftOffset(d)*this.scaleX;for(var l=0,k=g.length;l<k;l++)if(b=d,d+=this._getWidthOfChar(this.ctx,g[l],h,this.flipX?k-l:l)*this.scaleX,c<=e.y||d<=e.x)a++;else return this._getNewSelectionStartFromOffset(e,b,d,a+h,k);if(e.y<c)return this._getNewSelectionStartFromOffset(e,b,d,a+h-1,k)}return this.text.length}, +_getNewSelectionStartFromOffset:function(e,b,d,c,a){e=c+(d-e.x>e.x-b?0:1);this.flipX&&(e=a-e);e>this.text.length&&(e=this.text.length);return e}}); +fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea");this.hiddenTextarea.setAttribute("autocapitalize","off");this.hiddenTextarea.setAttribute("autocorrect","off");this.hiddenTextarea.setAttribute("autocomplete","off");this.hiddenTextarea.setAttribute("spellcheck","false");this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea","");this.hiddenTextarea.setAttribute("wrap","off");var e=this._calcTextareaPosition(); +this.hiddenTextarea.style.cssText="position: absolute; top: "+e.top+"; left: "+e.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; line-height: 1px; padding\uff70top: "+e.fontSize+";";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(e){if(this.isEditing){if(e.keyCode in this.keysMap)this[this.keysMap[e.keyCode]](e);else if(e.keyCode in this.ctrlKeysMapDown&&(e.ctrlKey||e.metaKey))this[this.ctrlKeysMapDown[e.keyCode]](e);else return;e.stopImmediatePropagation();e.preventDefault();33<=e.keyCode&&40>=e.keyCode?(this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.renderAll()}},onKeyUp:function(e){!this.isEditing||this._copyDone?this._copyDone=!1:e.keyCode in this.ctrlKeysMapUp&&(e.ctrlKey|| +e.metaKey)&&(this[this.ctrlKeysMapUp[e.keyCode]](e),e.stopImmediatePropagation(),e.preventDefault(),this.canvas&&this.canvas.renderAll())},onInput:function(e){if(this.isEditing&&!this.inCompositionMode){var b=this.selectionStart||0,d=this.selectionEnd||0,c=this.text.length,a=this.hiddenTextarea.value.length;a>c?(b="left"===this._selectionDirection?d:b,c=this.hiddenTextarea.value.slice(b,b+(a-c))):c=this.hiddenTextarea.value.slice(b,b+(a-c+d-b));this.insertChars(c);e.stopPropagation()}},onCompositionStart:function(){this.inCompositionMode= +!0;this.prevCompositionLength=0;this.compositionStart=this.selectionStart},onCompositionEnd:function(){this.inCompositionMode=!1},onCompositionUpdate:function(e){e=e.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(e){if(this.selectionStart===this.selectionEnd){if(this.selectionStart===this.text.length)return; +this.moveCursorRight(e)}this.removeChars(e)},copy:function(e){if(this.selectionStart!==this.selectionEnd){var b=this.getSelectedText(),d=this._getClipboardData(e);d&&d.setData("text",b);fabric.copiedText=b;fabric.copiedTextStyle=this.getSelectionStyles(this.selectionStart,this.selectionEnd);e.stopImmediatePropagation();e.preventDefault();this._copyDone=!0}},paste:function(e){var b;b=this._getClipboardData(e);var d=!0;b?(b=b.getData("text").replace(/\r/g,""),fabric.copiedTextStyle&&fabric.copiedText=== +b||(d=!1)):b=fabric.copiedText;b&&this.insertChars(b,d);e.stopImmediatePropagation();e.preventDefault()},cut:function(e){this.selectionStart!==this.selectionEnd&&(this.copy(e),this.removeChars(e))},_getClipboardData:function(e){return e&&e.clipboardData||fabric.window.clipboardData},_getWidthBeforeCursor:function(e,b){for(var d=this._textLines[e].slice(0,b),c=this._getLineWidth(this.ctx,e),c=this._getLineLeftOffset(c),a,g=0,h=d.length;g<h;g++)a=d[g],c+=this._getWidthOfChar(this.ctx,a,e,g);return c}, +getDownCursorOffset:function(e,b){var d=this._getSelectionForOffset(e,b),c=this.get2DCursorLocation(d),a=c.lineIndex;if(a===this._textLines.length-1||e.metaKey||34===e.keyCode)return this.text.length-d;d=c.charIndex;c=this._getWidthBeforeCursor(a,d);c=this._getIndexOnLine(a+1,c);return this._textLines[a].slice(d).length+c+2},_getSelectionForOffset:function(e,b){return e.shiftKey&&this.selectionStart!==this.selectionEnd&&b?this.selectionEnd:this.selectionStart},getUpCursorOffset:function(e,b){var d= +this._getSelectionForOffset(e,b),c=this.get2DCursorLocation(d),a=c.lineIndex;if(0===a||e.metaKey||33===e.keyCode)return-d;d=c.charIndex;c=this._getWidthBeforeCursor(a,d);c=this._getIndexOnLine(a-1,c);d=this._textLines[a].slice(0,d);return-this._textLines[a-1].length+c-d.length},_getIndexOnLine:function(e,b){for(var d=this._getLineWidth(this.ctx,e),c=this._textLines[e],d=this._getLineLeftOffset(d),a=0,g,h=0,f=c.length;h<f;h++){var l=this._getWidthOfChar(this.ctx,c[h],e,h),d=d+l;if(d>b){g=!0;a=Math.abs(d- +b)<Math.abs(d-l-b)?h:h-1;break}}g||(a=c.length-1);return a},moveCursorDown:function(e){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorUpOrDown("Down",e)},moveCursorUp:function(e){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",e)},_moveCursorUpOrDown:function(e,b){var d=this["get"+e+"CursorOffset"](b,"right"===this._selectionDirection);b.shiftKey?this.moveCursorWithShift(d):this.moveCursorWithoutShift(d);0!==d&&(this.setSelectionInBoundaries(), +this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(e){this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,"left"===this._selectionDirection?this.selectionStart+e:this.selectionEnd+e);return 0!==e},moveCursorWithoutShift:function(e){0>e?this.selectionEnd=this.selectionStart+=e:this.selectionStart=this.selectionEnd+=e;return 0!==e},moveCursorLeft:function(e){0===this.selectionStart&& +0===this.selectionEnd||this._moveCursorLeftOrRight("Left",e)},_move:function(e,b,d){if(e.altKey)e=this["findWordBoundary"+d](this[b]);else if(e.metaKey||35===e.keyCode||36===e.keyCode)e=this["findLineBoundary"+d](this[b]);else return this[b]+="Left"===d?-1:1,!0;if(this[b]!==e)return this[b]=e,!0},_moveLeft:function(e,b){return this._move(e,b,"Left")},_moveRight:function(e,b){return this._move(e,b,"Right")},moveCursorLeftWithoutShift:function(e){var b=!0;this._selectionDirection="left";this.selectionEnd=== +this.selectionStart&&0!==this.selectionStart&&(b=this._moveLeft(e,"selectionStart"));this.selectionEnd=this.selectionStart;return b},moveCursorLeftWithShift:function(e){if("right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd)return this._moveLeft(e,"selectionEnd");if(0!==this.selectionStart)return this._selectionDirection="left",this._moveLeft(e,"selectionStart")},moveCursorRight:function(e){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorLeftOrRight("Right", +e)},_moveCursorLeftOrRight:function(e,b){var d="moveCursor"+e+"With";this._currentCursorOpacity=1;d=b.shiftKey?d+"Shift":d+"outShift";this[d](b)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(e){if("left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd)return this._moveRight(e,"selectionStart");if(this.selectionEnd!==this.text.length)return this._selectionDirection="right",this._moveRight(e, +"selectionEnd")},moveCursorRightWithoutShift:function(e){var b=!0;this._selectionDirection="right";this.selectionStart===this.selectionEnd?(b=this._moveRight(e,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd;return b},removeChars:function(e){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(e):this._removeCharsFromTo(this.selectionStart,this.selectionEnd);this.set("dirty",!0);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(e){0!==this.selectionStart&&(e.metaKey?(e=this.findLineBoundaryLeft(this.selectionStart),this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)):e.altKey?(e=this.findWordBoundaryLeft(this.selectionStart),this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)):(this._removeSingleCharAndStyle(this.selectionStart), +this.setSelectionStart(this.selectionStart-1)))}}); +(function(){var e=fabric.util.toFixed,b=fabric.Object.NUM_FRACTION_DIGITS;fabric.util.object.extend(fabric.IText.prototype,{_setSVGTextLineText:function(b,c,a,e,h,f){this._getLineStyle(b)?this._setSVGTextLineChars(b,c,a,e,f):fabric.Text.prototype._setSVGTextLineText.call(this,b,c,a,e,h)},_setSVGTextLineChars:function(b,c,a,e,h){a=this._textLines[b];e=0;for(var d=this._getLineLeftOffset(this._getLineWidth(this.ctx,b))-this.width/2,g=this._getSVGLineTopOffset(b),k=this._getHeightOfLine(this.ctx,b), +m=0,n=a.length;m<n;m++){var p=this._getStyleDeclaration(b,m)||{};c.push(this._createTextCharSpan(a[m],p,d,g.lineTop+g.offset,e));var q=this._getWidthOfChar(this.ctx,a[m],b,m);p.textBackgroundColor&&h.push(this._createTextCharBg(p,d,g.lineTop,k,q,e));e+=q}},_getSVGLineTopOffset:function(b){for(var c=0,a=0;a<b;a++)c+=this._getHeightOfLine(this.ctx,a);b=this._getHeightOfLine(this.ctx,a);return{lineTop:c,offset:(this._fontSizeMult-this._fontSizeFraction)*b/(this.lineHeight*this._fontSizeMult)}},_createTextCharBg:function(d, +c,a,g,h,f){return['\t\t<rect fill="',d.textBackgroundColor,'" x="',e(c+f,b),'" y="',e(a-this.height/2,b),'" width="',e(h,b),'" height="',e(g/this.lineHeight,b),'"></rect>\n'].join("")},_createTextCharSpan:function(d,c,a,g,h){var f=this.getSvgStyles.call(fabric.util.object.extend({visible:!0,fill:this.fill,stroke:this.stroke,type:"text",getSvgFilter:fabric.Object.prototype.getSvgFilter},c));return['\t\t\t<tspan x="',e(a+h,b),'" y="',e(g-this.height/2,b),'" ',c.fontFamily?'font-family="'+c.fontFamily.replace(/"/g, +"'")+'" ':"",c.fontSize?'font-size="'+c.fontSize+'" ':"",c.fontStyle?'font-style="'+c.fontStyle+'" ':"",c.fontWeight?'font-weight="'+c.fontWeight+'" ':"",c.textDecoration?'text-decoration="'+c.textDecoration+'" ':"",'style="',f,'">',fabric.util.string.escapeXml(d),"</tspan>\n"].join("")}})})(); +(function(e){var b=e.fabric||(e.fabric={});b.Textbox=b.util.createClass(b.IText,b.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:2,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,noScaleCache:!1,_dimensionAffectingProps:b.Text.prototype._dimensionAffectingProps.concat("width"),initialize:function(d,c){this.callSuper("initialize",d,c);this.setControlsVisibility(b.Textbox.getTextboxControlVisibility());this.ctx=this.objectCaching?this._cacheContext:b.util.createCanvasElement().getContext("2d")}, +_initDimensions:function(d){this.__skipDimension||(d||(d=b.util.createCanvasElement().getContext("2d"),this._setTextStyles(d),this.clearContextTop()),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(d),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(d),this.setCoords())},_generateStyleMap:function(){for(var b=0,c=0,a=0,e={},h=0;h<this._textLines.length;h++)"\n"===this.text[a]&&0<h?(c=0,a++,b++):" "===this.text[a]&& +0<h&&(c++,a++),e[h]={line:b,offset:c},a+=this._textLines[h].length,c+=this._textLines[h].length;return e},_getStyleDeclaration:function(b,c,a){if(this._styleMap){var d=this._styleMap[b];if(!d)return a?{}:null;b=d.line;c=d.offset+c}return this.callSuper("_getStyleDeclaration",b,c,a)},_setStyleDeclaration:function(b,c,a){var d=this._styleMap[b];b=d.line;c=d.offset+c;this.styles[b][c]=a},_deleteStyleDeclaration:function(b,c){var a=this._styleMap[b];b=a.line;c=a.offset+c;delete this.styles[b][c]},_getLineStyle:function(b){return this.styles[this._styleMap[b].line]}, +_setLineStyle:function(b,c){this.styles[this._styleMap[b].line]=c},_deleteLineStyle:function(b){delete this.styles[this._styleMap[b].line]},_wrapText:function(b,c){var a=c.split(this._reNewline),d=[],e;for(e=0;e<a.length;e++)d=d.concat(this._wrapLine(b,a[e],e));return d},_measureText:function(b,c,a,e){var d=0;e=e||0;for(var f=0,g=c.length;f<g;f++)d+=this._getWidthOfChar(b,c[f],a,f+e);return d},_wrapLine:function(b,c,a){var d=0,e=[],f="";c=c.split(" ");for(var l,k=0,m,n=0,p=0,q=!0,t=this._getWidthOfCharSpacing(), +r=0;r<c.length;r++)l=c[r],m=this._measureText(b,l,a,k),k+=l.length,d+=n+m-t,d>=this.width&&!q?(e.push(f),f="",d=m,q=!0):d+=t,q||(f+=" "),f+=l,n=this._measureText(b," ",a,k),k++,q=!1,m>p&&(p=m);r&&e.push(f);p>this.dynamicMinWidth&&(this.dynamicMinWidth=p-t);return e},_splitTextIntoLines:function(b){b=b||this.ctx;var c=this.textAlign;this._styleMap=null;b.save();this._setTextStyles(b);this.textAlign="left";var a=this._wrapText(b,this.text);this.textAlign=c;b.restore();this._textLines=a;this._styleMap= +this._generateStyleMap();return a},setOnGroup:function(b,c){"scaleX"===b&&(this.set("scaleX",Math.abs(1/c)),this.set("width",this.get("width")*c/("undefined"===typeof this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=c)},get2DCursorLocation:function(b){"undefined"===typeof b&&(b=this.selectionStart);for(var c=this._textLines.length,a=0,d=0;d<c;d++){var e=this._textLines[d].length;if(b<=a+e)return{lineIndex:d,charIndex:b-a};a+=e;"\n"!==this.text[a]&&" "!==this.text[a]||a++}return{lineIndex:c- +1,charIndex:this._textLines[c-1].length}},_getCursorBoundariesOffsets:function(b,c){for(var a=0,d=0,e=this.get2DCursorLocation(),f=this._textLines[e.lineIndex].split(""),l=this._getLineLeftOffset(this._getLineWidth(this.ctx,e.lineIndex)),k=0;k<e.charIndex;k++)d+=this._getWidthOfChar(this.ctx,f[k],e.lineIndex,k);for(k=0;k<e.lineIndex;k++)a+=this._getHeightOfLine(this.ctx,k);"cursor"===c&&(a+=(1-this._fontSizeFraction)*this._getHeightOfLine(this.ctx,e.lineIndex)/this.lineHeight-this.getCurrentCharFontSize(e.lineIndex, +e.charIndex)*(1-this._fontSizeFraction));return{top:a,left:d,lineLeft:l}},getMinWidth:function(){return Math.max(this.minWidth,this.dynamicMinWidth)},toObject:function(b){return this.callSuper("toObject",["minWidth"].concat(b))}});b.Textbox.fromObject=function(d,c,a){return b.Object._fromObject("Textbox",d,c,a,"text")};b.Textbox.getTextboxControlVisibility=function(){return{tl:!1,tr:!1,br:!1,bl:!1,ml:!0,mt:!1,mr:!0,mb:!1,mtr:!0}}})("undefined"!==typeof exports?exports:this); +(function(){var e=fabric.Canvas.prototype._setObjectScale;fabric.Canvas.prototype._setObjectScale=function(b,d,c,a,g,h,f){var l=d.target;if(l instanceof fabric.Textbox){if(b=b.x/d.scaleX/(l.width+l.strokeWidth)*l.width,b>=l.getMinWidth())return l.set("width",b),!0}else return e.call(fabric.Canvas.prototype,b,d,c,a,g,h,f)};fabric.Group.prototype._refreshControlsVisibility=function(){if("undefined"!==typeof fabric.Textbox)for(var b=this._objects.length;b--;)if(this._objects[b]instanceof fabric.Textbox){this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility()); +break}};fabric.util.object.extend(fabric.Textbox.prototype,{_removeExtraneousStyles:function(){for(var b in this._styleMap)this._textLines[b]||delete this.styles[this._styleMap[b].line]},insertCharStyleObject:function(b,d,c){var a=this._styleMap[b];b=a.line;d=a.offset+d;fabric.IText.prototype.insertCharStyleObject.apply(this,[b,d,c])},insertNewlineStyleObject:function(b,d,c){var a=this._styleMap[b];b=a.line;d=a.offset+d;fabric.IText.prototype.insertNewlineStyleObject.apply(this,[b,d,c])},shiftLineStyles:function(b, +d){b=this._styleMap[b].line;fabric.IText.prototype.shiftLineStyles.call(this,b,d)},_getTextOnPreviousLine:function(b){for(var d=this._textLines[b-1];this._styleMap[b-2]&&this._styleMap[b-2].line===this._styleMap[b-1].line;)d=this._textLines[b-2]+d,b--;return d},removeStyleObject:function(b,d){var c=this.get2DCursorLocation(d),a=this._styleMap[c.lineIndex];this._removeStyleObject(b,c,a.line,a.offset+c.charIndex)}})})(); +(function(){var e=fabric.IText.prototype._getNewSelectionStartFromOffset;fabric.IText.prototype._getNewSelectionStartFromOffset=function(b,d,c,a,g){a=e.call(this,b,d,c,a,g);for(c=d=b=0;c<this._textLines.length;c++){b+=this._textLines[c].length;if(b+d>=a)break;"\n"!==this.text[b+d]&&" "!==this.text[b+d]||d++}return a-c+d}})(); +(function(){function e(b,d,e){var f=c.parse(b);f.port||(f.port=0===f.protocol.indexOf("https:")?443:80);b=(0===f.protocol.indexOf("https:")?g:a).request({hostname:f.hostname,port:f.port,path:f.path,method:"GET"},function(a){var b="";d&&a.setEncoding(d);a.on("end",function(){e(b)});a.on("data",function(c){200===a.statusCode&&(b+=c)})});b.on("error",function(a){a.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+f.hostname+":"+f.port):fabric.log(a.message);e(null)});b.end()} +function b(a,b){require("fs").readFile(a,function(a,c){if(a)throw fabric.log(a),a;b(c)})}if("undefined"===typeof document||"undefined"===typeof window){var d=require("xmldom").DOMParser,c=require("url"),a=require("http"),g=require("https"),h=require("canvas"),f=require("canvas").Image;fabric.util.loadImage=function(a,c,d){function g(b){b?(h.src=new Buffer(b,"binary"),h._src=a,c&&c.call(d,h)):(h=null,c&&c.call(d,null,!0))}var h=new f;a&&(a instanceof Buffer||0===a.indexOf("data"))?(h.src=h._src=a, +c&&c.call(d,h)):a&&0!==a.indexOf("http")?b(a,g):a?e(a,"binary",g):c&&c.call(d,a)};fabric.loadSVGFromURL=function(a,c,d){a=a.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim();0!==a.indexOf("http")?b(a,function(a){fabric.loadSVGFromString(a.toString(),c,d)}):e(a,"",function(a){fabric.loadSVGFromString(a,c,d)})};fabric.loadSVGFromString=function(a,b,c){a=(new d).parseFromString(a);fabric.parseSVGDocument(a.documentElement,function(a,c){b&&b(a,c)},c)};fabric.util.getScript=function(a,b){e(a,"",function(a){eval(a); +b&&b()})};fabric.createCanvasForNode=function(a,b,c,d){d=d||c;var e=fabric.document.createElement("canvas"),f=new h(a||600,b||600,d);a=new h(a||600,b||600,d);e.style={};e.width=f.width;e.height=f.height;c=c||{};c.nodeCanvas=f;c.nodeCacheCanvas=a;c=new (fabric.Canvas||fabric.StaticCanvas)(e,c);c.nodeCanvas=f;c.nodeCacheCanvas=a;c.contextContainer=f.getContext("2d");c.contextCache=a.getContext("2d");c.Font=h.Font;return c};var l=fabric.StaticCanvas.prototype._initStatic;fabric.StaticCanvas.prototype._initStatic= +function(a,b){a=a||fabric.document.createElement("canvas");this.nodeCanvas=new h(a.width,a.height);this.nodeCacheCanvas=new h(a.width,a.height);l.call(this,a,b);this.contextContainer=this.nodeCanvas.getContext("2d");this.contextCache=this.nodeCacheCanvas.getContext("2d");this.Font=h.Font};fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()};fabric.StaticCanvas.prototype.createJPEGStream=function(a){return this.nodeCanvas.createJPEGStream(a)};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 k=fabric.StaticCanvas.prototype._setBackstoreDimension;fabric.StaticCanvas.prototype._setBackstoreDimension=function(a,b){k.call(this,a,b);this.nodeCanvas[a]=b;return this};fabric.Canvas&&(fabric.Canvas.prototype._setBackstoreDimension=fabric.StaticCanvas.prototype._setBackstoreDimension)}})(); diff --git a/js/fabric.js b/js/fabric.js deleted file mode 120000 index 4c944ad4..00000000 --- a/js/fabric.js +++ /dev/null @@ -1 +0,0 @@ -fabric-v1.7.22.js \ No newline at end of file diff --git a/js/fabric.js b/js/fabric.js new file mode 100644 index 00000000..1735ce79 --- /dev/null +++ b/js/fabric.js @@ -0,0 +1,27106 @@ +/* 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.7.22" }; +if (typeof exports !== 'undefined') { + exports.fabric = fabric; +} + +if (typeof document !== 'undefined' && typeof window !== 'undefined') { + fabric.document = document; + fabric.window = window; + // ensure globality even if entire library were function wrapped (as in Meteor.js packaging system) + window.fabric = fabric; +} +else { + // assume we're running under node.js when document/window are not present + 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") + ); + + if (fabric.document.createWindow) { + fabric.window = fabric.document.createWindow(); + } else { + fabric.window = fabric.document.parentWindow; + } +} + +/** + * True when in environment that supports touch events + * @type boolean + */ + +fabric.isTouchSupported = 'ontouchstart' in fabric.window; + +/** + * True when in environment that's probably Node.js + * @type boolean + */ +fabric.isLikelyNode = typeof Buffer !== 'undefined' && + typeof window === 'undefined'; + +/* _FROM_SVG_START_ */ +/** + * Attributes parsed from all SVG elements + * @type array + */ +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" +]; +/* _FROM_SVG_END_ */ + +/** + * Pixel per Inch as a default value set to 96. Can be changed for more realistic conversion. + */ +fabric.DPI = 96; +fabric.reNum = '(?:[-+]?(?:\\d+|\\d*\\.\\d+)(?:e[-+]?\\d+)?)'; +fabric.fontPaths = { }; +fabric.iMatrix = [1, 0, 0, 1, 0, 0]; +fabric.canvasModule = 'canvas'; + +/** + * Pixel limit for cache canvases. 1Mpx , 4Mpx should be fine. + * @since 1.7.14 + * @type Number + * @default + */ +fabric.perfLimitSizeTotal = 2097152; + +/** + * Pixel limit for cache canvases width or height. IE fixes the maximum at 5000 + * @since 1.7.14 + * @type Number + * @default + */ +fabric.maxCacheSideLimit = 4096; + +/** + * Lowest pixel limit for cache canvases, set at 256PX + * @since 1.7.14 + * @type Number + * @default + */ +fabric.minCacheSideLimit = 256; + +/** + * Cache Object for widths of chars in text rendering. + */ +fabric.charWidthsCache = { }; + +/** + * Device Pixel Ratio + * @see https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/SettingUptheCanvas/SettingUptheCanvas.html + */ +fabric.devicePixelRatio = fabric.window.devicePixelRatio || + fabric.window.webkitDevicePixelRatio || + fabric.window.mozDevicePixelRatio || + 1; + + +(function() { + + /** + * @private + * @param {String} eventName + * @param {Function} handler + */ + function _removeEventListener(eventName, handler) { + if (!this.__eventListeners[eventName]) { + return; + } + var eventListener = this.__eventListeners[eventName]; + if (handler) { + eventListener[eventListener.indexOf(handler)] = false; + } + else { + fabric.util.array.fill(eventListener, false); + } + } + + /** + * Observes specified event + * @deprecated `observe` deprecated since 0.8.34 (use `on` instead) + * @memberOf fabric.Observable + * @alias on + * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler}) + * @param {Function} handler Function that receives a notification when an event of the specified type occurs + * @return {Self} thisArg + * @chainable + */ + function observe(eventName, handler) { + if (!this.__eventListeners) { + this.__eventListeners = { }; + } + // one object with key/value pairs was passed + if (arguments.length === 1) { + for (var prop in eventName) { + this.on(prop, eventName[prop]); + } + } + else { + if (!this.__eventListeners[eventName]) { + this.__eventListeners[eventName] = []; + } + this.__eventListeners[eventName].push(handler); + } + return this; + } + + /** + * Stops event observing for a particular event handler. Calling this method + * without arguments removes all handlers for all events + * @deprecated `stopObserving` deprecated since 0.8.34 (use `off` instead) + * @memberOf fabric.Observable + * @alias off + * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler}) + * @param {Function} handler Function to be deleted from EventListeners + * @return {Self} thisArg + * @chainable + */ + function stopObserving(eventName, handler) { + if (!this.__eventListeners) { + return; + } + + // remove all key/value pairs (event name -> event handler) + if (arguments.length === 0) { + for (eventName in this.__eventListeners) { + _removeEventListener.call(this, eventName); + } + } + // one object with key/value pairs was passed + else if (arguments.length === 1 && typeof arguments[0] === 'object') { + for (var prop in eventName) { + _removeEventListener.call(this, prop, eventName[prop]); + } + } + else { + _removeEventListener.call(this, eventName, handler); + } + return this; + } + + /** + * Fires event with an optional options object + * @deprecated `fire` deprecated since 1.0.7 (use `trigger` instead) + * @memberOf fabric.Observable + * @alias trigger + * @param {String} eventName Event name to fire + * @param {Object} [options] Options object + * @return {Self} thisArg + * @chainable + */ + function fire(eventName, options) { + if (!this.__eventListeners) { + return; + } + + var listenersForEvent = this.__eventListeners[eventName]; + if (!listenersForEvent) { + return; + } + + for (var i = 0, len = listenersForEvent.length; i < len; i++) { + listenersForEvent[i] && listenersForEvent[i].call(this, options || { }); + } + this.__eventListeners[eventName] = listenersForEvent.filter(function(value) { + return value !== false; + }); + return this; + } + + /** + * @namespace fabric.Observable + * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events} + * @see {@link http://fabricjs.com/events|Events demo} + */ + fabric.Observable = { + observe: observe, + stopObserving: stopObserving, + fire: fire, + + on: observe, + off: stopObserving, + trigger: fire + }; +})(); + + +/** + * @namespace fabric.Collection + */ +fabric.Collection = { + + _objects: [], + + /** + * 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 + * Use of this function is highly discouraged for groups. + * you can add a bunch of objects with the add method but then you NEED + * to run a addWithUpdate call for the Group class or position/bbox will be wrong. + * @param {...fabric.Object} object Zero or more fabric instances + * @return {Self} thisArg + * @chainable + */ + add: function () { + this._objects.push.apply(this._objects, arguments); + if (this._onObjectAdded) { + for (var i = 0, length = arguments.length; i < length; i++) { + this._onObjectAdded(arguments[i]); + } + } + this.renderOnAddRemove && this.renderAll(); + return this; + }, + + /** + * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`) + * An object should be an instance of (or inherit from) fabric.Object + * Use of this function is highly discouraged for groups. + * you can add a bunch of objects with the insertAt method but then you NEED + * to run a addWithUpdate call for the Group class or position/bbox will be wrong. + * @param {Object} object Object to insert + * @param {Number} index Index to insert object at + * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs + * @return {Self} thisArg + * @chainable + */ + insertAt: function (object, index, nonSplicing) { + var objects = this.getObjects(); + if (nonSplicing) { + objects[index] = object; + } + else { + objects.splice(index, 0, object); + } + this._onObjectAdded && this._onObjectAdded(object); + this.renderOnAddRemove && this.renderAll(); + return this; + }, + + /** + * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`) + * @param {...fabric.Object} object Zero or more fabric instances + * @return {Self} thisArg + * @chainable + */ + remove: function() { + var objects = this.getObjects(), + index, somethingRemoved = false; + + for (var i = 0, length = arguments.length; i < length; i++) { + index = objects.indexOf(arguments[i]); + + // only call onObjectRemoved if an object was actually removed + if (index !== -1) { + somethingRemoved = true; + objects.splice(index, 1); + this._onObjectRemoved && this._onObjectRemoved(arguments[i]); + } + } + + this.renderOnAddRemove && somethingRemoved && this.renderAll(); + return this; + }, + + /** + * Executes given function for each object in this group + * @param {Function} callback + * Callback invoked with current object as first argument, + * index - as second and an array of all objects - as third. + * Callback is invoked in a context of Global Object (e.g. `window`) + * when no `context` argument is given + * + * @param {Object} context Context (aka thisObject) + * @return {Self} thisArg + * @chainable + */ + forEachObject: function(callback, context) { + var objects = this.getObjects(); + for (var i = 0, len = objects.length; i < len; i++) { + callback.call(context, objects[i], i, objects); + } + return this; + }, + + /** + * Returns an array of children objects of this instance + * Type parameter introduced in 1.3.10 + * @param {String} [type] When specified, only objects of this type are returned + * @return {Array} + */ + getObjects: function(type) { + if (typeof type === 'undefined') { + return this._objects; + } + return this._objects.filter(function(o) { + return o.type === type; + }); + }, + + /** + * Returns object at specified index + * @param {Number} index + * @return {Self} thisArg + */ + item: function (index) { + return this.getObjects()[index]; + }, + + /** + * Returns true if collection contains no objects + * @return {Boolean} true if collection is empty + */ + isEmpty: function () { + return this.getObjects().length === 0; + }, + + /** + * Returns a size of a collection (i.e: length of an array containing its objects) + * @return {Number} Collection size + */ + size: function() { + return this.getObjects().length; + }, + + /** + * Returns true if collection contains an object + * @param {Object} object Object to check against + * @return {Boolean} `true` if collection contains an object + */ + contains: function(object) { + return this.getObjects().indexOf(object) > -1; + }, + + /** + * Returns number representation of a collection complexity + * @return {Number} complexity + */ + complexity: function () { + return this.getObjects().reduce(function (memo, current) { + memo += current.complexity ? current.complexity() : 0; + return memo; + }, 0); + } +}; + + +/** + * @namespace fabric.CommonMethods + */ +fabric.CommonMethods = { + + /** + * Sets object's properties from options + * @param {Object} [options] Options object + */ + _setOptions: function(options) { + for (var prop in options) { + this.set(prop, options[prop]); + } + }, + + /** + * @private + * @param {Object} [filler] Options object + * @param {String} [property] property to set the Gradient to + */ + _initGradient: function(filler, property) { + if (filler && filler.colorStops && !(filler instanceof fabric.Gradient)) { + this.set(property, new fabric.Gradient(filler)); + } + }, + + /** + * @private + * @param {Object} [filler] Options object + * @param {String} [property] property to set the Pattern to + * @param {Function} [callback] callback to invoke after pattern load + */ + _initPattern: function(filler, property, callback) { + if (filler && filler.source && !(filler instanceof fabric.Pattern)) { + this.set(property, new fabric.Pattern(filler, callback)); + } + else { + callback && callback(); + } + }, + + /** + * @private + * @param {Object} [options] Options object + */ + _initClipping: function(options) { + if (!options.clipTo || typeof options.clipTo !== 'string') { + return; + } + + var functionBody = fabric.util.getFunctionBody(options.clipTo); + if (typeof functionBody !== 'undefined') { + this.clipTo = new Function('ctx', functionBody); + } + }, + + /** + * @private + */ + _setObject: function(obj) { + for (var prop in obj) { + this._set(prop, obj[prop]); + } + }, + + /** + * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`. + * @param {String|Object} key Property name or object (if object, iterate over the object properties) + * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one) + * @return {fabric.Object} thisArg + * @chainable + */ + set: function(key, value) { + if (typeof key === 'object') { + this._setObject(key); + } + else { + if (typeof value === 'function' && key !== 'clipTo') { + this._set(key, value(this.get(key))); + } + else { + this._set(key, value); + } + } + return this; + }, + + _set: function(key, value) { + this[key] = value; + }, + + /** + * Toggles specified property from `true` to `false` or from `false` to `true` + * @param {String} property Property to toggle + * @return {fabric.Object} thisArg + * @chainable + */ + toggle: function(property) { + var value = this.get(property); + if (typeof value === 'boolean') { + this.set(property, !value); + } + return this; + }, + + /** + * Basic getter + * @param {String} property Property name + * @return {*} value of a property + */ + get: function(property) { + return this[property]; + } +}; + + +(function(global) { + + var sqrt = Math.sqrt, + atan2 = Math.atan2, + pow = Math.pow, + abs = Math.abs, + PiBy180 = Math.PI / 180; + + /** + * @namespace fabric.util + */ + fabric.util = { + + /** + * Removes value from an array. + * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf` + * @static + * @memberOf fabric.util + * @param {Array} array + * @param {*} value + * @return {Array} original array + */ + removeFromArray: function(array, value) { + var idx = array.indexOf(value); + if (idx !== -1) { + array.splice(idx, 1); + } + return array; + }, + + /** + * Returns random number between 2 specified ones. + * @static + * @memberOf fabric.util + * @param {Number} min lower limit + * @param {Number} max upper limit + * @return {Number} random value (between min and max) + */ + getRandomInt: function(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; + }, + + /** + * Transforms degrees to radians. + * @static + * @memberOf fabric.util + * @param {Number} degrees value in degrees + * @return {Number} value in radians + */ + degreesToRadians: function(degrees) { + return degrees * PiBy180; + }, + + /** + * Transforms radians to degrees. + * @static + * @memberOf fabric.util + * @param {Number} radians value in radians + * @return {Number} value in degrees + */ + radiansToDegrees: function(radians) { + return radians / PiBy180; + }, + + /** + * Rotates `point` around `origin` with `radians` + * @static + * @memberOf fabric.util + * @param {fabric.Point} point The point to rotate + * @param {fabric.Point} origin The origin of the rotation + * @param {Number} radians The radians of the angle for the rotation + * @return {fabric.Point} The new rotated point + */ + rotatePoint: function(point, origin, radians) { + point.subtractEquals(origin); + var v = fabric.util.rotateVector(point, radians); + return new fabric.Point(v.x, v.y).addEquals(origin); + }, + + /** + * Rotates `vector` with `radians` + * @static + * @memberOf fabric.util + * @param {Object} vector The vector to rotate (x and y) + * @param {Number} radians The radians of the angle for the rotation + * @return {Object} The new rotated point + */ + rotateVector: function(vector, radians) { + var sin = Math.sin(radians), + cos = Math.cos(radians), + rx = vector.x * cos - vector.y * sin, + ry = vector.x * sin + vector.y * cos; + return { + x: rx, + y: ry + }; + }, + + /** + * Apply transform t to point p + * @static + * @memberOf fabric.util + * @param {fabric.Point} p The point to transform + * @param {Array} t The transform + * @param {Boolean} [ignoreOffset] Indicates that the offset should not be applied + * @return {fabric.Point} The transformed point + */ + transformPoint: function(p, t, ignoreOffset) { + if (ignoreOffset) { + return new fabric.Point( + t[0] * p.x + t[2] * p.y, + t[1] * p.x + t[3] * p.y + ); + } + return new fabric.Point( + t[0] * p.x + t[2] * p.y + t[4], + t[1] * p.x + t[3] * p.y + t[5] + ); + }, + + /** + * Returns coordinates of points's bounding rectangle (left, top, width, height) + * @param {Array} points 4 points array + * @return {Object} Object with left, top, width, height properties + */ + makeBoundingBoxFromPoints: function(points) { + var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x], + minX = fabric.util.array.min(xPoints), + maxX = fabric.util.array.max(xPoints), + width = Math.abs(minX - maxX), + yPoints = [points[0].y, points[1].y, points[2].y, points[3].y], + minY = fabric.util.array.min(yPoints), + maxY = fabric.util.array.max(yPoints), + height = Math.abs(minY - maxY); + + return { + left: minX, + top: minY, + width: width, + height: height + }; + }, + + /** + * Invert transformation t + * @static + * @memberOf fabric.util + * @param {Array} t The transform + * @return {Array} The inverted transform + */ + invertTransform: function(t) { + var a = 1 / (t[0] * t[3] - t[1] * t[2]), + r = [a * t[3], -a * t[1], -a * t[2], a * t[0]], + o = fabric.util.transformPoint({ x: t[4], y: t[5] }, r, true); + r[4] = -o.x; + r[5] = -o.y; + return r; + }, + + /** + * A wrapper around Number#toFixed, which contrary to native method returns number, not string. + * @static + * @memberOf fabric.util + * @param {Number|String} number number to operate on + * @param {Number} fractionDigits number of fraction digits to "leave" + * @return {Number} + */ + toFixed: function(number, fractionDigits) { + return parseFloat(Number(number).toFixed(fractionDigits)); + }, + + /** + * Converts from attribute value to pixel value if applicable. + * Returns converted pixels or original value not converted. + * @param {Number|String} value number to operate on + * @param {Number} fontSize + * @return {Number|String} + */ + parseUnit: function(value, fontSize) { + var unit = /\D{0,2}$/.exec(value), + number = parseFloat(value); + if (!fontSize) { + fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE; + } + switch (unit[0]) { + case 'mm': + return number * fabric.DPI / 25.4; + + case 'cm': + return number * fabric.DPI / 2.54; + + case 'in': + return number * fabric.DPI; + + case 'pt': + return number * fabric.DPI / 72; // or * 4 / 3 + + case 'pc': + return number * fabric.DPI / 72 * 12; // or * 16 + + case 'em': + return number * fontSize; + + default: + return number; + } + }, + + /** + * Function which always returns `false`. + * @static + * @memberOf fabric.util + * @return {Boolean} + */ + falseFunction: function() { + return false; + }, + + /** + * Returns klass "Class" object of given namespace + * @memberOf fabric.util + * @param {String} type Type of object (eg. 'circle') + * @param {String} namespace Namespace to get klass "Class" object from + * @return {Object} klass "Class" + */ + getKlass: function(type, namespace) { + // capitalize first letter only + type = fabric.util.string.camelize(type.charAt(0).toUpperCase() + type.slice(1)); + return fabric.util.resolveNamespace(namespace)[type]; + }, + + /** + * Returns object of given namespace + * @memberOf fabric.util + * @param {String} namespace Namespace string e.g. 'fabric.Image.filter' or 'fabric' + * @return {Object} Object for given namespace (default fabric) + */ + resolveNamespace: function(namespace) { + if (!namespace) { + return fabric; + } + + var parts = namespace.split('.'), + len = parts.length, i, + obj = global || fabric.window; + + for (i = 0; i < len; ++i) { + obj = obj[parts[i]]; + } + + return obj; + }, + + /** + * Loads image element from given url and passes it to a callback + * @memberOf fabric.util + * @param {String} url URL representing an image + * @param {Function} callback Callback; invoked with loaded image + * @param {*} [context] Context to invoke callback in + * @param {Object} [crossOrigin] crossOrigin value to set image element to + */ + loadImage: function(url, callback, context, crossOrigin) { + if (!url) { + callback && callback.call(context, url); + return; + } + + var img = fabric.util.createImage(); + + /** @ignore */ + img.onload = function () { + callback && callback.call(context, img); + img = img.onload = img.onerror = null; + }; + + /** @ignore */ + img.onerror = function() { + fabric.log('Error loading ' + img.src); + callback && callback.call(context, null, true); + img = img.onload = img.onerror = null; + }; + + // data-urls appear to be buggy with crossOrigin + // https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767 + // see https://code.google.com/p/chromium/issues/detail?id=315152 + // https://bugzilla.mozilla.org/show_bug.cgi?id=935069 + if (url.indexOf('data') !== 0 && crossOrigin) { + img.crossOrigin = crossOrigin; + } + + img.src = url; + }, + + /** + * Creates corresponding fabric instances from their object representations + * @static + * @memberOf fabric.util + * @param {Array} objects Objects to enliven + * @param {Function} callback Callback to invoke when all objects are created + * @param {String} namespace Namespace to get klass "Class" object from + * @param {Function} reviver Method for further parsing of object elements, + * called after each fabric object created. + */ + enlivenObjects: function(objects, callback, namespace, reviver) { + objects = objects || []; + + function onLoaded() { + if (++numLoadedObjects === numTotalObjects) { + callback && callback(enlivenedObjects); + } + } + + var enlivenedObjects = [], + numLoadedObjects = 0, + numTotalObjects = objects.length, + forceAsync = true; + + if (!numTotalObjects) { + callback && callback(enlivenedObjects); + return; + } + + objects.forEach(function (o, index) { + // if sparse array + if (!o || !o.type) { + onLoaded(); + return; + } + var klass = fabric.util.getKlass(o.type, namespace); + klass.fromObject(o, function (obj, error) { + error || (enlivenedObjects[index] = obj); + reviver && reviver(o, obj, error); + onLoaded(); + }, forceAsync); + }); + }, + + /** + * Create and wait for loading of patterns + * @static + * @memberOf fabric.util + * @param {Array} objects Objects to enliven + * @param {Function} callback Callback to invoke when all objects are created + * @param {String} namespace Namespace to get klass "Class" object from + * @param {Function} reviver Method for further parsing of object elements, + * called after each fabric object created. + */ + enlivenPatterns: function(patterns, callback) { + patterns = patterns || []; + + function onLoaded() { + if (++numLoadedPatterns === numPatterns) { + callback && callback(enlivenedPatterns); + } + } + + var enlivenedPatterns = [], + numLoadedPatterns = 0, + numPatterns = patterns.length; + + if (!numPatterns) { + callback && callback(enlivenedPatterns); + return; + } + + patterns.forEach(function (p, index) { + if (p && p.source) { + new fabric.Pattern(p, function(pattern) { + enlivenedPatterns[index] = pattern; + onLoaded(); + }); + } + else { + enlivenedPatterns[index] = p; + onLoaded(); + } + }); + }, + + /** + * Groups SVG elements (usually those retrieved from SVG document) + * @static + * @memberOf fabric.util + * @param {Array} elements SVG elements to group + * @param {Object} [options] Options object + * @param {String} path Value to set sourcePath to + * @return {fabric.Object|fabric.PathGroup} + */ + groupSVGElements: function(elements, options, path) { + var object; + + object = new fabric.PathGroup(elements, options); + + if (typeof path !== 'undefined') { + object.sourcePath = path; + } + return object; + }, + + /** + * Populates an object with properties of another object + * @static + * @memberOf fabric.util + * @param {Object} source Source object + * @param {Object} destination Destination object + * @return {Array} properties Propertie names to include + */ + populateWithProperties: function(source, destination, properties) { + if (properties && Object.prototype.toString.call(properties) === '[object Array]') { + for (var i = 0, len = properties.length; i < len; i++) { + if (properties[i] in source) { + destination[properties[i]] = source[properties[i]]; + } + } + } + }, + + /** + * Draws a dashed line between two points + * + * This method is used to draw dashed line around selection area. + * See <a href="http://stackoverflow.com/questions/4576724/dotted-stroke-in-canvas">dotted stroke in canvas</a> + * + * @param {CanvasRenderingContext2D} ctx context + * @param {Number} x start x coordinate + * @param {Number} y start y coordinate + * @param {Number} x2 end x coordinate + * @param {Number} y2 end y coordinate + * @param {Array} da dash array pattern + */ + drawDashedLine: function(ctx, x, y, x2, y2, da) { + var dx = x2 - x, + dy = y2 - y, + len = sqrt(dx * dx + dy * dy), + rot = atan2(dy, dx), + dc = da.length, + di = 0, + draw = true; + + ctx.save(); + ctx.translate(x, y); + ctx.moveTo(0, 0); + ctx.rotate(rot); + + x = 0; + while (len > x) { + x += da[di++ % dc]; + if (x > len) { + x = len; + } + ctx[draw ? 'lineTo' : 'moveTo'](x, 0); + draw = !draw; + } + + ctx.restore(); + }, + + /** + * Creates canvas element and initializes it via excanvas if necessary + * @static + * @memberOf fabric.util + * @param {CanvasElement} [canvasEl] optional canvas element to initialize; + * when not given, element is created implicitly + * @return {CanvasElement} initialized canvas element + */ + createCanvasElement: function(canvasEl) { + canvasEl || (canvasEl = fabric.document.createElement('canvas')); + /* eslint-disable camelcase */ + if (!canvasEl.getContext && typeof G_vmlCanvasManager !== 'undefined') { + G_vmlCanvasManager.initElement(canvasEl); + } + /* eslint-enable camelcase */ + return canvasEl; + }, + + /** + * Creates image element (works on client and node) + * @static + * @memberOf fabric.util + * @return {HTMLImageElement} HTML image element + */ + createImage: function() { + return fabric.isLikelyNode + ? new (require('canvas').Image)() + : fabric.document.createElement('img'); + }, + + /** + * Creates accessors (getXXX, setXXX) for a "class", based on "stateProperties" array + * @static + * @memberOf fabric.util + * @param {Object} klass "Class" to create accessors for + */ + createAccessors: function(klass) { + 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; + + // using `new Function` for better introspection + if (!proto[getterName]) { + proto[getterName] = (function(property) { + return new Function('return this.get("' + property + '")'); + })(propName); + } + if (!proto[setterName]) { + proto[setterName] = (function(property) { + return new Function('value', 'return this.set("' + property + '", value)'); + })(propName); + } + } + }, + + /** + * @static + * @memberOf fabric.util + * @param {fabric.Object} receiver Object implementing `clipTo` method + * @param {CanvasRenderingContext2D} ctx Context to clip + */ + clipContext: function(receiver, ctx) { + ctx.save(); + ctx.beginPath(); + receiver.clipTo(ctx); + ctx.clip(); + }, + + /** + * Multiply matrix A by matrix B to nest transformations + * @static + * @memberOf fabric.util + * @param {Array} a First transformMatrix + * @param {Array} b Second transformMatrix + * @param {Boolean} is2x2 flag to multiply matrices as 2x2 matrices + * @return {Array} The product of the two transform matrices + */ + multiplyTransformMatrices: function(a, b, is2x2) { + // Matrix multiply a * b + return [ + a[0] * b[0] + a[2] * b[1], + a[1] * b[0] + a[3] * b[1], + a[0] * b[2] + a[2] * b[3], + a[1] * b[2] + a[3] * b[3], + is2x2 ? 0 : a[0] * b[4] + a[2] * b[5] + a[4], + is2x2 ? 0 : a[1] * b[4] + a[3] * b[5] + a[5] + ]; + }, + + /** + * Decomposes standard 2x2 matrix into transform componentes + * @static + * @memberOf fabric.util + * @param {Array} a transformMatrix + * @return {Object} Components of transform + */ + qrDecompose: function(a) { + var angle = atan2(a[1], a[0]), + denom = pow(a[0], 2) + pow(a[1], 2), + scaleX = sqrt(denom), + scaleY = (a[0] * a[3] - a[2] * a [1]) / scaleX, + skewX = atan2(a[0] * a[2] + a[1] * a [3], denom); + return { + angle: angle / PiBy180, + scaleX: scaleX, + scaleY: scaleY, + skewX: skewX / PiBy180, + skewY: 0, + translateX: a[4], + translateY: a[5] + }; + }, + + customTransformMatrix: function(scaleX, scaleY, skewX) { + var skewMatrixX = [1, 0, abs(Math.tan(skewX * PiBy180)), 1], + scaleMatrix = [abs(scaleX), 0, 0, abs(scaleY)]; + return fabric.util.multiplyTransformMatrices(scaleMatrix, skewMatrixX, true); + }, + + resetObjectTransform: function (target) { + target.scaleX = 1; + target.scaleY = 1; + target.skewX = 0; + target.skewY = 0; + target.flipX = false; + target.flipY = false; + target.setAngle(0); + }, + + /** + * Returns string representation of function body + * @param {Function} fn Function to get body of + * @return {String} Function body + */ + getFunctionBody: function(fn) { + return (String(fn).match(/function[^{]*\{([\s\S]*)\}/) || {})[1]; + }, + + /** + * Returns true if context has transparent pixel + * at specified location (taking tolerance into account) + * @param {CanvasRenderingContext2D} ctx context + * @param {Number} x x coordinate + * @param {Number} y y coordinate + * @param {Number} tolerance Tolerance + */ + isTransparent: function(ctx, x, y, tolerance) { + + // If tolerance is > 0 adjust start coords to take into account. + // If moves off Canvas fix to 0 + if (tolerance > 0) { + if (x > tolerance) { + x -= tolerance; + } + else { + x = 0; + } + if (y > tolerance) { + y -= tolerance; + } + else { + y = 0; + } + } + + 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 (i = 3; i < l; i += 4) { + temp = imageData.data[i]; + _isTransparent = temp <= 0; + if (_isTransparent === false) { + break; // Stop if colour found + } + } + + imageData = null; + + return _isTransparent; + }, + + /** + * Parse preserveAspectRatio attribute from element + * @param {string} attribute to be parsed + * @return {Object} an object containing align and meetOrSlice attribute + */ + parsePreserveAspectRatioAttribute: function(attribute) { + var meetOrSlice = 'meet', alignX = 'Mid', alignY = 'Mid', + aspectRatioAttrs = attribute.split(' '), align; + + if (aspectRatioAttrs && aspectRatioAttrs.length) { + meetOrSlice = aspectRatioAttrs.pop(); + if (meetOrSlice !== 'meet' && meetOrSlice !== 'slice') { + align = meetOrSlice; + meetOrSlice = 'meet'; + } + else if (aspectRatioAttrs.length) { + align = aspectRatioAttrs.pop(); + } + } + //divide align in alignX and alignY + alignX = align !== 'none' ? align.slice(1, 4) : 'none'; + alignY = align !== 'none' ? align.slice(5, 8) : 'none'; + return { + meetOrSlice: meetOrSlice, + alignX: alignX, + alignY: alignY + }; + }, + + /** + * Clear char widths cache for a font family. + * @memberOf fabric.util + * @param {String} [fontFamily] font family to clear + */ + clearFabricFontCache: function(fontFamily) { + if (!fontFamily) { + fabric.charWidthsCache = { }; + } + else if (fabric.charWidthsCache[fontFamily]) { + delete fabric.charWidthsCache[fontFamily]; + } + }, + + /** + * Clear char widths cache for a font family. + * @memberOf fabric.util + * @param {Number} ar aspect ratio + * @param {Number} maximumArea Maximum area you want to achieve + * @param {Number} maximumSide biggest side allowed + * @return {Object.x} Limited dimensions by X + * @return {Object.y} Limited dimensions by Y + */ + limitDimsByArea: function(ar, maximumArea) { + var roughWidth = Math.sqrt(maximumArea * ar), + perfLimitSizeY = Math.floor(maximumArea / roughWidth); + return { x: Math.floor(roughWidth), y: perfLimitSizeY }; + }, + + capValue: function(min, value, max) { + return Math.max(min, Math.min(value, max)); + } + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function() { + + var arcToSegmentsCache = { }, + segmentToBezierCache = { }, + boundsOfCurveCache = { }, + _join = Array.prototype.join; + + /* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp + * by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here + * http://mozilla.org/MPL/2.0/ + */ + function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) { + var argsString = _join.call(arguments); + if (arcToSegmentsCache[argsString]) { + return arcToSegmentsCache[argsString]; + } + + var PI = Math.PI, th = rotateX * PI / 180, + sinTh = Math.sin(th), + cosTh = Math.cos(th), + fromX = 0, fromY = 0; + + rx = Math.abs(rx); + ry = Math.abs(ry); + + var px = -cosTh * toX * 0.5 - sinTh * toY * 0.5, + py = -cosTh * toY * 0.5 + sinTh * toX * 0.5, + rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px, + pl = rx2 * ry2 - rx2 * py2 - ry2 * px2, + root = 0; + + if (pl < 0) { + 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)); + } + + var cx = root * rx * py / ry, + cy = -root * ry * px / rx, + cx1 = cosTh * cx - sinTh * cy + toX * 0.5, + cy1 = sinTh * cx + cosTh * cy + toY * 0.5, + mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry), + dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px - cx) / rx, (-py - cy) / ry); + + if (sweep === 0 && dtheta > 0) { + dtheta -= 2 * PI; + } + else if (sweep === 1 && dtheta < 0) { + dtheta += 2 * PI; + } + + // Convert into cubic bezier segments <= 90deg + var segments = Math.ceil(Math.abs(dtheta / PI * 2)), + result = [], mDelta = dtheta / segments, + mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2), + th3 = mTheta + mDelta; + + for (var i = 0; i < segments; i++) { + result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY); + fromX = result[i][4]; + fromY = result[i][5]; + mTheta = th3; + th3 += mDelta; + } + arcToSegmentsCache[argsString] = result; + return result; + } + + function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) { + var argsString2 = _join.call(arguments); + if (segmentToBezierCache[argsString2]) { + return segmentToBezierCache[argsString2]; + } + + var costh2 = Math.cos(th2), + sinth2 = Math.sin(th2), + costh3 = Math.cos(th3), + 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), + cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3), + cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3); + + segmentToBezierCache[argsString2] = [ + cp1X, cp1Y, + cp2X, cp2Y, + toX, toY + ]; + return segmentToBezierCache[argsString2]; + } + + /* + * Private + */ + function calcVectorAngle(ux, uy, vx, vy) { + var ta = Math.atan2(uy, ux), + tb = Math.atan2(vy, vx); + if (tb >= ta) { + return tb - ta; + } + else { + return 2 * Math.PI - (ta - tb); + } + } + + /** + * Draws arc + * @param {CanvasRenderingContext2D} ctx + * @param {Number} fx + * @param {Number} fy + * @param {Array} coords + */ + fabric.util.drawArc = function(ctx, fx, fy, coords) { + var rx = coords[0], + ry = coords[1], + rot = coords[2], + large = coords[3], + sweep = coords[4], + tx = coords[5], + ty = coords[6], + segs = [[], [], [], []], + segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot); + + for (var i = 0, len = segsNorm.length; i < len; i++) { + segs[i][0] = segsNorm[i][0] + fx; + segs[i][1] = segsNorm[i][1] + fy; + segs[i][2] = segsNorm[i][2] + fx; + segs[i][3] = segsNorm[i][3] + fy; + segs[i][4] = segsNorm[i][4] + fx; + segs[i][5] = segsNorm[i][5] + fy; + ctx.bezierCurveTo.apply(ctx, segs[i]); + } + }; + + /** + * Calculate bounding box of a elliptic-arc + * @param {Number} fx start point of arc + * @param {Number} fy + * @param {Number} rx horizontal radius + * @param {Number} ry vertical radius + * @param {Number} rot angle of horizontal axe + * @param {Number} large 1 or 0, whatever the arc is the big or the small on the 2 points + * @param {Number} sweep 1 or 0, 1 clockwise or counterclockwise direction + * @param {Number} tx end point of arc + * @param {Number} ty + */ + 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); + + 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]); + bounds.push({ x: bound[0].x + fx, y: bound[0].y + fy }); + bounds.push({ x: bound[1].x + fx, y: bound[1].y + fy }); + fromX = segs[i][4]; + fromY = segs[i][5]; + } + return bounds; + }; + + /** + * Calculate bounding box of a beziercurve + * @param {Number} x0 starting point + * @param {Number} y0 + * @param {Number} x1 first control point + * @param {Number} y1 + * @param {Number} x2 secondo control point + * @param {Number} y2 + * @param {Number} x3 end of beizer + * @param {Number} y3 + */ + // taken from http://jsbin.com/ivomiq/56/edit no credits available for that. + function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) { + var argsString = _join.call(arguments); + if (boundsOfCurveCache[argsString]) { + return boundsOfCurveCache[argsString]; + } + + var sqrt = Math.sqrt, + min = Math.min, max = Math.max, + abs = Math.abs, tvalues = [], + bounds = [[], []], + a, b, c, t, t1, t2, b2ac, sqrtb2ac; + + b = 6 * x0 - 12 * x1 + 6 * x2; + a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3; + c = 3 * x1 - 3 * x0; + + for (var i = 0; i < 2; ++i) { + if (i > 0) { + b = 6 * y0 - 12 * y1 + 6 * y2; + a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3; + c = 3 * y1 - 3 * y0; + } + + if (abs(a) < 1e-12) { + if (abs(b) < 1e-12) { + continue; + } + t = -c / b; + if (0 < t && t < 1) { + tvalues.push(t); + } + continue; + } + b2ac = b * b - 4 * c * a; + if (b2ac < 0) { + continue; + } + sqrtb2ac = sqrt(b2ac); + t1 = (-b + sqrtb2ac) / (2 * a); + if (0 < t1 && t1 < 1) { + tvalues.push(t1); + } + t2 = (-b - sqrtb2ac) / (2 * a); + if (0 < t2 && t2 < 1) { + tvalues.push(t2); + } + } + + var x, y, j = tvalues.length, jlen = j, mt; + while (j--) { + t = tvalues[j]; + mt = 1 - t; + x = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3); + bounds[0][j] = x; + + y = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3); + bounds[1][j] = y; + } + + bounds[0][jlen] = x0; + bounds[1][jlen] = y0; + bounds[0][jlen + 1] = x3; + bounds[1][jlen + 1] = y3; + var result = [ + { + x: min.apply(null, bounds[0]), + y: min.apply(null, bounds[1]) + }, + { + x: max.apply(null, bounds[0]), + y: max.apply(null, bounds[1]) + } + ]; + boundsOfCurveCache[argsString] = result; + return result; + } + + fabric.util.getBoundsOfCurve = getBoundsOfCurve; + +})(); + + +(function() { + + var slice = Array.prototype.slice; + + /* _ES5_COMPAT_START_ */ + + if (!Array.prototype.indexOf) { + /** + * Finds index of an element in an array + * @param {*} searchElement + * @return {Number} + */ + Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { + if (this === void 0 || this === null) { + throw new TypeError(); + } + var t = Object(this), len = t.length >>> 0; + if (len === 0) { + return -1; + } + var n = 0; + if (arguments.length > 0) { + n = Number(arguments[1]); + if (n !== n) { // shortcut for verifying if it's NaN + n = 0; + } + else if (n !== 0 && n !== Number.POSITIVE_INFINITY && n !== Number.NEGATIVE_INFINITY) { + n = (n > 0 || -1) * Math.floor(Math.abs(n)); + } + } + if (n >= len) { + return -1; + } + var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); + for (; k < len; k++) { + if (k in t && t[k] === searchElement) { + return k; + } + } + return -1; + }; + } + + if (!Array.prototype.forEach) { + /** + * Iterates an array, invoking callback for each element + * @param {Function} fn Callback to invoke for each element + * @param {Object} [context] Context to invoke callback in + * @return {Array} + */ + Array.prototype.forEach = function(fn, context) { + for (var i = 0, len = this.length >>> 0; i < len; i++) { + if (i in this) { + fn.call(context, this[i], i, this); + } + } + }; + } + + if (!Array.prototype.map) { + /** + * Returns a result of iterating over an array, invoking callback for each element + * @param {Function} fn Callback to invoke for each element + * @param {Object} [context] Context to invoke callback in + * @return {Array} + */ + Array.prototype.map = function(fn, context) { + 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); + } + } + return result; + }; + } + + if (!Array.prototype.every) { + /** + * Returns true if a callback returns truthy value for all elements in an array + * @param {Function} fn Callback to invoke for each element + * @param {Object} [context] Context to invoke callback in + * @return {Boolean} + */ + Array.prototype.every = function(fn, context) { + for (var i = 0, len = this.length >>> 0; i < len; i++) { + if (i in this && !fn.call(context, this[i], i, this)) { + return false; + } + } + return true; + }; + } + + if (!Array.prototype.some) { + /** + * Returns true if a callback returns truthy value for at least one element in an array + * @param {Function} fn Callback to invoke for each element + * @param {Object} [context] Context to invoke callback in + * @return {Boolean} + */ + Array.prototype.some = function(fn, context) { + for (var i = 0, len = this.length >>> 0; i < len; i++) { + if (i in this && fn.call(context, this[i], i, this)) { + return true; + } + } + return false; + }; + } + + if (!Array.prototype.filter) { + /** + * Returns the result of iterating over elements in an array + * @param {Function} fn Callback to invoke for each element + * @param {Object} [context] Context to invoke callback in + * @return {Array} + */ + Array.prototype.filter = function(fn, context) { + 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 + if (fn.call(context, val, i, this)) { + result.push(val); + } + } + } + return result; + }; + } + + if (!Array.prototype.reduce) { + /** + * Returns "folded" (reduced) result of iterating over elements in an array + * @param {Function} fn Callback to invoke for each element + * @return {*} + */ + Array.prototype.reduce = function(fn /*, initial*/) { + var len = this.length >>> 0, + i = 0, + rv; + + if (arguments.length > 1) { + rv = arguments[1]; + } + else { + do { + if (i in this) { + rv = this[i++]; + break; + } + // if array contains no values, no initial value to return + if (++i >= len) { + throw new TypeError(); + } + } + while (true); + } + for (; i < len; i++) { + if (i in this) { + rv = fn.call(null, rv, this[i], i, this); + } + } + return rv; + }; + } + + /* _ES5_COMPAT_END_ */ + + /** + * Invokes method on all items in a given array + * @memberOf fabric.util.array + * @param {Array} array Array to iterate over + * @param {String} method Name of a method to invoke + * @return {Array} + */ + function invoke(array, method) { + 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]); + } + return result; + } + + /** + * Finds maximum value in array (not necessarily "first" one) + * @memberOf fabric.util.array + * @param {Array} array Array to iterate over + * @param {String} byProperty + * @return {*} + */ + function max(array, byProperty) { + return find(array, byProperty, function(value1, value2) { + return value1 >= value2; + }); + } + + /** + * Finds minimum value in array (not necessarily "first" one) + * @memberOf fabric.util.array + * @param {Array} array Array to iterate over + * @param {String} byProperty + * @return {*} + */ + function min(array, byProperty) { + return find(array, byProperty, function(value1, value2) { + return value1 < value2; + }); + } + + /** + * @private + */ + function fill(array, value) { + var k = array.length; + while (k--) { + array[k] = value; + } + return array; + } + + /** + * @private + */ + function find(array, byProperty, condition) { + if (!array || array.length === 0) { + return; + } + + var i = array.length - 1, + result = byProperty ? array[i][byProperty] : array[i]; + if (byProperty) { + while (i--) { + if (condition(array[i][byProperty], result)) { + result = array[i][byProperty]; + } + } + } + else { + while (i--) { + if (condition(array[i], result)) { + result = array[i]; + } + } + } + return result; + } + + /** + * @namespace fabric.util.array + */ + fabric.util.array = { + fill: fill, + invoke: invoke, + min: min, + max: max + }; + +})(); + + +(function() { + /** + * Copies all enumerable properties of one js object to another + * Does not clone or extend fabric.Object subclasses. + * @memberOf fabric.util.object + * @param {Object} destination Where to copy to + * @param {Object} source Where to copy from + * @return {Object} + */ + + function extend(destination, source, deep) { + // JScript DontEnum bug is not taken care of + // 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 (!fabric.isLikelyNode && source instanceof Element) { + // avoid cloning deep images, canvases, + destination = source; + } + else if (source instanceof Array) { + destination = []; + for (var i = 0, len = source.length; i < len; i++) { + destination[i] = extend({ }, source[i], deep); + } + } + else if (source && typeof source === 'object') { + for (var property in source) { + if (source.hasOwnProperty(property)) { + destination[property] = extend({ }, 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; + } + + /** + * Creates an empty object and copies all enumerable properties of another object to it + * @memberOf fabric.util.object + * @param {Object} object Object to clone + * @return {Object} + */ + function clone(object, deep) { + return extend({ }, object, deep); + } + + /** @namespace fabric.util.object */ + fabric.util.object = { + extend: extend, + clone: clone + }; + +})(); + + +(function() { + + /* _ES5_COMPAT_START_ */ + if (!String.prototype.trim) { + /** + * Trims a string (removing whitespace from the beginning and the end) + * @function external:String#trim + * @see <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/Trim">String#trim on MDN</a> + */ + String.prototype.trim = function () { + // this trim is not fully ES3 or ES5 compliant, but it should cover most cases for now + return this.replace(/^[\s\xA0]+/, '').replace(/[\s\xA0]+$/, ''); + }; + } + /* _ES5_COMPAT_END_ */ + + /** + * Camelizes a string + * @memberOf fabric.util.string + * @param {String} string String to camelize + * @return {String} Camelized version of a string + */ + function camelize(string) { + return string.replace(/-+(.)?/g, function(match, character) { + return character ? character.toUpperCase() : ''; + }); + } + + /** + * Capitalizes a string + * @memberOf fabric.util.string + * @param {String} string String to capitalize + * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized + * and other letters stay untouched, if false first letter is capitalized + * and other letters are converted to lowercase. + * @return {String} Capitalized version of a string + */ + function capitalize(string, firstLetterOnly) { + return string.charAt(0).toUpperCase() + + (firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase()); + } + + /** + * Escapes XML in a string + * @memberOf fabric.util.string + * @param {String} string String to escape + * @return {String} Escaped version of a string + */ + function escapeXml(string) { + return string.replace(/&/g, '&amp;') + .replace(/"/g, '&quot;') + .replace(/'/g, '&apos;') + .replace(/</g, '&lt;') + .replace(/>/g, '&gt;'); + } + + /** + * String utilities + * @namespace fabric.util.string + */ + fabric.util.string = { + camelize: camelize, + capitalize: capitalize, + escapeXml: escapeXml + }; +})(); + + +/* _ES5_COMPAT_START_ */ +(function() { + + var slice = Array.prototype.slice, + apply = Function.prototype.apply, + Dummy = function() { }; + + if (!Function.prototype.bind) { + /** + * Cross-browser approximation of ES5 Function.prototype.bind (not fully spec conforming) + * @see <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind">Function#bind on MDN</a> + * @param {Object} thisArg Object to bind function to + * @param {Any[]} Values to pass to a bound function + * @return {Function} + */ + Function.prototype.bind = function(thisArg) { + var _this = this, args = slice.call(arguments, 1), bound; + if (args.length) { + bound = function() { + return apply.call(_this, this instanceof Dummy ? this : thisArg, args.concat(slice.call(arguments))); + }; + } + else { + /** @ignore */ + bound = function() { + return apply.call(_this, this instanceof Dummy ? this : thisArg, arguments); + }; + } + Dummy.prototype = this.prototype; + bound.prototype = new Dummy(); + + return bound; + }; + } + +})(); +/* _ES5_COMPAT_END_ */ + + +(function() { + + var slice = Array.prototype.slice, emptyFunction = function() { }, + + IS_DONTENUM_BUGGY = (function() { + for (var p in { toString: 1 }) { + if (p === 'toString') { + return false; + } + } + return true; + })(), + + /** @ignore */ + addMethods = function(klass, source, parent) { + for (var property in source) { + + if (property in klass.prototype && + typeof klass.prototype[property] === 'function' && + (source[property] + '').indexOf('callSuper') > -1) { + + klass.prototype[property] = (function(property) { + return function() { + + var superclass = this.constructor.superclass; + this.constructor.superclass = parent; + var returnValue = source[property].apply(this, arguments); + this.constructor.superclass = superclass; + + if (property !== 'initialize') { + return returnValue; + } + }; + })(property); + } + else { + klass.prototype[property] = source[property]; + } + + if (IS_DONTENUM_BUGGY) { + if (source.toString !== Object.prototype.toString) { + klass.prototype.toString = source.toString; + } + if (source.valueOf !== Object.prototype.valueOf) { + klass.prototype.valueOf = source.valueOf; + } + } + } + }; + + function Subclass() { } + + function callSuper(methodName) { + var parentMethod = null, + _this = this; + + // climb prototype chain to find method not equal to callee's method + while (_this.constructor.superclass) { + var superClassMethod = _this.constructor.superclass.prototype[methodName]; + if (_this[methodName] !== superClassMethod) { + parentMethod = superClassMethod; + break; + } + // eslint-disable-next-line + _this = _this.constructor.superclass.prototype; + } + + if (!parentMethod) { + return console.log('tried to callSuper ' + methodName + ', method not found in prototype chain', this); + } + + return (arguments.length > 1) + ? parentMethod.apply(this, slice.call(arguments, 1)) + : parentMethod.call(this); + } + + /** + * Helper for creation of "classes". + * @memberOf fabric.util + * @param {Function} [parent] optional "Class" to inherit from + * @param {Object} [properties] Properties shared by all instances of this class + * (be careful modifying objects defined here as this would affect all instances) + */ + function createClass() { + var parent = null, + properties = slice.call(arguments, 0); + + if (typeof properties[0] === 'function') { + parent = properties.shift(); + } + function klass() { + this.initialize.apply(this, arguments); + } + + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + Subclass.prototype = parent.prototype; + klass.prototype = new Subclass(); + parent.subclasses.push(klass); + } + for (var i = 0, length = properties.length; i < length; i++) { + addMethods(klass, properties[i], parent); + } + if (!klass.prototype.initialize) { + klass.prototype.initialize = emptyFunction; + } + klass.prototype.constructor = klass; + klass.prototype.callSuper = callSuper; + return klass; + } + + fabric.util.createClass = createClass; +})(); + + +(function () { + + var unknown = 'unknown'; + + /* EVENT HANDLING */ + + function areHostMethods(object) { + var methodNames = Array.prototype.slice.call(arguments, 1), + t, i, len = methodNames.length; + for (i = 0; i < len; i++) { + t = typeof object[methodNames[i]]; + if (!(/^(?:function|object|unknown)$/).test(t)) { + return false; + } + } + return true; + } + + /** @ignore */ + var getElement, + setElement, + getUniqueId = (function () { + var uid = 0; + return function (element) { + return element.__uniqueID || (element.__uniqueID = 'uniqueID__' + uid++); + }; + })(); + + (function () { + var elements = { }; + /** @ignore */ + getElement = function (uid) { + return elements[uid]; + }; + /** @ignore */ + setElement = function (uid, element) { + elements[uid] = element; + }; + })(); + + function createListener(uid, handler) { + return { + handler: handler, + wrappedHandler: createWrappedHandler(uid, handler) + }; + } + + function createWrappedHandler(uid, handler) { + return function (e) { + handler.call(getElement(uid), e || fabric.window.event); + }; + } + + function createDispatcher(uid, eventName) { + return function (e) { + if (handlers[uid] && handlers[uid][eventName]) { + var handlersForEvent = handlers[uid][eventName]; + for (var i = 0, len = handlersForEvent.length; i < len; i++) { + handlersForEvent[i].call(this, e || fabric.window.event); + } + } + }; + } + + var shouldUseAddListenerRemoveListener = ( + areHostMethods(fabric.document.documentElement, 'addEventListener', 'removeEventListener') && + areHostMethods(fabric.window, 'addEventListener', 'removeEventListener')), + + shouldUseAttachEventDetachEvent = ( + areHostMethods(fabric.document.documentElement, 'attachEvent', 'detachEvent') && + areHostMethods(fabric.window, 'attachEvent', 'detachEvent')), + + // IE branch + listeners = { }, + + // DOM L0 branch + handlers = { }, + + addListener, removeListener; + + if (shouldUseAddListenerRemoveListener) { + /** @ignore */ + addListener = function (element, eventName, handler, options) { + // since ie10 or ie9 can use addEventListener but they do not support options, i need to check + element && element.addEventListener(eventName, handler, shouldUseAttachEventDetachEvent ? false : options); + }; + /** @ignore */ + removeListener = function (element, eventName, handler, options) { + element && element.removeEventListener(eventName, handler, shouldUseAttachEventDetachEvent ? false : options); + }; + } + + else if (shouldUseAttachEventDetachEvent) { + /** @ignore */ + addListener = function (element, eventName, handler) { + if (!element) { + return; + } + var uid = getUniqueId(element); + setElement(uid, element); + if (!listeners[uid]) { + listeners[uid] = { }; + } + if (!listeners[uid][eventName]) { + listeners[uid][eventName] = []; + + } + var listener = createListener(uid, handler); + listeners[uid][eventName].push(listener); + element.attachEvent('on' + eventName, listener.wrappedHandler); + }; + /** @ignore */ + removeListener = function (element, eventName, handler) { + if (!element) { + return; + } + var uid = getUniqueId(element), listener; + if (listeners[uid] && listeners[uid][eventName]) { + for (var i = 0, len = listeners[uid][eventName].length; i < len; i++) { + listener = listeners[uid][eventName][i]; + if (listener && listener.handler === handler) { + element.detachEvent('on' + eventName, listener.wrappedHandler); + listeners[uid][eventName][i] = null; + } + } + } + }; + } + else { + /** @ignore */ + addListener = function (element, eventName, handler) { + if (!element) { + return; + } + var uid = getUniqueId(element); + if (!handlers[uid]) { + handlers[uid] = { }; + } + if (!handlers[uid][eventName]) { + handlers[uid][eventName] = []; + var existingHandler = element['on' + eventName]; + if (existingHandler) { + handlers[uid][eventName].push(existingHandler); + } + element['on' + eventName] = createDispatcher(uid, eventName); + } + handlers[uid][eventName].push(handler); + }; + /** @ignore */ + removeListener = function (element, eventName, handler) { + if (!element) { + return; + } + var uid = getUniqueId(element); + if (handlers[uid] && handlers[uid][eventName]) { + var handlersForEvent = handlers[uid][eventName]; + for (var i = 0, len = handlersForEvent.length; i < len; i++) { + if (handlersForEvent[i] === handler) { + handlersForEvent.splice(i, 1); + } + } + } + }; + } + + /** + * Adds an event listener to an element + * @function + * @memberOf fabric.util + * @param {HTMLElement} element + * @param {String} eventName + * @param {Function} handler + */ + fabric.util.addListener = addListener; + + /** + * Removes an event listener from an element + * @function + * @memberOf fabric.util + * @param {HTMLElement} element + * @param {String} eventName + * @param {Function} handler + */ + fabric.util.removeListener = removeListener; + + /** + * Cross-browser wrapper for getting event's coordinates + * @memberOf fabric.util + * @param {Event} event Event object + */ + function getPointer(event) { + event || (event = fabric.window.event); + + var element = event.target || + (typeof event.srcElement !== unknown ? event.srcElement : null), + + scroll = fabric.util.getScrollLeftTop(element); + + return { + x: pointerX(event) + scroll.left, + y: pointerY(event) + scroll.top + }; + } + + var pointerX = function(event) { + // 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); + }, + + pointerY = function(event) { + return (typeof event.clientY !== unknown ? event.clientY : 0); + }; + + function _getPointer(event, pageProp, clientProp) { + var touchProp = event.type === 'touchend' ? 'changedTouches' : 'touches'; + + return (event[touchProp] && event[touchProp][0] + ? (event[touchProp][0][pageProp] - (event[touchProp][0][pageProp] - event[touchProp][0][clientProp])) + || event[clientProp] + : event[clientProp]); + } + + if (fabric.isTouchSupported) { + pointerX = function(event) { + return _getPointer(event, 'pageX', 'clientX'); + }; + pointerY = function(event) { + return _getPointer(event, 'pageY', 'clientY'); + }; + } + + fabric.util.getPointer = getPointer; + + fabric.util.object.extend(fabric.util, fabric.Observable); + +})(); + + +(function () { + + /** + * Cross-browser wrapper for setting element's style + * @memberOf fabric.util + * @param {HTMLElement} element + * @param {Object} styles + * @return {HTMLElement} Element that was passed as a first argument + */ + function setStyle(element, styles) { + var elementStyle = element.style; + if (!elementStyle) { + return element; + } + if (typeof styles === 'string') { + element.style.cssText += ';' + styles; + return styles.indexOf('opacity') > -1 + ? setOpacity(element, styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) + : element; + } + for (var property in styles) { + if (property === 'opacity') { + setOpacity(element, styles[property]); + } + else { + var normalizedProperty = (property === 'float' || property === 'cssFloat') + ? (typeof elementStyle.styleFloat === 'undefined' ? 'cssFloat' : 'styleFloat') + : property; + elementStyle[normalizedProperty] = styles[property]; + } + } + return element; + } + + var parseEl = fabric.document.createElement('div'), + supportsOpacity = typeof parseEl.style.opacity === 'string', + supportsFilters = typeof parseEl.style.filter === 'string', + reOpacity = /alpha\s*\(\s*opacity\s*=\s*([^\)]+)\)/, + + /** @ignore */ + setOpacity = function (element) { return element; }; + + if (supportsOpacity) { + /** @ignore */ + setOpacity = function(element, value) { + element.style.opacity = value; + return element; + }; + } + else if (supportsFilters) { + /** @ignore */ + setOpacity = function(element, value) { + var es = element.style; + if (element.currentStyle && !element.currentStyle.hasLayout) { + es.zoom = 1; + } + if (reOpacity.test(es.filter)) { + value = value >= 0.9999 ? '' : ('alpha(opacity=' + (value * 100) + ')'); + es.filter = es.filter.replace(reOpacity, value); + } + else { + es.filter += ' alpha(opacity=' + (value * 100) + ')'; + } + return element; + }; + } + + fabric.util.setStyle = setStyle; + +})(); + + +(function() { + + var _slice = Array.prototype.slice; + + /** + * Takes id and returns an element with that id (if one exists in a document) + * @memberOf fabric.util + * @param {String|HTMLElement} id + * @return {HTMLElement|null} + */ + function getById(id) { + return typeof id === 'string' ? fabric.document.getElementById(id) : id; + } + + var sliceCanConvertNodelists, + /** + * Converts an array-like object (e.g. arguments or NodeList) to an array + * @memberOf fabric.util + * @param {Object} arrayLike + * @return {Array} + */ + toArray = function(arrayLike) { + return _slice.call(arrayLike, 0); + }; + + try { + sliceCanConvertNodelists = toArray(fabric.document.childNodes) instanceof Array; + } + catch (err) { } + + if (!sliceCanConvertNodelists) { + toArray = function(arrayLike) { + var arr = new Array(arrayLike.length), i = arrayLike.length; + while (i--) { + arr[i] = arrayLike[i]; + } + return arr; + }; + } + + /** + * Creates specified element with specified attributes + * @memberOf fabric.util + * @param {String} tagName Type of an element to create + * @param {Object} [attributes] Attributes to set on an element + * @return {HTMLElement} Newly created element + */ + function makeElement(tagName, attributes) { + var el = fabric.document.createElement(tagName); + for (var prop in attributes) { + if (prop === 'class') { + el.className = attributes[prop]; + } + else if (prop === 'for') { + el.htmlFor = attributes[prop]; + } + else { + el.setAttribute(prop, attributes[prop]); + } + } + return el; + } + + /** + * Adds class to an element + * @memberOf fabric.util + * @param {HTMLElement} element Element to add class to + * @param {String} className Class to add to an element + */ + function addClass(element, className) { + if (element && (' ' + element.className + ' ').indexOf(' ' + className + ' ') === -1) { + element.className += (element.className ? ' ' : '') + className; + } + } + + /** + * Wraps element with another element + * @memberOf fabric.util + * @param {HTMLElement} element Element to wrap + * @param {HTMLElement|String} wrapper Element to wrap with + * @param {Object} [attributes] Attributes to set on a wrapper + * @return {HTMLElement} wrapper + */ + function wrapElement(element, wrapper, attributes) { + if (typeof wrapper === 'string') { + wrapper = makeElement(wrapper, attributes); + } + if (element.parentNode) { + element.parentNode.replaceChild(wrapper, element); + } + wrapper.appendChild(element); + return wrapper; + } + + /** + * Returns element scroll offsets + * @memberOf fabric.util + * @param {HTMLElement} element Element to operate on + * @return {Object} Object with left/top values + */ + function getScrollLeftTop(element) { + + var left = 0, + top = 0, + docElement = fabric.document.documentElement, + body = fabric.document.body || { + scrollLeft: 0, scrollTop: 0 + }; + + // While loop checks (and then sets element to) .parentNode OR .host + // to account for ShadowDOM. We still want to traverse up out of ShadowDOM, + // but the .parentNode of a root ShadowDOM node will always be null, instead + // it should be accessed through .host. See http://stackoverflow.com/a/24765528/4383938 + while (element && (element.parentNode || element.host)) { + + // Set element to element parent, or 'host' in case of ShadowDOM + element = element.parentNode || element.host; + + if (element === fabric.document) { + left = body.scrollLeft || docElement.scrollLeft || 0; + top = body.scrollTop || docElement.scrollTop || 0; + } + else { + left += element.scrollLeft || 0; + top += element.scrollTop || 0; + } + + if (element.nodeType === 1 && + fabric.util.getElementStyle(element, 'position') === 'fixed') { + break; + } + } + + return { left: left, top: top }; + } + + /** + * Returns offset for a given element + * @function + * @memberOf fabric.util + * @param {HTMLElement} element Element to get offset for + * @return {Object} Object with "left" and "top" properties + */ + function getElementOffset(element) { + var docElem, + doc = element && element.ownerDocument, + box = { left: 0, top: 0 }, + offset = { left: 0, top: 0 }, + scrollLeftTop, + offsetAttributes = { + borderLeftWidth: 'left', + borderTopWidth: 'top', + paddingLeft: 'left', + paddingTop: 'top' + }; + + if (!doc) { + return offset; + } + + for (var attr in offsetAttributes) { + offset[offsetAttributes[attr]] += parseInt(getElementStyle(element, attr), 10) || 0; + } + + docElem = doc.documentElement; + if ( typeof element.getBoundingClientRect !== 'undefined' ) { + box = element.getBoundingClientRect(); + } + + scrollLeftTop = getScrollLeftTop(element); + + return { + left: box.left + scrollLeftTop.left - (docElem.clientLeft || 0) + offset.left, + top: box.top + scrollLeftTop.top - (docElem.clientTop || 0) + offset.top + }; + } + + /** + * Returns style attribute value of a given element + * @memberOf fabric.util + * @param {HTMLElement} element Element to get style attribute for + * @param {String} attr Style attribute to get for element + * @return {String} Style attribute value of the given element. + */ + var getElementStyle; + if (fabric.document.defaultView && fabric.document.defaultView.getComputedStyle) { + getElementStyle = function(element, attr) { + var style = fabric.document.defaultView.getComputedStyle(element, null); + return style ? style[attr] : undefined; + }; + } + else { + getElementStyle = function(element, attr) { + var value = element.style[attr]; + if (!value && element.currentStyle) { + value = element.currentStyle[attr]; + } + return value; + }; + } + + (function () { + var style = fabric.document.documentElement.style, + selectProp = 'userSelect' in style + ? 'userSelect' + : 'MozUserSelect' in style + ? 'MozUserSelect' + : 'WebkitUserSelect' in style + ? 'WebkitUserSelect' + : 'KhtmlUserSelect' in style + ? 'KhtmlUserSelect' + : ''; + + /** + * Makes element unselectable + * @memberOf fabric.util + * @param {HTMLElement} element Element to make unselectable + * @return {HTMLElement} Element that was passed in + */ + function makeElementUnselectable(element) { + if (typeof element.onselectstart !== 'undefined') { + element.onselectstart = fabric.util.falseFunction; + } + if (selectProp) { + element.style[selectProp] = 'none'; + } + else if (typeof element.unselectable === 'string') { + element.unselectable = 'on'; + } + return element; + } + + /** + * Makes element selectable + * @memberOf fabric.util + * @param {HTMLElement} element Element to make selectable + * @return {HTMLElement} Element that was passed in + */ + function makeElementSelectable(element) { + if (typeof element.onselectstart !== 'undefined') { + element.onselectstart = null; + } + if (selectProp) { + element.style[selectProp] = ''; + } + else if (typeof element.unselectable === 'string') { + element.unselectable = ''; + } + return element; + } + + fabric.util.makeElementUnselectable = makeElementUnselectable; + fabric.util.makeElementSelectable = makeElementSelectable; + })(); + + (function() { + + /** + * Inserts a script element with a given url into a document; invokes callback, when that script is finished loading + * @memberOf fabric.util + * @param {String} url URL of a script to load + * @param {Function} callback Callback to execute when script is finished loading + */ + function getScript(url, callback) { + var headEl = fabric.document.getElementsByTagName('head')[0], + scriptEl = fabric.document.createElement('script'), + loading = true; + + /** @ignore */ + scriptEl.onload = /** @ignore */ scriptEl.onreadystatechange = function(e) { + if (loading) { + if (typeof this.readyState === 'string' && + this.readyState !== 'loaded' && + this.readyState !== 'complete') { + return; + } + loading = false; + callback(e || fabric.window.event); + scriptEl = scriptEl.onload = scriptEl.onreadystatechange = null; + } + }; + scriptEl.src = url; + headEl.appendChild(scriptEl); + // causes issue in Opera + // headEl.removeChild(scriptEl); + } + + fabric.util.getScript = getScript; + })(); + + fabric.util.getById = getById; + fabric.util.toArray = toArray; + fabric.util.makeElement = makeElement; + fabric.util.addClass = addClass; + fabric.util.wrapElement = wrapElement; + fabric.util.getScrollLeftTop = getScrollLeftTop; + fabric.util.getElementOffset = getElementOffset; + fabric.util.getElementStyle = getElementStyle; + +})(); + + +(function() { + + function addParamToUrl(url, param) { + return url + (/\?/.test(url) ? '&' : '?') + param; + } + + var makeXHR = (function() { + var factories = [ + function() { return new ActiveXObject('Microsoft.XMLHTTP'); }, + function() { return new ActiveXObject('Msxml2.XMLHTTP'); }, + function() { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); }, + function() { return new XMLHttpRequest(); } + ]; + for (var i = factories.length; i--; ) { + try { + var req = factories[i](); + if (req) { + return factories[i]; + } + } + catch (err) { } + } + })(); + + function emptyFn() { } + + /** + * Cross-browser abstraction for sending XMLHttpRequest + * @memberOf fabric.util + * @param {String} url URL to send XMLHttpRequest to + * @param {Object} [options] Options object + * @param {String} [options.method="GET"] + * @param {String} [options.parameters] parameters to append to url in GET or in body + * @param {String} [options.body] body to send with POST or PUT request + * @param {Function} options.onComplete Callback to invoke when request is completed + * @return {XMLHttpRequest} request + */ + function request(url, options) { + + options || (options = { }); + + var method = options.method ? options.method.toUpperCase() : 'GET', + onComplete = options.onComplete || function() { }, + xhr = makeXHR(), + body = options.body || options.parameters; + + /** @ignore */ + xhr.onreadystatechange = function() { + if (xhr.readyState === 4) { + onComplete(xhr); + xhr.onreadystatechange = emptyFn; + } + }; + + if (method === 'GET') { + body = null; + if (typeof options.parameters === 'string') { + url = addParamToUrl(url, options.parameters); + } + } + + xhr.open(method, url, true); + + if (method === 'POST' || method === 'PUT') { + xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); + } + + xhr.send(body); + return xhr; + } + + fabric.util.request = request; +})(); + + +/** + * Wrapper around `console.log` (when available) + * @param {*} [values] Values to log + */ +fabric.log = function() { }; + +/** + * Wrapper around `console.warn` (when available) + * @param {*} [values] Values to log as a warning + */ +fabric.warn = function() { }; + +/* eslint-disable */ +if (typeof console !== 'undefined') { + + ['log', 'warn'].forEach(function(methodName) { + + if (typeof console[methodName] !== 'undefined' && + typeof console[methodName].apply === 'function') { + + fabric[methodName] = function() { + return console[methodName].apply(console, arguments); + }; + } + }); +} +/* eslint-enable */ + + +(function() { + + function noop() { + return false; + } + + /** + * Changes value from one to another within certain period of time, invoking callbacks as value is being changed. + * @memberOf fabric.util + * @param {Object} [options] Animation options + * @param {Function} [options.onChange] Callback; invoked on every value change + * @param {Function} [options.onComplete] Callback; invoked when value change is completed + * @param {Number} [options.startValue=0] Starting value + * @param {Number} [options.endValue=100] Ending value + * @param {Number} [options.byValue=100] Value to modify the property by + * @param {Function} [options.easing] Easing function + * @param {Number} [options.duration=500] Duration of change (in ms) + */ + function animate(options) { + + requestAnimFrame(function(timestamp) { + options || (options = { }); + + var start = timestamp || +new Date(), + duration = options.duration || 500, + finish = start + duration, time, + onChange = options.onChange || noop, + abort = options.abort || noop, + onComplete = options.onComplete || noop, + easing = options.easing || function(t, b, c, d) {return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;}, + startValue = 'startValue' in options ? options.startValue : 0, + endValue = 'endValue' in options ? options.endValue : 100, + byValue = options.byValue || endValue - startValue; + + options.onStart && options.onStart(); + + (function tick(ticktime) { + if (abort()) { + onComplete(endValue, 1, 1); + return; + } + time = ticktime || +new Date(); + var currentTime = time > finish ? duration : (time - start), + timePerc = currentTime / duration, + current = easing(currentTime, startValue, byValue, duration), + valuePerc = Math.abs((current - startValue) / byValue); + onChange(current, valuePerc, timePerc); + if (time > finish) { + options.onComplete && options.onComplete(); + return; + } + requestAnimFrame(tick); + })(start); + }); + + } + + var _requestAnimFrame = fabric.window.requestAnimationFrame || + fabric.window.webkitRequestAnimationFrame || + fabric.window.mozRequestAnimationFrame || + fabric.window.oRequestAnimationFrame || + fabric.window.msRequestAnimationFrame || + function(callback) { + fabric.window.setTimeout(callback, 1000 / 60); + }; + + /** + * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/ + * In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method + * @memberOf fabric.util + * @param {Function} callback Callback to invoke + * @param {DOMElement} element optional Element to associate with animation + */ + function requestAnimFrame() { + return _requestAnimFrame.apply(fabric.window, arguments); + } + + fabric.util.animate = animate; + fabric.util.requestAnimFrame = requestAnimFrame; + +})(); + + +(function() { + // Calculate an in-between color. Returns a "rgba()" string. + // Credit: Edwin Martin <edwin@bitstorm.org> + // http://www.bitstorm.org/jquery/color-animation/jquery.animate-colors.js + function calculateColor(begin, end, pos) { + var color = 'rgba(' + + parseInt((begin[0] + pos * (end[0] - begin[0])), 10) + ',' + + parseInt((begin[1] + pos * (end[1] - begin[1])), 10) + ',' + + parseInt((begin[2] + pos * (end[2] - begin[2])), 10); + + color += ',' + (begin && end ? parseFloat(begin[3] + pos * (end[3] - begin[3])) : 1); + color += ')'; + return color; + } + + /** + * Changes the color from one to another within certain period of time, invoking callbacks as value is being changed. + * @memberOf fabric.util + * @param {String} fromColor The starting color in hex or rgb(a) format. + * @param {String} toColor The starting color in hex or rgb(a) format. + * @param {Number} [duration] Duration of change (in ms). + * @param {Object} [options] Animation options + * @param {Function} [options.onChange] Callback; invoked on every value change + * @param {Function} [options.onComplete] Callback; invoked when value change is completed + * @param {Function} [options.colorEasing] Easing function. Note that this function only take two arguments (currentTime, duration). Thus the regular animation easing functions cannot be used. + */ + function animateColor(fromColor, toColor, duration, options) { + var startColor = new fabric.Color(fromColor).getSource(), + endColor = new fabric.Color(toColor).getSource(); + + options = options || {}; + + fabric.util.animate(fabric.util.object.extend(options, { + duration: duration || 500, + startValue: startColor, + endValue: endColor, + byValue: endColor, + easing: function (currentTime, startValue, byValue, duration) { + var posValue = options.colorEasing + ? options.colorEasing(currentTime, duration) + : 1 - Math.cos(currentTime / duration * (Math.PI / 2)); + return calculateColor(startValue, byValue, posValue); + } + })); + } + + fabric.util.animateColor = animateColor; + +})(); + + +(function() { + + function normalize(a, c, p, s) { + if (a < Math.abs(c)) { + a = c; + s = p / 4; + } + else { + //handle the 0/0 case: + if (c === 0 && a === 0) { + s = p / (2 * Math.PI) * Math.asin(1); + } + else { + s = p / (2 * Math.PI) * Math.asin(c / a); + } + } + return { a: a, c: c, p: p, s: s }; + } + + function elastic(opts, t, d) { + return opts.a * + Math.pow(2, 10 * (t -= 1)) * + Math.sin( (t * d - opts.s) * (2 * Math.PI) / opts.p ); + } + + /** + * Cubic easing out + * @memberOf fabric.util.ease + */ + function easeOutCubic(t, b, c, d) { + return c * ((t = t / d - 1) * t * t + 1) + b; + } + + /** + * Cubic easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutCubic(t, b, c, d) { + t /= d / 2; + if (t < 1) { + return c / 2 * t * t * t + b; + } + return c / 2 * ((t -= 2) * t * t + 2) + b; + } + + /** + * Quartic easing in + * @memberOf fabric.util.ease + */ + function easeInQuart(t, b, c, d) { + return c * (t /= d) * t * t * t + b; + } + + /** + * Quartic easing out + * @memberOf fabric.util.ease + */ + function easeOutQuart(t, b, c, d) { + return -c * ((t = t / d - 1) * t * t * t - 1) + b; + } + + /** + * Quartic easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutQuart(t, b, c, d) { + t /= d / 2; + if (t < 1) { + return c / 2 * t * t * t * t + b; + } + return -c / 2 * ((t -= 2) * t * t * t - 2) + b; + } + + /** + * Quintic easing in + * @memberOf fabric.util.ease + */ + function easeInQuint(t, b, c, d) { + return c * (t /= d) * t * t * t * t + b; + } + + /** + * Quintic easing out + * @memberOf fabric.util.ease + */ + function easeOutQuint(t, b, c, d) { + return c * ((t = t / d - 1) * t * t * t * t + 1) + b; + } + + /** + * Quintic easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutQuint(t, b, c, d) { + t /= d / 2; + if (t < 1) { + return c / 2 * t * t * t * t * t + b; + } + return c / 2 * ((t -= 2) * t * t * t * t + 2) + b; + } + + /** + * Sinusoidal easing in + * @memberOf fabric.util.ease + */ + function easeInSine(t, b, c, d) { + return -c * Math.cos(t / d * (Math.PI / 2)) + c + b; + } + + /** + * Sinusoidal easing out + * @memberOf fabric.util.ease + */ + function easeOutSine(t, b, c, d) { + return c * Math.sin(t / d * (Math.PI / 2)) + b; + } + + /** + * Sinusoidal easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutSine(t, b, c, d) { + return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b; + } + + /** + * Exponential easing in + * @memberOf fabric.util.ease + */ + function easeInExpo(t, b, c, d) { + return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b; + } + + /** + * Exponential easing out + * @memberOf fabric.util.ease + */ + function easeOutExpo(t, b, c, d) { + return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b; + } + + /** + * Exponential easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutExpo(t, b, c, d) { + if (t === 0) { + return b; + } + if (t === d) { + return b + c; + } + t /= d / 2; + if (t < 1) { + return c / 2 * Math.pow(2, 10 * (t - 1)) + b; + } + return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b; + } + + /** + * Circular easing in + * @memberOf fabric.util.ease + */ + function easeInCirc(t, b, c, d) { + return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b; + } + + /** + * Circular easing out + * @memberOf fabric.util.ease + */ + function easeOutCirc(t, b, c, d) { + return c * Math.sqrt(1 - (t = t / d - 1) * t) + b; + } + + /** + * Circular easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutCirc(t, b, c, d) { + t /= d / 2; + if (t < 1) { + return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b; + } + return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b; + } + + /** + * Elastic easing in + * @memberOf fabric.util.ease + */ + function easeInElastic(t, b, c, d) { + var s = 1.70158, p = 0, a = c; + if (t === 0) { + return b; + } + t /= d; + if (t === 1) { + return b + c; + } + if (!p) { + p = d * 0.3; + } + var opts = normalize(a, c, p, s); + return -elastic(opts, t, d) + b; + } + + /** + * Elastic easing out + * @memberOf fabric.util.ease + */ + function easeOutElastic(t, b, c, d) { + var s = 1.70158, p = 0, a = c; + if (t === 0) { + return b; + } + t /= d; + if (t === 1) { + return b + c; + } + if (!p) { + p = d * 0.3; + } + var opts = normalize(a, c, p, s); + return opts.a * Math.pow(2, -10 * t) * Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) + opts.c + b; + } + + /** + * Elastic easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutElastic(t, b, c, d) { + var s = 1.70158, p = 0, a = c; + if (t === 0) { + return b; + } + t /= d / 2; + if (t === 2) { + return b + c; + } + if (!p) { + p = d * (0.3 * 1.5); + } + var opts = normalize(a, c, p, s); + if (t < 1) { + return -0.5 * elastic(opts, t, d) + b; + } + return opts.a * Math.pow(2, -10 * (t -= 1)) * + Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) * 0.5 + opts.c + b; + } + + /** + * Backwards easing in + * @memberOf fabric.util.ease + */ + function easeInBack(t, b, c, d, s) { + if (s === undefined) { + s = 1.70158; + } + return c * (t /= d) * t * ((s + 1) * t - s) + b; + } + + /** + * Backwards easing out + * @memberOf fabric.util.ease + */ + function easeOutBack(t, b, c, d, s) { + if (s === undefined) { + s = 1.70158; + } + return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b; + } + + /** + * Backwards easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutBack(t, b, c, d, s) { + if (s === undefined) { + s = 1.70158; + } + t /= d / 2; + if (t < 1) { + return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b; + } + return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b; + } + + /** + * Bouncing easing in + * @memberOf fabric.util.ease + */ + function easeInBounce(t, b, c, d) { + return c - easeOutBounce (d - t, 0, c, d) + b; + } + + /** + * Bouncing easing out + * @memberOf fabric.util.ease + */ + function easeOutBounce(t, b, c, d) { + if ((t /= d) < (1 / 2.75)) { + return c * (7.5625 * t * t) + b; + } + 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)) { + return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b; + } + else { + return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b; + } + } + + /** + * Bouncing easing in and out + * @memberOf fabric.util.ease + */ + function easeInOutBounce(t, b, c, d) { + if (t < d / 2) { + return easeInBounce (t * 2, 0, c, d) * 0.5 + b; + } + return easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b; + } + + /** + * Easing functions + * See <a href="http://gizma.com/easing/">Easing Equations by Robert Penner</a> + * @namespace fabric.util.ease + */ + fabric.util.ease = { + + /** + * Quadratic easing in + * @memberOf fabric.util.ease + */ + easeInQuad: function(t, b, c, d) { + return c * (t /= d) * t + b; + }, + + /** + * Quadratic easing out + * @memberOf fabric.util.ease + */ + easeOutQuad: function(t, b, c, d) { + return -c * (t /= d) * (t - 2) + b; + }, + + /** + * Quadratic easing in and out + * @memberOf fabric.util.ease + */ + easeInOutQuad: function(t, b, c, d) { + t /= (d / 2); + if (t < 1) { + return c / 2 * t * t + b; + } + return -c / 2 * ((--t) * (t - 2) - 1) + b; + }, + + /** + * Cubic easing in + * @memberOf fabric.util.ease + */ + easeInCubic: function(t, b, c, d) { + return c * (t /= d) * t * t + b; + }, + + easeOutCubic: easeOutCubic, + easeInOutCubic: easeInOutCubic, + easeInQuart: easeInQuart, + easeOutQuart: easeOutQuart, + easeInOutQuart: easeInOutQuart, + easeInQuint: easeInQuint, + easeOutQuint: easeOutQuint, + easeInOutQuint: easeInOutQuint, + easeInSine: easeInSine, + easeOutSine: easeOutSine, + easeInOutSine: easeInOutSine, + easeInExpo: easeInExpo, + easeOutExpo: easeOutExpo, + easeInOutExpo: easeInOutExpo, + easeInCirc: easeInCirc, + easeOutCirc: easeOutCirc, + easeInOutCirc: easeInOutCirc, + easeInElastic: easeInElastic, + easeOutElastic: easeOutElastic, + easeInOutElastic: easeInOutElastic, + easeInBack: easeInBack, + easeOutBack: easeOutBack, + easeInOutBack: easeInOutBack, + easeInBounce: easeInBounce, + easeOutBounce: easeOutBounce, + easeInOutBounce: easeInOutBounce + }; + +})(); + + +(function(global) { + + 'use strict'; + + /** + * @name fabric + * @namespace + */ + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + clone = fabric.util.object.clone, + toFixed = fabric.util.toFixed, + parseUnit = fabric.util.parseUnit, + multiplyTransformMatrices = fabric.util.multiplyTransformMatrices, + + reAllowedSVGTagNames = /^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i, + reViewBoxTagNames = /^(symbol|image|marker|pattern|view|svg)$/i, + reNotAllowedAncestors = /^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i, + reAllowedParents = /^(symbol|g|a|svg)$/i, + + attributesMap = { + 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', + opacity: 'opacity' + }, + + colorAttributes = { + stroke: 'strokeOpacity', + fill: 'fillOpacity' + }; + + fabric.cssRules = { }; + fabric.gradientDefs = { }; + + function normalizeAttr(attr) { + // transform attribute names + if (attr in attributesMap) { + return attributesMap[attr]; + } + return attr; + } + + function normalizeValue(attr, value, parentAttributes, fontSize) { + var isArray = Object.prototype.toString.call(value) === '[object Array]', + parsed; + + if ((attr === 'fill' || attr === 'stroke') && value === 'none') { + value = ''; + } + else if (attr === 'strokeDashArray') { + if (value === 'none') { + value = null; + } + else { + value = value.replace(/,/g, ' ').split(/\s+/).map(function(n) { + return parseFloat(n); + }); + } + } + else if (attr === 'transformMatrix') { + if (parentAttributes && parentAttributes.transformMatrix) { + value = multiplyTransformMatrices( + parentAttributes.transformMatrix, fabric.parseTransformAttribute(value)); + } + else { + value = fabric.parseTransformAttribute(value); + } + } + else if (attr === 'visible') { + value = (value === 'none' || value === 'hidden') ? false : true; + // display=none on parent element always takes precedence over child element + if (parentAttributes && parentAttributes.visible === false) { + value = false; + } + } + else if (attr === 'opacity') { + value = parseFloat(value); + if (parentAttributes && typeof parentAttributes.opacity !== 'undefined') { + value *= parentAttributes.opacity; + } + } + else if (attr === 'originX' /* text-anchor */) { + value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center'; + } + else { + parsed = isArray ? value.map(parseUnit) : parseUnit(value, fontSize); + } + + return (!isArray && isNaN(parsed) ? value : parsed); + } + + /** + * @private + * @param {Object} attributes Array of attributes to parse + */ + function _setStrokeFillOpacity(attributes) { + for (var attr in colorAttributes) { + + if (typeof attributes[colorAttributes[attr]] === 'undefined' || attributes[attr] === '') { + continue; + } + + if (typeof attributes[attr] === 'undefined') { + if (!fabric.Object.prototype[attr]) { + continue; + } + attributes[attr] = fabric.Object.prototype[attr]; + } + + if (attributes[attr].indexOf('url(') === 0) { + continue; + } + + var color = new fabric.Color(attributes[attr]); + attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba(); + } + return attributes; + } + + /** + * @private + */ + function _getMultipleNodes(doc, nodeNames) { + var nodeName, nodeArray = [], nodeList; + for (var i = 0; i < nodeNames.length; i++) { + nodeName = nodeNames[i]; + nodeList = doc.getElementsByTagName(nodeName); + nodeArray = nodeArray.concat(Array.prototype.slice.call(nodeList)); + } + return nodeArray; + } + + /** + * Parses "transform" attribute, returning an array of values + * @static + * @function + * @memberOf fabric + * @param {String} attributeValue String containing attribute value + * @return {Array} Array of 6 elements representing transformation matrix + */ + fabric.parseTransformAttribute = (function() { + function rotateMatrix(matrix, args) { + var cos = Math.cos(args[0]), sin = Math.sin(args[0]), + x = 0, y = 0; + if (args.length === 3) { + x = args[1]; + y = args[2]; + } + + matrix[0] = cos; + matrix[1] = sin; + matrix[2] = -sin; + matrix[3] = cos; + matrix[4] = x - (cos * x - sin * y); + matrix[5] = y - (sin * x + cos * y); + } + + function scaleMatrix(matrix, args) { + var multiplierX = args[0], + multiplierY = (args.length === 2) ? args[1] : args[0]; + + matrix[0] = multiplierX; + matrix[3] = multiplierY; + } + + function skewMatrix(matrix, args, pos) { + matrix[pos] = Math.tan(fabric.util.degreesToRadians(args[0])); + } + + function translateMatrix(matrix, args) { + matrix[4] = args[0]; + if (args.length === 2) { + matrix[5] = args[1]; + } + } + + // identity matrix + var iMatrix = [ + 1, // a + 0, // b + 0, // c + 1, // d + 0, // e + 0 // f + ], + + // == begin transform regexp + number = fabric.reNum, + + commaWsp = '(?:\\s+,?\\s*|,\\s*)', + + skewX = '(?:(skewX)\\s*\\(\\s*(' + number + ')\\s*\\))', + + skewY = '(?:(skewY)\\s*\\(\\s*(' + number + ')\\s*\\))', + + rotate = '(?:(rotate)\\s*\\(\\s*(' + number + ')(?:' + + commaWsp + '(' + number + ')' + + commaWsp + '(' + number + '))?\\s*\\))', + + scale = '(?:(scale)\\s*\\(\\s*(' + number + ')(?:' + + commaWsp + '(' + number + '))?\\s*\\))', + + translate = '(?:(translate)\\s*\\(\\s*(' + number + ')(?:' + + commaWsp + '(' + number + '))?\\s*\\))', + + matrix = '(?:(matrix)\\s*\\(\\s*' + + '(' + number + ')' + commaWsp + + '(' + number + ')' + commaWsp + + '(' + number + ')' + commaWsp + + '(' + number + ')' + commaWsp + + '(' + number + ')' + commaWsp + + '(' + number + ')' + + '\\s*\\))', + + transform = '(?:' + + matrix + '|' + + translate + '|' + + scale + '|' + + rotate + '|' + + skewX + '|' + + skewY + + ')', + + transforms = '(?:' + transform + '(?:' + commaWsp + '*' + transform + ')*' + ')', + + transformList = '^\\s*(?:' + transforms + '?)\\s*$', + + // http://www.w3.org/TR/SVG/coords.html#TransformAttribute + reTransformList = new RegExp(transformList), + // == end transform regexp + + reTransform = new RegExp(transform, 'g'); + + return function(attributeValue) { + + // start with identity matrix + var matrix = iMatrix.concat(), + matrices = []; + + // return if no argument was given or + // an argument does not match transform attribute regexp + if (!attributeValue || (attributeValue && !reTransformList.test(attributeValue))) { + return matrix; + } + + attributeValue.replace(reTransform, function(match) { + + var m = new RegExp(transform).exec(match).filter(function (match) { + // match !== '' && match != null + return (!!match); + }), + operation = m[1], + args = m.slice(2).map(parseFloat); + + switch (operation) { + case 'translate': + translateMatrix(matrix, args); + break; + case 'rotate': + args[0] = fabric.util.degreesToRadians(args[0]); + rotateMatrix(matrix, args); + break; + case 'scale': + scaleMatrix(matrix, args); + break; + case 'skewX': + skewMatrix(matrix, args, 2); + break; + case 'skewY': + skewMatrix(matrix, args, 1); + break; + case 'matrix': + matrix = args; + break; + } + + // snapshot current matrix into matrices array + matrices.push(matrix.concat()); + // reset + matrix = iMatrix.concat(); + }); + + var combinedMatrix = matrices[0]; + while (matrices.length > 1) { + matrices.shift(); + combinedMatrix = fabric.util.multiplyTransformMatrices(combinedMatrix, matrices[0]); + } + return combinedMatrix; + }; + })(); + + /** + * @private + */ + function parseStyleString(style, oStyle) { + var attr, value; + style.replace(/;\s*$/, '').split(';').forEach(function (chunk) { + var pair = chunk.split(':'); + + attr = pair[0].trim().toLowerCase(); + value = pair[1].trim(); + + oStyle[attr] = value; + }); + } + + /** + * @private + */ + function parseStyleObject(style, oStyle) { + var attr, value; + for (var prop in style) { + if (typeof style[prop] === 'undefined') { + continue; + } + + attr = prop.toLowerCase(); + value = style[prop]; + + oStyle[attr] = value; + } + } + + /** + * @private + */ + function getGlobalStylesForElement(element, svgUid) { + var styles = { }; + for (var rule in fabric.cssRules[svgUid]) { + if (elementMatchesRule(element, rule.split(' '))) { + for (var property in fabric.cssRules[svgUid][rule]) { + styles[property] = fabric.cssRules[svgUid][rule][property]; + } + } + } + return styles; + } + + /** + * @private + */ + function elementMatchesRule(element, selectors) { + var firstMatching, parentMatching = true; + //start from rightmost selector. + firstMatching = selectorMatches(element, selectors.pop()); + if (firstMatching && selectors.length) { + parentMatching = doesSomeParentMatch(element, selectors); + } + return firstMatching && parentMatching && (selectors.length === 0); + } + + function doesSomeParentMatch(element, selectors) { + var selector, parentMatching = true; + while (element.parentNode && element.parentNode.nodeType === 1 && selectors.length) { + if (parentMatching) { + selector = selectors.pop(); + } + element = element.parentNode; + parentMatching = selectorMatches(element, selector); + } + return selectors.length === 0; + } + + /** + * @private + */ + function selectorMatches(element, selector) { + var nodeName = element.nodeName, + classNames = element.getAttribute('class'), + id = element.getAttribute('id'), matcher; + // i check if a selector matches slicing away part from it. + // if i get empty string i should match + matcher = new RegExp('^' + nodeName, 'i'); + selector = selector.replace(matcher, ''); + if (id && selector.length) { + matcher = new RegExp('#' + id + '(?![a-zA-Z\\-]+)', 'i'); + selector = selector.replace(matcher, ''); + } + if (classNames && selector.length) { + classNames = classNames.split(' '); + for (var i = classNames.length; i--;) { + matcher = new RegExp('\\.' + classNames[i] + '(?![a-zA-Z\\-]+)', 'i'); + selector = selector.replace(matcher, ''); + } + } + return selector.length === 0; + } + + /** + * @private + * to support IE8 missing getElementById on SVGdocument + */ + function elementById(doc, id) { + var el; + doc.getElementById && (el = doc.getElementById(id)); + if (el) { + return el; + } + var node, i, nodelist = doc.getElementsByTagName('*'); + for (i = 0; i < nodelist.length; i++) { + node = nodelist[i]; + if (id === node.getAttribute('id')) { + return node; + } + } + } + + /** + * @private + */ + function parseUseDirectives(doc) { + var nodelist = _getMultipleNodes(doc, ['use', 'svg:use']), i = 0; + + while (nodelist.length && i < nodelist.length) { + var el = nodelist[i], + xlink = el.getAttribute('xlink:href').substr(1), + x = el.getAttribute('x') || 0, + y = el.getAttribute('y') || 0, + el2 = elementById(doc, xlink).cloneNode(true), + currentTrans = (el2.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')', + parentNode, oldLength = nodelist.length, attr, j, attrs, l; + + applyViewboxTransform(el2); + if (/^svg$/i.test(el2.nodeName)) { + var el3 = el2.ownerDocument.createElement('g'); + for (j = 0, attrs = el2.attributes, l = attrs.length; j < l; j++) { + attr = attrs.item(j); + el3.setAttribute(attr.nodeName, attr.nodeValue); + } + // el2.firstChild != null + while (el2.firstChild) { + el3.appendChild(el2.firstChild); + } + el2 = el3; + } + + for (j = 0, attrs = el.attributes, l = attrs.length; j < l; j++) { + attr = attrs.item(j); + if (attr.nodeName === 'x' || attr.nodeName === 'y' || attr.nodeName === 'xlink:href') { + continue; + } + + if (attr.nodeName === 'transform') { + currentTrans = attr.nodeValue + ' ' + currentTrans; + } + else { + el2.setAttribute(attr.nodeName, attr.nodeValue); + } + } + + el2.setAttribute('transform', currentTrans); + el2.setAttribute('instantiated_by_use', '1'); + el2.removeAttribute('id'); + parentNode = el.parentNode; + parentNode.replaceChild(el2, el); + // some browsers do not shorten nodelist after replaceChild (IE8) + if (nodelist.length === oldLength) { + i++; + } + } + } + + // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute + // matches, e.g.: +14.56e-12, etc. + var reViewBoxAttrValue = new RegExp( + '^' + + '\\s*(' + fabric.reNum + '+)\\s*,?' + + '\\s*(' + fabric.reNum + '+)\\s*,?' + + '\\s*(' + fabric.reNum + '+)\\s*,?' + + '\\s*(' + fabric.reNum + '+)\\s*' + + '$' + ); + + /** + * Add a <g> element that envelop all child elements and makes the viewbox transformMatrix descend on all elements + */ + function applyViewboxTransform(element) { + + var viewBoxAttr = element.getAttribute('viewBox'), + scaleX = 1, + scaleY = 1, + minX = 0, + minY = 0, + viewBoxWidth, viewBoxHeight, matrix, el, + widthAttr = element.getAttribute('width'), + heightAttr = element.getAttribute('height'), + x = element.getAttribute('x') || 0, + y = element.getAttribute('y') || 0, + preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '', + missingViewBox = (!viewBoxAttr || !reViewBoxTagNames.test(element.nodeName) + || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue))), + missingDimAttr = (!widthAttr || !heightAttr || widthAttr === '100%' || heightAttr === '100%'), + toBeParsed = missingViewBox && missingDimAttr, + parsedDim = { }, translateMatrix = ''; + + parsedDim.width = 0; + parsedDim.height = 0; + parsedDim.toBeParsed = toBeParsed; + + if (toBeParsed) { + return parsedDim; + } + + if (missingViewBox) { + parsedDim.width = parseUnit(widthAttr); + parsedDim.height = parseUnit(heightAttr); + return parsedDim; + } + + minX = -parseFloat(viewBoxAttr[1]); + minY = -parseFloat(viewBoxAttr[2]); + viewBoxWidth = parseFloat(viewBoxAttr[3]); + viewBoxHeight = parseFloat(viewBoxAttr[4]); + + if (!missingDimAttr) { + parsedDim.width = parseUnit(widthAttr); + parsedDim.height = parseUnit(heightAttr); + scaleX = parsedDim.width / viewBoxWidth; + scaleY = parsedDim.height / viewBoxHeight; + } + else { + parsedDim.width = viewBoxWidth; + parsedDim.height = viewBoxHeight; + } + + // default is to preserve aspect ratio + preserveAspectRatio = fabric.util.parsePreserveAspectRatioAttribute(preserveAspectRatio); + if (preserveAspectRatio.alignX !== 'none') { + //translate all container for the effect of Mid, Min, Max + scaleY = scaleX = (scaleX > scaleY ? scaleY : scaleX); + } + + if (scaleX === 1 && scaleY === 1 && minX === 0 && minY === 0 && x === 0 && y === 0) { + return parsedDim; + } + + if (x || y) { + translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') '; + } + + matrix = translateMatrix + ' matrix(' + scaleX + + ' 0' + + ' 0 ' + + scaleY + ' ' + + (minX * scaleX) + ' ' + + (minY * scaleY) + ') '; + + if (element.nodeName === 'svg') { + el = element.ownerDocument.createElement('g'); + // element.firstChild != null + while (element.firstChild) { + el.appendChild(element.firstChild); + } + element.appendChild(el); + } + else { + el = element; + matrix = el.getAttribute('transform') + matrix; + } + + el.setAttribute('transform', matrix); + return parsedDim; + } + + function hasAncestorWithNodeName(element, nodeName) { + while (element && (element = element.parentNode)) { + if (element.nodeName && nodeName.test(element.nodeName.replace('svg:', '')) + && !element.getAttribute('instantiated_by_use')) { + return true; + } + } + return false; + } + + /** + * Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback + * @static + * @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} [reviver] Method for further parsing of SVG elements, called after each fabric object created. + * @param {Object} [parsingOptions] options for parsing document + * @param {String} [parsingOptions.crossOrigin] crossOrigin settings + */ + fabric.parseSVGDocument = function(doc, callback, reviver, parsingOptions) { + if (!doc) { + return; + } + + parseUseDirectives(doc); + + var svgUid = fabric.Object.__uid++, + options = applyViewboxTransform(doc), + descendants = fabric.util.toArray(doc.getElementsByTagName('*')); + options.crossOrigin = parsingOptions && parsingOptions.crossOrigin; + options.svgUid = svgUid; + + if (descendants.length === 0 && fabric.isLikelyNode) { + // 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 = []; + for (var i = 0, len = descendants.length; i < len; i++) { + arr[i] = descendants[i]; + } + descendants = arr; + } + + var elements = descendants.filter(function(el) { + applyViewboxTransform(el); + return reAllowedSVGTagNames.test(el.nodeName.replace('svg:', '')) && + !hasAncestorWithNodeName(el, reNotAllowedAncestors); // http://www.w3.org/TR/SVG/struct.html#DefsElement + }); + + if (!elements || (elements && !elements.length)) { + callback && callback([], {}); + return; + } + + fabric.gradientDefs[svgUid] = fabric.getGradientDefs(doc); + fabric.cssRules[svgUid] = fabric.getCSSRules(doc); + // Precedence of rules: style > class > attribute + fabric.parseElements(elements, function(instances) { + if (callback) { + callback(instances, options); + } + }, clone(options), reviver, parsingOptions); + }; + + 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*(' + + fabric.reNum + + '(?:px|cm|mm|em|pt|pc|in)*)(?:\\/(normal|' + fabric.reNum + '))?\\s+(.*)'); + + extend(fabric, { + /** + * Parses a short font declaration, building adding its properties to a style object + * @static + * @function + * @memberOf fabric + * @param {String} value font declaration + * @param {Object} oStyle definition + */ + parseFontDeclaration: function(value, oStyle) { + var match = value.match(reFontDeclaration); + + if (!match) { + return; + } + var fontStyle = match[1], + // font variant is not used + // fontVariant = match[2], + fontWeight = match[3], + fontSize = match[4], + lineHeight = match[5], + fontFamily = match[6]; + + if (fontStyle) { + oStyle.fontStyle = fontStyle; + } + if (fontWeight) { + oStyle.fontWeight = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight); + } + if (fontSize) { + oStyle.fontSize = parseUnit(fontSize); + } + if (fontFamily) { + oStyle.fontFamily = fontFamily; + } + if (lineHeight) { + oStyle.lineHeight = lineHeight === 'normal' ? 1 : lineHeight; + } + }, + + /** + * Parses an SVG document, returning all of the gradient declarations found in it + * @static + * @function + * @memberOf fabric + * @param {SVGDocument} doc SVG document to parse + * @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition element + */ + getGradientDefs: function(doc) { + var tagArray = [ + 'linearGradient', + 'radialGradient', + 'svg:linearGradient', + 'svg:radialGradient'], + elList = _getMultipleNodes(doc, tagArray), + el, j = 0, id, xlink, + gradientDefs = { }, idsToXlinkMap = { }; + + 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); + } + } + return gradientDefs; + }, + + /** + * Returns an object of attributes' name/value, given element and an array of attribute names; + * Parses parent "g" nodes recursively upwards. + * @static + * @memberOf fabric + * @param {DOMElement} element Element to parse + * @param {Array} attributes Array of attributes to parse + * @return {Object} object containing parsed attributes' names/values + */ + parseAttributes: function(element, attributes, svgUid) { + + if (!element) { + return; + } + + var value, + parentAttributes = { }, + fontSize; + + if (typeof svgUid === 'undefined') { + svgUid = element.getAttribute('svgUid'); + } + // if there's a parent container (`g` or `a` or `symbol` node), parse its attributes recursively upwards + if (element.parentNode && reAllowedParents.test(element.parentNode.nodeName)) { + parentAttributes = fabric.parseAttributes(element.parentNode, attributes, svgUid); + } + fontSize = (parentAttributes && parentAttributes.fontSize ) || + element.getAttribute('font-size') || fabric.Text.DEFAULT_SVG_FONT_SIZE; + + var ownAttributes = attributes.reduce(function(memo, attr) { + value = element.getAttribute(attr); + if (value) { // eslint-disable-line + memo[attr] = value; + } + return memo; + }, { }); + // add values parsed from style, which take precedence over attributes + // (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes) + ownAttributes = extend(ownAttributes, + extend(getGlobalStylesForElement(element, svgUid), fabric.parseStyleAttribute(element))); + + var normalizedAttr, normalizedValue, normalizedStyle = {}; + for (var attr in ownAttributes) { + normalizedAttr = normalizeAttr(attr); + normalizedValue = normalizeValue(normalizedAttr, ownAttributes[attr], parentAttributes, fontSize); + normalizedStyle[normalizedAttr] = normalizedValue; + } + if (normalizedStyle && normalizedStyle.font) { + fabric.parseFontDeclaration(normalizedStyle.font, normalizedStyle); + } + var mergedAttrs = extend(parentAttributes, normalizedStyle); + return reAllowedParents.test(element.nodeName) ? mergedAttrs : _setStrokeFillOpacity(mergedAttrs); + }, + + /** + * Transforms an array of svg elements to corresponding fabric.* instances + * @static + * @memberOf fabric + * @param {Array} elements Array of elements to parse + * @param {Function} callback Being passed an array of fabric instances (transformed from SVG elements) + * @param {Object} [options] Options object + * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created. + */ + parseElements: function(elements, callback, options, reviver, parsingOptions) { + new fabric.ElementsParser(elements, callback, options, reviver, parsingOptions).parse(); + }, + + /** + * Parses "style" attribute, retuning an object with values + * @static + * @memberOf fabric + * @param {SVGElement} element Element to parse + * @return {Object} Objects with values parsed from style attribute of an element + */ + parseStyleAttribute: function(element) { + var oStyle = { }, + style = element.getAttribute('style'); + + if (!style) { + return oStyle; + } + + if (typeof style === 'string') { + parseStyleString(style, oStyle); + } + else { + parseStyleObject(style, oStyle); + } + + return oStyle; + }, + + /** + * Parses "points" attribute, returning an array of values + * @static + * @memberOf fabric + * @param {String} points points attribute string + * @return {Array} array of points + */ + parsePointsAttribute: function(points) { + + // points attribute is required and must not be empty + if (!points) { + return null; + } + + // replace commas with whitespace and remove bookending whitespace + points = points.replace(/,/g, ' ').trim(); + + points = points.split(/\s+/); + var parsedPoints = [], i, len; + + i = 0; + len = points.length; + for (; i < len; i += 2) { + parsedPoints.push({ + x: parseFloat(points[i]), + y: parseFloat(points[i + 1]) + }); + } + + // odd number of points is an error + // if (parsedPoints.length % 2 !== 0) { + // return null; + // } + + return parsedPoints; + }, + + /** + * Returns CSS rules for a given SVG document + * @static + * @function + * @memberOf fabric + * @param {SVGDocument} doc SVG document to parse + * @return {Object} CSS rules of this document + */ + getCSSRules: function(doc) { + var styles = doc.getElementsByTagName('style'), + allRules = { }, rules; + + // very crude parsing of style contents + for (var i = 0, len = styles.length; i < len; i++) { + // IE9 doesn't support textContent, but provides text instead. + var styleContents = styles[i].textContent || styles[i].text; + + // remove comments + styleContents = styleContents.replace(/\/\*[\s\S]*?\*\//g, ''); + if (styleContents.trim() === '') { + continue; + } + rules = styleContents.match(/[^{]*\{[\s\S]*?\}/g); + rules = rules.map(function(rule) { return rule.trim(); }); + rules.forEach(function(rule) { + + var match = rule.match(/([\s\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*/), + property = pair[0], + value = pair[1]; + ruleObj[property] = value; + } + rule = match[1]; + rule.split(',').forEach(function(_rule) { + _rule = _rule.replace(/^svg/i, '').trim(); + if (_rule === '') { + return; + } + if (allRules[_rule]) { + fabric.util.object.extend(allRules[_rule], ruleObj); + } + else { + allRules[_rule] = fabric.util.object.clone(ruleObj); + } + }); + }); + } + return allRules; + }, + + /** + * 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 + * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created. + * @param {Object} [options] Object containing options for parsing + * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources + */ + loadSVGFromURL: function(url, callback, reviver, options) { + + url = url.replace(/^\n\s*/, '').trim(); + new fabric.util.request(url, { + method: 'get', + onComplete: onComplete + }); + + function onComplete(r) { + + var xml = r.responseXML; + if (xml && !xml.documentElement && fabric.window.ActiveXObject && r.responseText) { + xml = new ActiveXObject('Microsoft.XMLDOM'); + xml.async = 'false'; + //IE chokes on DOCTYPE + xml.loadXML(r.responseText.replace(/<!DOCTYPE[\s\S]*?(\[[\s\S]*\])*?>/i, '')); + } + if (!xml || !xml.documentElement) { + callback && callback(null); + } + + fabric.parseSVGDocument(xml.documentElement, function (results, _options) { + callback && callback(results, _options); + }, reviver, options); + } + }, + + /** + * Takes string corresponding to an SVG document, and parses it into a set of fabric objects + * @memberOf fabric + * @param {String} string + * @param {Function} callback + * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created. + * @param {Object} [options] Object containing options for parsing + * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources + */ + loadSVGFromString: function(string, callback, reviver, options) { + string = string.trim(); + var doc; + if (typeof DOMParser !== 'undefined') { + var parser = new DOMParser(); + if (parser && parser.parseFromString) { + doc = parser.parseFromString(string, 'text/xml'); + } + } + else if (fabric.window.ActiveXObject) { + doc = new ActiveXObject('Microsoft.XMLDOM'); + doc.async = 'false'; + // IE chokes on DOCTYPE + doc.loadXML(string.replace(/<!DOCTYPE[\s\S]*?(\[[\s\S]*\])*?>/i, '')); + } + + fabric.parseSVGDocument(doc.documentElement, function (results, _options) { + callback(results, _options); + }, reviver, options); + } + }); + +})(typeof exports !== 'undefined' ? exports : this); + + +fabric.ElementsParser = function(elements, callback, options, reviver, parsingOptions) { + this.elements = elements; + this.callback = callback; + this.options = options; + this.reviver = reviver; + this.svgUid = (options && options.svgUid) || 0; + this.parsingOptions = parsingOptions; +}; + +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 i = 0, len = this.elements.length; i < len; i++) { + this.elements[i].setAttribute('svgUid', this.svgUid); + (function(_obj, i) { + setTimeout(function() { + _obj.createObject(_obj.elements[i], i); + }, 0); + })(this, i); + } +}; + +fabric.ElementsParser.prototype.createObject = function(el, index) { + var klass = fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))]; + if (klass && klass.fromElement) { + try { + this._createObject(klass, el, index); + } + catch (err) { + fabric.log(err); + } + } + else { + this.checkIfDone(); + } +}; + +fabric.ElementsParser.prototype._createObject = function(klass, el, index) { + if (klass.async) { + klass.fromElement(el, this.createCallback(index, el), this.options); + } + else { + var obj = klass.fromElement(el, this.options); + this.resolveGradient(obj, 'fill'); + this.resolveGradient(obj, 'stroke'); + this.reviver && this.reviver(el, obj); + this.instances[index] = obj; + this.checkIfDone(); + } +}; + +fabric.ElementsParser.prototype.createCallback = function(index, el) { + var _this = this; + return function(obj) { + _this.resolveGradient(obj, 'fill'); + _this.resolveGradient(obj, 'stroke'); + _this.reviver && _this.reviver(el, obj); + _this.instances[index] = obj; + _this.checkIfDone(); + }; +}; + +fabric.ElementsParser.prototype.resolveGradient = function(obj, property) { + + var instanceFillValue = obj.get(property); + if (!(/^url\(/).test(instanceFillValue)) { + return; + } + var gradientId = instanceFillValue.slice(5, instanceFillValue.length - 1); + if (fabric.gradientDefs[this.svgUid][gradientId]) { + obj.set(property, + fabric.Gradient.fromElement(fabric.gradientDefs[this.svgUid][gradientId], obj)); + } +}; + +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); + } +}; + + +(function(global) { + + 'use strict'; + + /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */ + + var fabric = global.fabric || (global.fabric = { }); + + if (fabric.Point) { + fabric.warn('fabric.Point is already defined'); + return; + } + + fabric.Point = Point; + + /** + * Point class + * @class fabric.Point + * @memberOf fabric + * @constructor + * @param {Number} x + * @param {Number} y + * @return {fabric.Point} thisArg + */ + function Point(x, y) { + this.x = x; + this.y = y; + } + + Point.prototype = /** @lends fabric.Point.prototype */ { + + type: 'point', + + constructor: Point, + + /** + * Adds another point to this one and returns another one + * @param {fabric.Point} that + * @return {fabric.Point} new Point instance with added values + */ + add: function (that) { + return new Point(this.x + that.x, this.y + that.y); + }, + + /** + * Adds another point to this one + * @param {fabric.Point} that + * @return {fabric.Point} thisArg + * @chainable + */ + addEquals: function (that) { + this.x += that.x; + this.y += that.y; + return this; + }, + + /** + * Adds value to this point and returns a new one + * @param {Number} scalar + * @return {fabric.Point} new Point with added value + */ + scalarAdd: function (scalar) { + return new Point(this.x + scalar, this.y + scalar); + }, + + /** + * Adds value to this point + * @param {Number} scalar + * @return {fabric.Point} thisArg + * @chainable + */ + scalarAddEquals: function (scalar) { + this.x += scalar; + this.y += scalar; + return this; + }, + + /** + * Subtracts another point from this point and returns a new one + * @param {fabric.Point} that + * @return {fabric.Point} new Point object with subtracted values + */ + subtract: function (that) { + return new Point(this.x - that.x, this.y - that.y); + }, + + /** + * Subtracts another point from this point + * @param {fabric.Point} that + * @return {fabric.Point} thisArg + * @chainable + */ + subtractEquals: function (that) { + this.x -= that.x; + this.y -= that.y; + return this; + }, + + /** + * Subtracts value from this point and returns a new one + * @param {Number} scalar + * @return {fabric.Point} + */ + scalarSubtract: function (scalar) { + return new Point(this.x - scalar, this.y - scalar); + }, + + /** + * Subtracts value from this point + * @param {Number} scalar + * @return {fabric.Point} thisArg + * @chainable + */ + scalarSubtractEquals: function (scalar) { + this.x -= scalar; + this.y -= scalar; + return this; + }, + + /** + * Miltiplies this point by a value and returns a new one + * TODO: rename in scalarMultiply in 2.0 + * @param {Number} scalar + * @return {fabric.Point} + */ + multiply: function (scalar) { + return new Point(this.x * scalar, this.y * scalar); + }, + + /** + * Miltiplies this point by a value + * TODO: rename in scalarMultiplyEquals in 2.0 + * @param {Number} scalar + * @return {fabric.Point} thisArg + * @chainable + */ + multiplyEquals: function (scalar) { + this.x *= scalar; + this.y *= scalar; + return this; + }, + + /** + * Divides this point by a value and returns a new one + * TODO: rename in scalarDivide in 2.0 + * @param {Number} scalar + * @return {fabric.Point} + */ + divide: function (scalar) { + return new Point(this.x / scalar, this.y / scalar); + }, + + /** + * Divides this point by a value + * TODO: rename in scalarDivideEquals in 2.0 + * @param {Number} scalar + * @return {fabric.Point} thisArg + * @chainable + */ + divideEquals: function (scalar) { + this.x /= scalar; + this.y /= scalar; + return this; + }, + + /** + * Returns true if this point is equal to another one + * @param {fabric.Point} that + * @return {Boolean} + */ + eq: function (that) { + return (this.x === that.x && this.y === that.y); + }, + + /** + * Returns true if this point is less than another one + * @param {fabric.Point} that + * @return {Boolean} + */ + lt: function (that) { + return (this.x < that.x && this.y < that.y); + }, + + /** + * Returns true if this point is less than or equal to another one + * @param {fabric.Point} that + * @return {Boolean} + */ + lte: function (that) { + return (this.x <= that.x && this.y <= that.y); + }, + + /** + + * Returns true if this point is greater another one + * @param {fabric.Point} that + * @return {Boolean} + */ + gt: function (that) { + return (this.x > that.x && this.y > that.y); + }, + + /** + * Returns true if this point is greater than or equal to another one + * @param {fabric.Point} that + * @return {Boolean} + */ + gte: function (that) { + return (this.x >= that.x && this.y >= that.y); + }, + + /** + * Returns new point which is the result of linear interpolation with this one and another one + * @param {fabric.Point} that + * @param {Number} t , position of interpolation, between 0 and 1 default 0.5 + * @return {fabric.Point} + */ + lerp: function (that, t) { + if (typeof t === 'undefined') { + t = 0.5; + } + t = Math.max(Math.min(1, t), 0); + return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t); + }, + + /** + * Returns distance from this point and another one + * @param {fabric.Point} that + * @return {Number} + */ + distanceFrom: function (that) { + var dx = this.x - that.x, + dy = this.y - that.y; + return Math.sqrt(dx * dx + dy * dy); + }, + + /** + * Returns the point between this point and another one + * @param {fabric.Point} that + * @return {fabric.Point} + */ + midPointFrom: function (that) { + return this.lerp(that); + }, + + /** + * Returns a new point which is the min of this and another one + * @param {fabric.Point} that + * @return {fabric.Point} + */ + min: function (that) { + return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y)); + }, + + /** + * Returns a new point which is the max of this and another one + * @param {fabric.Point} that + * @return {fabric.Point} + */ + max: function (that) { + return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y)); + }, + + /** + * Returns string representation of this point + * @return {String} + */ + toString: function () { + return this.x + ',' + this.y; + }, + + /** + * Sets x/y of this point + * @param {Number} x + * @param {Number} y + * @chainable + */ + setXY: function (x, y) { + this.x = x; + this.y = y; + return this; + }, + + /** + * Sets x of this point + * @param {Number} x + * @chainable + */ + setX: function (x) { + this.x = x; + return this; + }, + + /** + * Sets y of this point + * @param {Number} y + * @chainable + */ + setY: function (y) { + this.y = y; + return this; + }, + + /** + * Sets x/y of this point from another point + * @param {fabric.Point} that + * @chainable + */ + setFromPoint: function (that) { + this.x = that.x; + this.y = that.y; + return this; + }, + + /** + * Swaps x/y of this point and another point + * @param {fabric.Point} that + */ + swap: function (that) { + var x = this.x, + y = this.y; + this.x = that.x; + this.y = that.y; + that.x = x; + that.y = y; + }, + + /** + * return a cloned instance of the point + * @return {fabric.Point} + */ + clone: function () { + return new Point(this.x, this.y); + } + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */ + var fabric = global.fabric || (global.fabric = { }); + + if (fabric.Intersection) { + fabric.warn('fabric.Intersection is already defined'); + return; + } + + /** + * Intersection class + * @class fabric.Intersection + * @memberOf fabric + * @constructor + */ + function Intersection(status) { + this.status = status; + this.points = []; + } + + fabric.Intersection = Intersection; + + fabric.Intersection.prototype = /** @lends fabric.Intersection.prototype */ { + + constructor: Intersection, + + /** + * Appends a point to intersection + * @param {fabric.Point} point + * @return {fabric.Intersection} thisArg + * @chainable + */ + appendPoint: function (point) { + this.points.push(point); + return this; + }, + + /** + * Appends points to intersection + * @param {Array} points + * @return {fabric.Intersection} thisArg + * @chainable + */ + appendPoints: function (points) { + this.points = this.points.concat(points); + return this; + } + }; + + /** + * Checks if one line intersects another + * TODO: rename in intersectSegmentSegment + * @static + * @param {fabric.Point} a1 + * @param {fabric.Point} a2 + * @param {fabric.Point} b1 + * @param {fabric.Point} b2 + * @return {fabric.Intersection} + */ + fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) { + var result, + uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x), + ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x), + uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y); + if (uB !== 0) { + var ua = uaT / uB, + ub = ubT / uB; + if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) { + result = new Intersection('Intersection'); + result.appendPoint(new fabric.Point(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y))); + } + else { + result = new Intersection(); + } + } + else { + if (uaT === 0 || ubT === 0) { + result = new Intersection('Coincident'); + } + else { + result = new Intersection('Parallel'); + } + } + return result; + }; + + /** + * Checks if line intersects polygon + * TODO: rename in intersectSegmentPolygon + * fix detection of coincident + * @static + * @param {fabric.Point} a1 + * @param {fabric.Point} a2 + * @param {Array} points + * @return {fabric.Intersection} + */ + 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); + + result.appendPoints(inter.points); + } + if (result.points.length > 0) { + result.status = 'Intersection'; + } + return result; + }; + + /** + * Checks if polygon intersects another polygon + * @static + * @param {Array} points1 + * @param {Array} points2 + * @return {fabric.Intersection} + */ + fabric.Intersection.intersectPolygonPolygon = function (points1, points2) { + var result = new Intersection(), + length = points1.length; + + for (var i = 0; i < length; i++) { + var a1 = points1[i], + a2 = points1[(i + 1) % length], + inter = Intersection.intersectLinePolygon(a1, a2, points2); + + result.appendPoints(inter.points); + } + if (result.points.length > 0) { + result.status = 'Intersection'; + } + return result; + }; + + /** + * Checks if polygon intersects rectangle + * @static + * @param {Array} points + * @param {fabric.Point} r1 + * @param {fabric.Point} r2 + * @return {fabric.Intersection} + */ + fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) { + var min = r1.min(r2), + max = r1.max(r2), + topRight = new fabric.Point(max.x, min.y), + bottomLeft = new fabric.Point(min.x, max.y), + inter1 = Intersection.intersectLinePolygon(min, topRight, points), + inter2 = Intersection.intersectLinePolygon(topRight, max, points), + inter3 = Intersection.intersectLinePolygon(max, bottomLeft, points), + inter4 = Intersection.intersectLinePolygon(bottomLeft, min, points), + result = new Intersection(); + + result.appendPoints(inter1.points); + result.appendPoints(inter2.points); + result.appendPoints(inter3.points); + result.appendPoints(inter4.points); + + if (result.points.length > 0) { + result.status = 'Intersection'; + } + return result; + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }); + + if (fabric.Color) { + fabric.warn('fabric.Color is already defined.'); + return; + } + + /** + * Color class + * The purpose of {@link fabric.Color} is to abstract and encapsulate common color operations; + * {@link fabric.Color} is a constructor and creates instances of {@link fabric.Color} objects. + * + * @class fabric.Color + * @param {String} color optional in hex or rgb(a) or hsl format or from known color list + * @return {fabric.Color} thisArg + * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#colors} + */ + function Color(color) { + if (!color) { + this.setSource([0, 0, 0, 1]); + } + else { + this._tryParsingColor(color); + } + } + + fabric.Color = Color; + + fabric.Color.prototype = /** @lends fabric.Color.prototype */ { + + /** + * @private + * @param {String|Array} color Color value to parse + */ + _tryParsingColor: function(color) { + var source; + + if (color in Color.colorNameMap) { + color = Color.colorNameMap[color]; + } + + if (color === 'transparent') { + source = [255, 255, 255, 0]; + } + + if (!source) { + source = Color.sourceFromHex(color); + } + if (!source) { + source = Color.sourceFromRgb(color); + } + if (!source) { + source = Color.sourceFromHsl(color); + } + if (!source) { + //if color is not recognize let's make black as canvas does + source = [0, 0, 0, 1]; + } + if (source) { + this.setSource(source); + } + }, + + /** + * Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a> + * @private + * @param {Number} r Red color value + * @param {Number} g Green color value + * @param {Number} b Blue color value + * @return {Array} Hsl color + */ + _rgbToHsl: function(r, g, b) { + 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) { + h = s = 0; // achromatic + } + else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: + h = (g - b) / d + (g < b ? 6 : 0); + break; + case g: + h = (b - r) / d + 2; + break; + case b: + h = (r - g) / d + 4; + break; + } + h /= 6; + } + + return [ + Math.round(h * 360), + Math.round(s * 100), + Math.round(l * 100) + ]; + }, + + /** + * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1]) + * @return {Array} + */ + getSource: function() { + return this._source; + }, + + /** + * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1]) + * @param {Array} source + */ + setSource: function(source) { + this._source = source; + }, + + /** + * Returns color representation in RGB format + * @return {String} ex: rgb(0-255,0-255,0-255) + */ + toRgb: function() { + var source = this.getSource(); + return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')'; + }, + + /** + * Returns color representation in RGBA format + * @return {String} ex: rgba(0-255,0-255,0-255,0-1) + */ + toRgba: function() { + var source = this.getSource(); + return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')'; + }, + + /** + * Returns color representation in HSL format + * @return {String} ex: hsl(0-360,0%-100%,0%-100%) + */ + toHsl: function() { + var source = this.getSource(), + hsl = this._rgbToHsl(source[0], source[1], source[2]); + + return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)'; + }, + + /** + * Returns color representation in HSLA format + * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1) + */ + toHsla: function() { + var source = this.getSource(), + hsl = this._rgbToHsl(source[0], source[1], source[2]); + + return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')'; + }, + + /** + * Returns color representation in HEX format + * @return {String} ex: FF5555 + */ + toHex: function() { + var source = this.getSource(), r, g, b; + + r = source[0].toString(16); + r = (r.length === 1) ? ('0' + r) : r; + + g = source[1].toString(16); + g = (g.length === 1) ? ('0' + g) : g; + + b = source[2].toString(16); + b = (b.length === 1) ? ('0' + b) : b; + + return r.toUpperCase() + g.toUpperCase() + b.toUpperCase(); + }, + + /** + * Returns color representation in HEXA format + * @return {String} ex: FF5555CC + */ + toHexa: function() { + var source = this.getSource(), a; + + a = source[3] * 255; + a = a.toString(16); + a = (a.length === 1) ? ('0' + a) : a; + + return this.toHex() + a.toUpperCase(); + }, + + /** + * Gets value of alpha channel for this color + * @return {Number} 0-1 + */ + getAlpha: function() { + return this.getSource()[3]; + }, + + /** + * Sets value of alpha channel for this color + * @param {Number} alpha Alpha value 0-1 + * @return {fabric.Color} thisArg + */ + setAlpha: function(alpha) { + var source = this.getSource(); + source[3] = alpha; + this.setSource(source); + return this; + }, + + /** + * Transforms color to its grayscale representation + * @return {fabric.Color} thisArg + */ + toGrayscale: function() { + var source = this.getSource(), + average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10), + currentAlpha = source[3]; + this.setSource([average, average, average, currentAlpha]); + return this; + }, + + /** + * Transforms color to its black and white representation + * @param {Number} threshold + * @return {fabric.Color} thisArg + */ + toBlackWhite: function(threshold) { + var source = this.getSource(), + average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), + currentAlpha = source[3]; + + threshold = threshold || 127; + + average = (Number(average) < Number(threshold)) ? 0 : 255; + this.setSource([average, average, average, currentAlpha]); + return this; + }, + + /** + * Overlays color with another color + * @param {String|fabric.Color} otherColor + * @return {fabric.Color} thisArg + */ + overlayWith: function(otherColor) { + if (!(otherColor instanceof Color)) { + otherColor = new Color(otherColor); + } + + var result = [], + alpha = this.getAlpha(), + otherAlpha = 0.5, + source = this.getSource(), + otherSource = otherColor.getSource(); + + for (var i = 0; i < 3; i++) { + result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha))); + } + + result[3] = alpha; + this.setSource(result); + return this; + } + }; + + /** + * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgba(255, 100, 10, 0.5), rgba( 255 , 100 , 10 , 0.5 ), rgb(1,1,1), rgba(100%, 60%, 10%, 0.5)) + * @static + * @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*)?\)$/; + + /** + * Regex matching color in HSL or HSLA formats (ex: hsl(200, 80%, 10%), hsla(300, 50%, 80%, 0.5), hsla( 300 , 50% , 80% , 0.5 )) + * @static + * @field + * @memberOf fabric.Color + */ + fabric.Color.reHSLa = /^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/; + + /** + * Regex matching color in HEX format (ex: #FF5544CC, #FF5555, 010155, aff) + * @static + * @field + * @memberOf fabric.Color + */ + fabric.Color.reHex = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i; + + /** + * Map of the 17 basic color names with HEX code + * @static + * @field + * @memberOf fabric.Color + * @see: http://www.w3.org/TR/CSS2/syndata.html#color-units + */ + fabric.Color.colorNameMap = { + aqua: '#00FFFF', + black: '#000000', + blue: '#0000FF', + fuchsia: '#FF00FF', + gray: '#808080', + grey: '#808080', + green: '#008000', + lime: '#00FF00', + maroon: '#800000', + navy: '#000080', + olive: '#808000', + orange: '#FFA500', + purple: '#800080', + red: '#FF0000', + silver: '#C0C0C0', + teal: '#008080', + white: '#FFFFFF', + yellow: '#FFFF00' + }; + + /** + * @private + * @param {Number} p + * @param {Number} q + * @param {Number} t + * @return {Number} + */ + function hue2rgb(p, q, t) { + if (t < 0) { + t += 1; + } + if (t > 1) { + t -= 1; + } + if (t < 1 / 6) { + return p + (q - p) * 6 * t; + } + if (t < 1 / 2) { + return q; + } + if (t < 2 / 3) { + return p + (q - p) * (2 / 3 - t) * 6; + } + return p; + } + + /** + * Returns new color object, when given a color in RGB format + * @memberOf fabric.Color + * @param {String} color Color value ex: rgb(0-255,0-255,0-255) + * @return {fabric.Color} + */ + fabric.Color.fromRgb = function(color) { + return Color.fromSource(Color.sourceFromRgb(color)); + }; + + /** + * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format + * @memberOf fabric.Color + * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%) + * @return {Array} source + */ + fabric.Color.sourceFromRgb = function(color) { + var match = color.match(Color.reRGBa); + if (match) { + var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1), + g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1), + b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1); + + return [ + parseInt(r, 10), + parseInt(g, 10), + parseInt(b, 10), + match[4] ? parseFloat(match[4]) : 1 + ]; + } + }; + + /** + * Returns new color object, when given a color in RGBA format + * @static + * @function + * @memberOf fabric.Color + * @param {String} color + * @return {fabric.Color} + */ + fabric.Color.fromRgba = Color.fromRgb; + + /** + * Returns new color object, when given a color in HSL format + * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%) + * @memberOf fabric.Color + * @return {fabric.Color} + */ + fabric.Color.fromHsl = function(color) { + return Color.fromSource(Color.sourceFromHsl(color)); + }; + + /** + * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format. + * Adapted from <a href="https://rawgithub.com/mjijackson/mjijackson.github.com/master/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript.html">https://github.com/mjijackson</a> + * @memberOf fabric.Color + * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1) + * @return {Array} source + * @see http://http://www.w3.org/TR/css3-color/#hsl-color + */ + fabric.Color.sourceFromHsl = function(color) { + var match = color.match(Color.reHSLa); + if (!match) { + return; + } + + var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360, + s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1), + l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1), + r, g, b; + + if (s === 0) { + r = g = b = l; + } + else { + var q = l <= 0.5 ? l * (s + 1) : l + s - l * s, + p = l * 2 - q; + + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + + return [ + Math.round(r * 255), + Math.round(g * 255), + Math.round(b * 255), + match[4] ? parseFloat(match[4]) : 1 + ]; + }; + + /** + * Returns new color object, when given a color in HSLA format + * @static + * @function + * @memberOf fabric.Color + * @param {String} color + * @return {fabric.Color} + */ + fabric.Color.fromHsla = Color.fromHsl; + + /** + * Returns new color object, when given a color in HEX format + * @static + * @memberOf fabric.Color + * @param {String} color Color value ex: FF5555 + * @return {fabric.Color} + */ + fabric.Color.fromHex = function(color) { + return Color.fromSource(Color.sourceFromHex(color)); + }; + + /** + * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HEX format + * @static + * @memberOf fabric.Color + * @param {String} color ex: FF5555 or FF5544CC (RGBa) + * @return {Array} source + */ + fabric.Color.sourceFromHex = function(color) { + if (color.match(Color.reHex)) { + var value = color.slice(color.indexOf('#') + 1), + isShortNotation = (value.length === 3 || value.length === 4), + isRGBa = (value.length === 8 || value.length === 4), + r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2), + g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4), + b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6), + a = isRGBa ? (isShortNotation ? (value.charAt(3) + value.charAt(3)) : value.substring(6, 8)) : 'FF'; + + return [ + parseInt(r, 16), + parseInt(g, 16), + parseInt(b, 16), + parseFloat((parseInt(a, 16) / 255).toFixed(2)) + ]; + } + }; + + /** + * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5]) + * @static + * @memberOf fabric.Color + * @param {Array} source + * @return {fabric.Color} + */ + fabric.Color.fromSource = function(source) { + var oColor = new Color(); + oColor.setSource(source); + return oColor; + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function() { + + /* _FROM_SVG_START_ */ + function getColorStop(el) { + var style = el.getAttribute('style'), + offset = el.getAttribute('offset') || 0, + color, colorAlpha, opacity; + + // convert percents to absolute values + offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1); + offset = offset < 0 ? 0 : offset > 1 ? 1 : offset; + if (style) { + var keyValuePairs = style.split(/\s*;\s*/); + + if (keyValuePairs[keyValuePairs.length - 1] === '') { + keyValuePairs.pop(); + } + + for (var i = keyValuePairs.length; i--; ) { + + var split = keyValuePairs[i].split(/\s*:\s*/), + key = split[0].trim(), + value = split[1].trim(); + + if (key === 'stop-color') { + color = value; + } + else if (key === 'stop-opacity') { + opacity = value; + } + } + } + + if (!color) { + color = el.getAttribute('stop-color') || 'rgb(0,0,0)'; + } + if (!opacity) { + opacity = el.getAttribute('stop-opacity'); + } + + color = new fabric.Color(color); + colorAlpha = color.getAlpha(); + opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity); + opacity *= colorAlpha; + + return { + offset: offset, + color: color.toRgb(), + opacity: opacity + }; + } + + function getLinearCoords(el) { + return { + x1: el.getAttribute('x1') || 0, + y1: el.getAttribute('y1') || 0, + x2: el.getAttribute('x2') || '100%', + y2: el.getAttribute('y2') || 0 + }; + } + + function getRadialCoords(el) { + return { + x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%', + y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%', + r1: 0, + x2: el.getAttribute('cx') || '50%', + y2: el.getAttribute('cy') || '50%', + r2: el.getAttribute('r') || '50%' + }; + } + /* _FROM_SVG_END_ */ + + var clone = fabric.util.object.clone; + + /** + * Gradient class + * @class fabric.Gradient + * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#gradients} + * @see {@link fabric.Gradient#initialize} for constructor definition + */ + fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ { + + /** + * Horizontal offset for aligning gradients coming from SVG when outside pathgroups + * @type Number + * @default 0 + */ + offsetX: 0, + + /** + * Vertical offset for aligning gradients coming from SVG when outside pathgroups + * @type Number + * @default 0 + */ + offsetY: 0, + + /** + * Constructor + * @param {Object} [options] Options object with type, coords, gradientUnits and colorStops + * @return {fabric.Gradient} thisArg + */ + initialize: function(options) { + options || (options = { }); + + var coords = { }; + + this.id = fabric.Object.__uid++; + this.type = options.type || 'linear'; + + coords = { + x1: options.coords.x1 || 0, + y1: options.coords.y1 || 0, + x2: options.coords.x2 || 0, + y2: options.coords.y2 || 0 + }; + + if (this.type === 'radial') { + coords.r1 = options.coords.r1 || 0; + coords.r2 = options.coords.r2 || 0; + } + this.coords = coords; + this.colorStops = options.colorStops.slice(); + if (options.gradientTransform) { + this.gradientTransform = options.gradientTransform; + } + this.offsetX = options.offsetX || this.offsetX; + this.offsetY = options.offsetY || this.offsetY; + }, + + /** + * Adds another colorStop + * @param {Object} colorStop Object with offset and color + * @return {fabric.Gradient} thisArg + */ + addColorStop: function(colorStops) { + for (var position in colorStops) { + var color = new fabric.Color(colorStops[position]); + this.colorStops.push({ + offset: parseFloat(position), + color: color.toRgb(), + opacity: color.getAlpha() + }); + } + return this; + }, + + /** + * Returns object representation of a gradient + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} + */ + toObject: function(propertiesToInclude) { + var object = { + type: this.type, + coords: this.coords, + colorStops: this.colorStops, + offsetX: this.offsetX, + offsetY: this.offsetY, + gradientTransform: this.gradientTransform ? this.gradientTransform.concat() : this.gradientTransform + }; + fabric.util.populateWithProperties(this, object, propertiesToInclude); + + return object; + }, + + /* _TO_SVG_START_ */ + /** + * Returns SVG representation of an gradient + * @param {Object} object Object to create a gradient for + * @return {String} SVG representation of an gradient (linear/radial) + */ + toSVG: function(object) { + var coords = clone(this.coords, true), + markup, commonAttributes, colorStops = clone(this.colorStops, true), + needsSwap = coords.r1 > coords.r2; + // colorStops must be sorted ascending + colorStops.sort(function(a, b) { + return a.offset - b.offset; + }); + + if (!(object.group && object.group.type === 'path-group')) { + for (var prop in coords) { + if (prop === 'x1' || prop === 'x2') { + coords[prop] += this.offsetX - object.width / 2; + } + else if (prop === 'y1' || prop === 'y2') { + coords[prop] += this.offsetY - object.height / 2; + } + } + } + + commonAttributes = 'id="SVGID_' + this.id + + '" gradientUnits="userSpaceOnUse"'; + if (this.gradientTransform) { + commonAttributes += ' gradientTransform="matrix(' + this.gradientTransform.join(' ') + ')" '; + } + if (this.type === 'linear') { + markup = [ + '<linearGradient ', + commonAttributes, + ' x1="', coords.x1, + '" y1="', coords.y1, + '" x2="', coords.x2, + '" y2="', coords.y2, + '">\n' + ]; + } + else if (this.type === 'radial') { + // svg radial gradient has just 1 radius. the biggest. + markup = [ + '<radialGradient ', + commonAttributes, + ' cx="', needsSwap ? coords.x1 : coords.x2, + '" cy="', needsSwap ? coords.y1 : coords.y2, + '" r="', needsSwap ? coords.r1 : coords.r2, + '" fx="', needsSwap ? coords.x2 : coords.x1, + '" fy="', needsSwap ? coords.y2 : coords.y1, + '">\n' + ]; + } + + if (this.type === 'radial') { + if (needsSwap) { + // svg goes from internal to external radius. if radius are inverted, swap color stops. + colorStops = colorStops.concat(); + colorStops.reverse(); + for (var i = 0; i < colorStops.length; i++) { + colorStops[i].offset = 1 - colorStops[i].offset; + } + } + var minRadius = Math.min(coords.r1, coords.r2); + if (minRadius > 0) { + // i have to shift all colorStops and add new one in 0. + var maxRadius = Math.max(coords.r1, coords.r2), + percentageShift = minRadius / maxRadius; + for (var i = 0; i < colorStops.length; i++) { + colorStops[i].offset += percentageShift * (1 - colorStops[i].offset); + } + } + } + + for (var i = 0; i < colorStops.length; i++) { + var colorStop = colorStops[i]; + markup.push( + '<stop ', + 'offset="', (colorStop.offset * 100) + '%', + '" style="stop-color:', colorStop.color, + (colorStop.opacity !== null ? ';stop-opacity: ' + colorStop.opacity : ';'), + '"/>\n' + ); + } + + markup.push((this.type === 'linear' ? '</linearGradient>\n' : '</radialGradient>\n')); + + return markup.join(''); + }, + /* _TO_SVG_END_ */ + + /** + * Returns an instance of CanvasGradient + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Object} object + * @return {CanvasGradient} + */ + toLive: function(ctx, object) { + var gradient, prop, coords = fabric.util.object.clone(this.coords); + + if (!this.type) { + return; + } + + if (object.group && object.group.type === 'path-group') { + for (prop in coords) { + if (prop === 'x1' || prop === 'x2') { + coords[prop] += -this.offsetX + object.width / 2; + } + else if (prop === 'y1' || prop === 'y2') { + coords[prop] += -this.offsetY + object.height / 2; + } + } + } + + if (this.type === 'linear') { + gradient = ctx.createLinearGradient( + coords.x1, coords.y1, coords.x2, coords.y2); + } + else if (this.type === 'radial') { + gradient = ctx.createRadialGradient( + coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2); + } + + for (var i = 0, len = this.colorStops.length; i < len; i++) { + var color = this.colorStops[i].color, + opacity = this.colorStops[i].opacity, + offset = this.colorStops[i].offset; + + if (typeof opacity !== 'undefined') { + color = new fabric.Color(color).setAlpha(opacity).toRgba(); + } + gradient.addColorStop(offset, color); + } + + return gradient; + } + }); + + fabric.util.object.extend(fabric.Gradient, { + + /* _FROM_SVG_START_ */ + /** + * Returns {@link fabric.Gradient} instance from an SVG element + * @static + * @memberOf fabric.Gradient + * @param {SVGGradientElement} el SVG gradient element + * @param {fabric.Object} instance + * @return {fabric.Gradient} Gradient instance + * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement + * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement + */ + fromElement: function(el, instance) { + + /** + * @example: + * + * <linearGradient id="linearGrad1"> + * <stop offset="0%" stop-color="white"/> + * <stop offset="100%" stop-color="black"/> + * </linearGradient> + * + * OR + * + * <linearGradient id="linearGrad2"> + * <stop offset="0" style="stop-color:rgb(255,255,255)"/> + * <stop offset="1" style="stop-color:rgb(0,0,0)"/> + * </linearGradient> + * + * OR + * + * <radialGradient id="radialGrad1"> + * <stop offset="0%" stop-color="white" stop-opacity="1" /> + * <stop offset="50%" stop-color="black" stop-opacity="0.5" /> + * <stop offset="100%" stop-color="white" stop-opacity="1" /> + * </radialGradient> + * + * OR + * + * <radialGradient id="radialGrad2"> + * <stop offset="0" stop-color="rgb(255,255,255)" /> + * <stop offset="0.5" stop-color="rgb(0,0,0)" /> + * <stop offset="1" stop-color="rgb(255,255,255)" /> + * </radialGradient> + * + */ + + var colorStopEls = el.getElementsByTagName('stop'), + type, + gradientUnits = el.getAttribute('gradientUnits') || 'objectBoundingBox', + gradientTransform = el.getAttribute('gradientTransform'), + colorStops = [], + coords, ellipseMatrix; + + if (el.nodeName === 'linearGradient' || el.nodeName === 'LINEARGRADIENT') { + type = 'linear'; + } + else { + type = 'radial'; + } + + if (type === 'linear') { + coords = getLinearCoords(el); + } + else if (type === 'radial') { + coords = getRadialCoords(el); + } + + for (var i = colorStopEls.length; i--; ) { + colorStops.push(getColorStop(colorStopEls[i])); + } + + ellipseMatrix = _convertPercentUnitsToValues(instance, coords, gradientUnits); + + var gradient = new fabric.Gradient({ + type: type, + coords: coords, + colorStops: colorStops, + offsetX: -instance.left, + offsetY: -instance.top + }); + + if (gradientTransform || ellipseMatrix !== '') { + gradient.gradientTransform = fabric.parseTransformAttribute((gradientTransform || '') + ellipseMatrix); + } + return gradient; + }, + /* _FROM_SVG_END_ */ + + /** + * Returns {@link fabric.Gradient} instance from its object representation + * @static + * @memberOf fabric.Gradient + * @param {Object} obj + * @param {Object} [options] Options object + */ + forObject: function(obj, options) { + options || (options = { }); + _convertPercentUnitsToValues(obj, options.coords, 'userSpaceOnUse'); + return new fabric.Gradient(options); + } + }); + + /** + * @private + */ + function _convertPercentUnitsToValues(object, options, gradientUnits) { + var propValue, addFactor = 0, multFactor = 1, ellipseMatrix = ''; + for (var prop in options) { + if (options[prop] === 'Infinity') { + options[prop] = 1; + } + else if (options[prop] === '-Infinity') { + options[prop] = 0; + } + propValue = parseFloat(options[prop], 10); + if (typeof options[prop] === 'string' && /^\d+%$/.test(options[prop])) { + multFactor = 0.01; + } + else { + multFactor = 1; + } + if (prop === 'x1' || prop === 'x2' || prop === 'r2') { + multFactor *= gradientUnits === 'objectBoundingBox' ? object.width : 1; + addFactor = gradientUnits === 'objectBoundingBox' ? object.left || 0 : 0; + } + else if (prop === 'y1' || prop === 'y2') { + multFactor *= gradientUnits === 'objectBoundingBox' ? object.height : 1; + addFactor = gradientUnits === 'objectBoundingBox' ? object.top || 0 : 0; + } + options[prop] = propValue * multFactor + addFactor; + } + if (object.type === 'ellipse' && + options.r2 !== null && + gradientUnits === 'objectBoundingBox' && + object.rx !== object.ry) { + + var scaleFactor = object.ry / object.rx; + ellipseMatrix = ' scale(1, ' + scaleFactor + ')'; + if (options.y1) { + options.y1 /= scaleFactor; + } + if (options.y2) { + options.y2 /= scaleFactor; + } + } + return ellipseMatrix; + } +})(); + + +(function() { + + 'use strict'; + + var toFixed = fabric.util.toFixed; + + /** + * Pattern class + * @class fabric.Pattern + * @see {@link http://fabricjs.com/patterns|Pattern demo} + * @see {@link http://fabricjs.com/dynamic-patterns|DynamicPattern demo} + * @see {@link fabric.Pattern#initialize} for constructor definition + */ + + + fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ { + + /** + * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat) + * @type String + * @default + */ + repeat: 'repeat', + + /** + * Pattern horizontal offset from object's left/top corner + * @type Number + * @default + */ + offsetX: 0, + + /** + * Pattern vertical offset from object's left/top corner + * @type Number + * @default + */ + offsetY: 0, + + /** + * Constructor + * @param {Object} [options] Options object + * @param {Function} [callback] function to invoke after callback init. + * @return {fabric.Pattern} thisArg + */ + initialize: function(options, callback) { + options || (options = { }); + + this.id = fabric.Object.__uid++; + this.setOptions(options); + if (!options.source || (options.source && typeof options.source !== 'string')) { + callback && callback(this); + return; + } + // function string + if (typeof fabric.util.getFunctionBody(options.source) !== 'undefined') { + this.source = new Function(fabric.util.getFunctionBody(options.source)); + callback && callback(this); + } + else { + // img src string + var _this = this; + this.source = fabric.util.createImage(); + fabric.util.loadImage(options.source, function(img) { + _this.source = img; + callback && callback(_this); + }); + } + }, + + /** + * Returns object representation of a pattern + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} Object representation of a pattern instance + */ + toObject: function(propertiesToInclude) { + var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, + source, object; + + // callback + if (typeof this.source === 'function') { + source = String(this.source); + } + // <img> element + else if (typeof this.source.src === 'string') { + source = this.source.src; + } + // <canvas> element + else if (typeof this.source === 'object' && this.source.toDataURL) { + source = this.source.toDataURL(); + } + + object = { + type: 'pattern', + source: source, + repeat: this.repeat, + offsetX: toFixed(this.offsetX, NUM_FRACTION_DIGITS), + offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS), + }; + fabric.util.populateWithProperties(this, object, propertiesToInclude); + + return object; + }, + + /* _TO_SVG_START_ */ + /** + * Returns SVG representation of a pattern + * @param {fabric.Object} object + * @return {String} SVG representation of a pattern + */ + toSVG: function(object) { + var patternSource = typeof this.source === 'function' ? this.source() : this.source, + patternWidth = patternSource.width / object.width, + patternHeight = patternSource.height / object.height, + patternOffsetX = this.offsetX / object.width, + patternOffsetY = this.offsetY / object.height, + patternImgSrc = ''; + if (this.repeat === 'repeat-x' || this.repeat === 'no-repeat') { + patternHeight = 1; + } + if (this.repeat === 'repeat-y' || this.repeat === 'no-repeat') { + patternWidth = 1; + } + if (patternSource.src) { + patternImgSrc = patternSource.src; + } + else if (patternSource.toDataURL) { + patternImgSrc = patternSource.toDataURL(); + } + + return '<pattern id="SVGID_' + this.id + + '" x="' + patternOffsetX + + '" y="' + patternOffsetY + + '" width="' + patternWidth + + '" height="' + patternHeight + '">\n' + + '<image x="0" y="0"' + + ' width="' + patternSource.width + + '" height="' + patternSource.height + + '" xlink:href="' + patternImgSrc + + '"></image>\n' + + '</pattern>\n'; + }, + /* _TO_SVG_END_ */ + + setOptions: function(options) { + for (var prop in options) { + this[prop] = options[prop]; + } + }, + + /** + * Returns an instance of CanvasPattern + * @param {CanvasRenderingContext2D} ctx Context to create pattern + * @return {CanvasPattern} + */ + toLive: function(ctx) { + var source = typeof this.source === 'function' ? this.source() : this.source; + + // if the image failed to load, return, and allow rest to continue loading + if (!source) { + return ''; + } + + // if an image + if (typeof source.src !== 'undefined') { + if (!source.complete) { + return ''; + } + if (source.naturalWidth === 0 || source.naturalHeight === 0) { + return ''; + } + } + return ctx.createPattern(source, this.repeat); + } + }); +})(); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + toFixed = fabric.util.toFixed; + + if (fabric.Shadow) { + fabric.warn('fabric.Shadow is already defined.'); + return; + } + + /** + * Shadow class + * @class fabric.Shadow + * @see {@link http://fabricjs.com/shadows|Shadow demo} + * @see {@link fabric.Shadow#initialize} for constructor definition + */ + fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ { + + /** + * Shadow color + * @type String + * @default + */ + color: 'rgb(0,0,0)', + + /** + * Shadow blur + * @type Number + */ + blur: 0, + + /** + * Shadow horizontal offset + * @type Number + * @default + */ + offsetX: 0, + + /** + * Shadow vertical offset + * @type Number + * @default + */ + offsetY: 0, + + /** + * Whether the shadow should affect stroke operations + * @type Boolean + * @default + */ + affectStroke: false, + + /** + * Indicates whether toObject should include default values + * @type Boolean + * @default + */ + includeDefaultValues: true, + + /** + * Constructor + * @param {Object|String} [options] Options object with any of color, blur, offsetX, offsetX properties or string (e.g. "rgba(0,0,0,0.2) 2px 2px 10px, "2px 2px 10px rgba(0,0,0,0.2)") + * @return {fabric.Shadow} thisArg + */ + initialize: function(options) { + + if (typeof options === 'string') { + options = this._parseShadow(options); + } + + for (var prop in options) { + this[prop] = options[prop]; + } + + this.id = fabric.Object.__uid++; + }, + + /** + * @private + * @param {String} shadow Shadow value to parse + * @return {Object} Shadow object with color, offsetX, offsetY and blur + */ + _parseShadow: function(shadow) { + var shadowStr = shadow.trim(), + offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [], + color = shadowStr.replace(fabric.Shadow.reOffsetsAndBlur, '') || 'rgb(0,0,0)'; + + return { + color: color.trim(), + offsetX: parseInt(offsetsAndBlur[1], 10) || 0, + offsetY: parseInt(offsetsAndBlur[2], 10) || 0, + blur: parseInt(offsetsAndBlur[3], 10) || 0 + }; + }, + + /** + * Returns a string representation of an instance + * @see http://www.w3.org/TR/css-text-decor-3/#text-shadow + * @return {String} Returns CSS3 text-shadow declaration + */ + toString: function() { + return [this.offsetX, this.offsetY, this.blur, this.color].join('px '); + }, + + /* _TO_SVG_START_ */ + /** + * Returns SVG representation of a shadow + * @param {fabric.Object} object + * @return {String} SVG representation of a shadow + */ + toSVG: function(object) { + var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, + offset = fabric.util.rotateVector( + { x: this.offsetX, y: this.offsetY }, + fabric.util.degreesToRadians(-object.angle)), + BLUR_BOX = 20; + + if (object.width && object.height) { + //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion + // we add some extra space to filter box to contain the blur ( 20 ) + fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX; + fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX; + } + if (object.flipX) { + offset.x *= -1; + } + if (object.flipY) { + offset.y *= -1; + } + return ( + '<filter id="SVGID_' + this.id + '" y="-' + fBoxY + '%" height="' + (100 + 2 * fBoxY) + '%" ' + + 'x="-' + fBoxX + '%" width="' + (100 + 2 * fBoxX) + '%" ' + '>\n' + + '\t<feGaussianBlur in="SourceAlpha" stdDeviation="' + + toFixed(this.blur ? this.blur / 2 : 0, NUM_FRACTION_DIGITS) + '"></feGaussianBlur>\n' + + '\t<feOffset dx="' + toFixed(offset.x, NUM_FRACTION_DIGITS) + + '" dy="' + toFixed(offset.y, NUM_FRACTION_DIGITS) + '" result="oBlur" ></feOffset>\n' + + '\t<feFlood flood-color="' + this.color + '"/>\n' + + '\t<feComposite in2="oBlur" operator="in" />\n' + + '\t<feMerge>\n' + + '\t\t<feMergeNode></feMergeNode>\n' + + '\t\t<feMergeNode in="SourceGraphic"></feMergeNode>\n' + + '\t</feMerge>\n' + + '</filter>\n'); + }, + /* _TO_SVG_END_ */ + + /** + * Returns object representation of a shadow + * @return {Object} Object representation of a shadow instance + */ + toObject: function() { + if (this.includeDefaultValues) { + return { + color: this.color, + blur: this.blur, + offsetX: this.offsetX, + offsetY: this.offsetY, + affectStroke: this.affectStroke + }; + } + var obj = { }, proto = fabric.Shadow.prototype; + + ['color', 'blur', 'offsetX', 'offsetY', 'affectStroke'].forEach(function(prop) { + if (this[prop] !== proto[prop]) { + obj[prop] = this[prop]; + } + }, this); + + return obj; + } + }); + + /** + * Regex matching shadow offsetX, offsetY and blur (ex: "2px 2px 10px rgba(0,0,0,0.2)", "rgb(0,255,0) 2px 2px") + * @static + * @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); + + +(function () { + + 'use strict'; + + if (fabric.StaticCanvas) { + fabric.warn('fabric.StaticCanvas is already defined.'); + return; + } + + // aliases for faster resolution + var extend = fabric.util.object.extend, + getElementOffset = fabric.util.getElementOffset, + removeFromArray = fabric.util.removeFromArray, + toFixed = fabric.util.toFixed, + transformPoint = fabric.util.transformPoint, + invertTransform = fabric.util.invertTransform, + + CANVAS_INIT_ERROR = new Error('Could not initialize `canvas` element'); + + /** + * Static canvas class + * @class fabric.StaticCanvas + * @mixes fabric.Collection + * @mixes fabric.Observable + * @see {@link http://fabricjs.com/static_canvas|StaticCanvas demo} + * @see {@link fabric.StaticCanvas#initialize} for constructor definition + * @fires before:render + * @fires after:render + * @fires canvas:cleared + * @fires object:added + * @fires object:removed + */ + fabric.StaticCanvas = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.StaticCanvas.prototype */ { + + /** + * Constructor + * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on + * @param {Object} [options] Options object + * @return {Object} thisArg + */ + initialize: function(el, options) { + options || (options = { }); + + this._initStatic(el, options); + }, + + /** + * Background color of canvas instance. + * Should be set via {@link fabric.StaticCanvas#setBackgroundColor}. + * @type {(String|fabric.Pattern)} + * @default + */ + backgroundColor: '', + + /** + * Background image of canvas instance. + * Should be set via {@link fabric.StaticCanvas#setBackgroundImage}. + * <b>Backwards incompatibility note:</b> The "backgroundImageOpacity" + * and "backgroundImageStretch" properties are deprecated since 1.3.9. + * Use {@link fabric.Image#opacity}, {@link fabric.Image#width} and {@link fabric.Image#height}. + * @type fabric.Image + * @default + */ + backgroundImage: null, + + /** + * Overlay color of canvas instance. + * Should be set via {@link fabric.StaticCanvas#setOverlayColor} + * @since 1.3.9 + * @type {(String|fabric.Pattern)} + * @default + */ + overlayColor: '', + + /** + * Overlay image of canvas instance. + * Should be set via {@link fabric.StaticCanvas#setOverlayImage}. + * <b>Backwards incompatibility note:</b> The "overlayImageLeft" + * and "overlayImageTop" properties are deprecated since 1.3.9. + * Use {@link fabric.Image#left} and {@link fabric.Image#top}. + * @type fabric.Image + * @default + */ + overlayImage: null, + + /** + * Indicates whether toObject/toDatalessObject should include default values + * @type Boolean + * @default + */ + includeDefaultValues: true, + + /** + * Indicates whether objects' state should be saved + * @type Boolean + * @default + */ + stateful: false, + + /** + * Indicates whether {@link fabric.Collection.add}, {@link fabric.Collection.insertAt} and {@link fabric.Collection.remove} should also re-render canvas. + * Disabling this option could give a great performance boost when adding/removing a lot of objects to/from canvas at once + * (followed by a manual rendering after addition/deletion) + * @type Boolean + * @default + */ + renderOnAddRemove: true, + + /** + * Function that determines clipping of entire canvas area + * Being passed context as first argument. See clipping canvas area in {@link https://github.com/kangax/fabric.js/wiki/FAQ} + * @type Function + * @default + */ + clipTo: null, + + /** + * Indicates whether object controls (borders/controls) are rendered above overlay image + * @type Boolean + * @default + */ + controlsAboveOverlay: false, + + /** + * Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas + * @type Boolean + * @default + */ + allowTouchScrolling: false, + + /** + * Indicates whether this canvas will use image smoothing, this is on by default in browsers + * @type Boolean + * @default + */ + imageSmoothingEnabled: true, + + /** + * The transformation (in the format of Canvas transform) which focuses the viewport + * @type Array + * @default + */ + viewportTransform: fabric.iMatrix.concat(), + + /** + * if set to false background image is not affected by viewport transform + * @since 1.6.3 + * @type Boolean + * @default + */ + backgroundVpt: true, + + /** + * if set to false overlya image is not affected by viewport transform + * @since 1.6.3 + * @type Boolean + * @default + */ + overlayVpt: true, + + /** + * Callback; invoked right before object is about to be scaled/rotated + */ + onBeforeScaleRotate: function () { + /* NOOP */ + }, + + /** + * When true, canvas is scaled by devicePixelRatio for better rendering on retina screens + */ + enableRetinaScaling: true, + + /** + * Describe canvas element extension over design + * properties are tl,tr,bl,br. + * if canvas is not zoomed/panned those points are the four corner of canvas + * if canvas is viewportTransformed you those points indicate the extension + * of canvas element in plain untrasformed coordinates + * The coordinates get updated with @method calcViewportBoundaries. + * @memberOf fabric.StaticCanvas.prototype + */ + vptCoords: { }, + + /** + * Based on vptCoords and object.aCoords, skip rendering of objects that + * are not included in current viewport. + * May greatly help in applications with crowded canvas and use of zoom/pan + * If One of the corner of the bounding box of the object is on the canvas + * the objects get rendered. + * @memberOf fabric.StaticCanvas.prototype + */ + skipOffscreen: false, + + /** + * @private + * @param {HTMLElement | String} el &lt;canvas> element to initialize instance on + * @param {Object} [options] Options object + */ + _initStatic: function(el, options) { + var cb = fabric.StaticCanvas.prototype.renderAll.bind(this); + this._objects = []; + this._createLowerCanvas(el); + this._initOptions(options); + this._setImageSmoothing(); + // only initialize retina scaling once + if (!this.interactive) { + this._initRetinaScaling(); + } + + if (options.overlayImage) { + this.setOverlayImage(options.overlayImage, cb); + } + if (options.backgroundImage) { + this.setBackgroundImage(options.backgroundImage, cb); + } + if (options.backgroundColor) { + this.setBackgroundColor(options.backgroundColor, cb); + } + if (options.overlayColor) { + this.setOverlayColor(options.overlayColor, cb); + } + this.calcOffset(); + }, + + /** + * @private + */ + _isRetinaScaling: function() { + return (fabric.devicePixelRatio !== 1 && this.enableRetinaScaling); + }, + + /** + * @private + * @return {Number} retinaScaling if applied, otherwise 1; + */ + getRetinaScaling: function() { + return this._isRetinaScaling() ? fabric.devicePixelRatio : 1; + }, + + /** + * @private + */ + _initRetinaScaling: function() { + if (!this._isRetinaScaling()) { + return; + } + this.lowerCanvasEl.setAttribute('width', this.width * fabric.devicePixelRatio); + this.lowerCanvasEl.setAttribute('height', this.height * fabric.devicePixelRatio); + + this.contextContainer.scale(fabric.devicePixelRatio, fabric.devicePixelRatio); + }, + + /** + * Calculates canvas element offset relative to the document + * This method is also attached as "resize" event handler of window + * @return {fabric.Canvas} instance + * @chainable + */ + calcOffset: function () { + this._offset = getElementOffset(this.lowerCanvasEl); + return this; + }, + + /** + * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas + * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to + * @param {Function} callback callback to invoke when image is loaded and set as an overlay + * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}. + * @return {fabric.Canvas} thisArg + * @chainable + * @see {@link http://jsfiddle.net/fabricjs/MnzHT/|jsFiddle demo} + * @example <caption>Normal overlayImage with left/top = 0</caption> + * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { + * // Needed to position overlayImage at 0/0 + * originX: 'left', + * originY: 'top' + * }); + * @example <caption>overlayImage with different properties</caption> + * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { + * opacity: 0.5, + * angle: 45, + * left: 400, + * top: 400, + * originX: 'left', + * originY: 'top' + * }); + * @example <caption>Stretched overlayImage #1 - width/height correspond to canvas width/height</caption> + * fabric.Image.fromURL('http://fabricjs.com/assets/jail_cell_bars.png', function(img) { + * img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'}); + * canvas.setOverlayImage(img, canvas.renderAll.bind(canvas)); + * }); + * @example <caption>Stretched overlayImage #2 - width/height correspond to canvas width/height</caption> + * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { + * width: canvas.width, + * height: canvas.height, + * // Needed to position overlayImage at 0/0 + * originX: 'left', + * originY: 'top' + * }); + * @example <caption>overlayImage loaded from cross-origin</caption> + * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), { + * opacity: 0.5, + * angle: 45, + * left: 400, + * top: 400, + * originX: 'left', + * originY: 'top', + * crossOrigin: 'anonymous' + * }); + */ + setOverlayImage: function (image, callback, options) { + return this.__setBgOverlayImage('overlayImage', image, callback, options); + }, + + /** + * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas + * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to + * @param {Function} callback Callback to invoke when image is loaded and set as background + * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}. + * @return {fabric.Canvas} thisArg + * @chainable + * @see {@link http://jsfiddle.net/fabricjs/YH9yD/|jsFiddle demo} + * @example <caption>Normal backgroundImage with left/top = 0</caption> + * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { + * // Needed to position backgroundImage at 0/0 + * originX: 'left', + * originY: 'top' + * }); + * @example <caption>backgroundImage with different properties</caption> + * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { + * opacity: 0.5, + * angle: 45, + * left: 400, + * top: 400, + * originX: 'left', + * originY: 'top' + * }); + * @example <caption>Stretched backgroundImage #1 - width/height correspond to canvas width/height</caption> + * fabric.Image.fromURL('http://fabricjs.com/assets/honey_im_subtle.png', function(img) { + * img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'}); + * canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas)); + * }); + * @example <caption>Stretched backgroundImage #2 - width/height correspond to canvas width/height</caption> + * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { + * width: canvas.width, + * height: canvas.height, + * // Needed to position backgroundImage at 0/0 + * originX: 'left', + * originY: 'top' + * }); + * @example <caption>backgroundImage loaded from cross-origin</caption> + * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), { + * opacity: 0.5, + * angle: 45, + * left: 400, + * top: 400, + * originX: 'left', + * originY: 'top', + * crossOrigin: 'anonymous' + * }); + */ + setBackgroundImage: function (image, callback, options) { + return this.__setBgOverlayImage('backgroundImage', image, callback, options); + }, + + /** + * Sets {@link fabric.StaticCanvas#overlayColor|background color} for this canvas + * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set background color to + * @param {Function} callback Callback to invoke when background color is set + * @return {fabric.Canvas} thisArg + * @chainable + * @see {@link http://jsfiddle.net/fabricjs/pB55h/|jsFiddle demo} + * @example <caption>Normal overlayColor - color value</caption> + * canvas.setOverlayColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas)); + * @example <caption>fabric.Pattern used as overlayColor</caption> + * canvas.setOverlayColor({ + * source: 'http://fabricjs.com/assets/escheresque_ste.png' + * }, canvas.renderAll.bind(canvas)); + * @example <caption>fabric.Pattern used as overlayColor with repeat and offset</caption> + * canvas.setOverlayColor({ + * source: 'http://fabricjs.com/assets/escheresque_ste.png', + * repeat: 'repeat', + * offsetX: 200, + * offsetY: 100 + * }, canvas.renderAll.bind(canvas)); + */ + setOverlayColor: function(overlayColor, callback) { + return this.__setBgOverlayColor('overlayColor', overlayColor, callback); + }, + + /** + * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas + * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to + * @param {Function} callback Callback to invoke when background color is set + * @return {fabric.Canvas} thisArg + * @chainable + * @see {@link http://jsfiddle.net/fabricjs/hXzvk/|jsFiddle demo} + * @example <caption>Normal backgroundColor - color value</caption> + * canvas.setBackgroundColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas)); + * @example <caption>fabric.Pattern used as backgroundColor</caption> + * canvas.setBackgroundColor({ + * source: 'http://fabricjs.com/assets/escheresque_ste.png' + * }, canvas.renderAll.bind(canvas)); + * @example <caption>fabric.Pattern used as backgroundColor with repeat and offset</caption> + * canvas.setBackgroundColor({ + * source: 'http://fabricjs.com/assets/escheresque_ste.png', + * repeat: 'repeat', + * offsetX: 200, + * offsetY: 100 + * }, canvas.renderAll.bind(canvas)); + */ + setBackgroundColor: function(backgroundColor, callback) { + return this.__setBgOverlayColor('backgroundColor', backgroundColor, callback); + }, + + /** + * @private + * @see {@link http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-imagesmoothingenabled|WhatWG Canvas Standard} + */ + _setImageSmoothing: function() { + var ctx = this.getContext(); + + ctx.imageSmoothingEnabled = ctx.imageSmoothingEnabled || ctx.webkitImageSmoothingEnabled + || ctx.mozImageSmoothingEnabled || ctx.msImageSmoothingEnabled || ctx.oImageSmoothingEnabled; + ctx.imageSmoothingEnabled = this.imageSmoothingEnabled; + }, + + /** + * @private + * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage} + * or {@link fabric.StaticCanvas#overlayImage|overlayImage}) + * @param {(fabric.Image|String|null)} image fabric.Image instance, URL of an image or null to set background or overlay to + * @param {Function} callback Callback to invoke when image is loaded and set as background or overlay + * @param {Object} [options] Optional options to set for the {@link fabric.Image|image}. + */ + __setBgOverlayImage: function(property, image, callback, options) { + if (typeof image === 'string') { + fabric.util.loadImage(image, function(img) { + img && (this[property] = new fabric.Image(img, options)); + callback && callback(img); + }, this, options && options.crossOrigin); + } + else { + options && image.setOptions(options); + this[property] = image; + callback && callback(image); + } + + return this; + }, + + /** + * @private + * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor} + * or {@link fabric.StaticCanvas#overlayColor|overlayColor}) + * @param {(Object|String|null)} color Object with pattern information, color value or null + * @param {Function} [callback] Callback is invoked when color is set + */ + __setBgOverlayColor: function(property, color, callback) { + this[property] = color; + this._initGradient(color, property); + this._initPattern(color, property, callback); + return this; + }, + + /** + * @private + */ + _createCanvasElement: function(canvasEl) { + var element = fabric.util.createCanvasElement(canvasEl); + if (!element.style) { + element.style = { }; + } + if (!element) { + throw CANVAS_INIT_ERROR; + } + if (typeof element.getContext === 'undefined') { + throw CANVAS_INIT_ERROR; + } + return element; + }, + + /** + * @private + * @param {Object} [options] Options object + */ + _initOptions: function (options) { + this._setOptions(options); + + this.width = this.width || parseInt(this.lowerCanvasEl.width, 10) || 0; + this.height = this.height || parseInt(this.lowerCanvasEl.height, 10) || 0; + + if (!this.lowerCanvasEl.style) { + return; + } + + 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(); + }, + + /** + * Creates a bottom canvas + * @private + * @param {HTMLElement} [canvasEl] + */ + _createLowerCanvas: function (canvasEl) { + this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement(canvasEl); + + fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas'); + + if (this.interactive) { + this._applyCanvasStyle(this.lowerCanvasEl); + } + + this.contextContainer = this.lowerCanvasEl.getContext('2d'); + }, + + /** + * Returns canvas width (in px) + * @return {Number} + */ + getWidth: function () { + return this.width; + }, + + /** + * Returns canvas height (in px) + * @return {Number} + */ + getHeight: function () { + return this.height; + }, + + /** + * Sets width of this canvas instance + * @param {Number|String} value Value to set width to + * @param {Object} [options] Options object + * @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions + * @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions + * @return {fabric.Canvas} instance + * @chainable true + */ + setWidth: function (value, options) { + return this.setDimensions({ width: value }, options); + }, + + /** + * Sets height of this canvas instance + * @param {Number|String} value Value to set height to + * @param {Object} [options] Options object + * @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions + * @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions + * @return {fabric.Canvas} instance + * @chainable true + */ + setHeight: function (value, options) { + return this.setDimensions({ height: value }, options); + }, + + /** + * Sets dimensions (width, height) of this canvas instance. when options.cssOnly flag active you should also supply the unit of measure (px/%/em) + * @param {Object} dimensions Object with width/height properties + * @param {Number|String} [dimensions.width] Width of canvas element + * @param {Number|String} [dimensions.height] Height of canvas element + * @param {Object} [options] Options object + * @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions + * @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions + * @return {fabric.Canvas} thisArg + * @chainable + */ + setDimensions: function (dimensions, options) { + var cssValue; + + options = options || {}; + + for (var prop in dimensions) { + cssValue = dimensions[prop]; + + if (!options.cssOnly) { + this._setBackstoreDimension(prop, dimensions[prop]); + cssValue += 'px'; + } + + if (!options.backstoreOnly) { + this._setCssDimension(prop, cssValue); + } + } + this._initRetinaScaling(); + this._setImageSmoothing(); + this.calcOffset(); + + if (!options.cssOnly) { + this.renderAll(); + } + + return this; + }, + + /** + * Helper for setting width/height + * @private + * @param {String} prop property (width|height) + * @param {Number} value value to set property to + * @return {fabric.Canvas} instance + * @chainable true + */ + _setBackstoreDimension: function (prop, value) { + this.lowerCanvasEl[prop] = value; + + if (this.upperCanvasEl) { + this.upperCanvasEl[prop] = value; + } + + if (this.cacheCanvasEl) { + this.cacheCanvasEl[prop] = value; + } + + this[prop] = value; + + return this; + }, + + /** + * Helper for setting css width/height + * @private + * @param {String} prop property (width|height) + * @param {String} value value to set property to + * @return {fabric.Canvas} instance + * @chainable true + */ + _setCssDimension: function (prop, value) { + this.lowerCanvasEl.style[prop] = value; + + if (this.upperCanvasEl) { + this.upperCanvasEl.style[prop] = value; + } + + if (this.wrapperEl) { + this.wrapperEl.style[prop] = value; + } + + return this; + }, + + /** + * Returns canvas zoom level + * @return {Number} + */ + getZoom: function () { + return this.viewportTransform[0]; + }, + + /** + * Sets viewport transform of this canvas instance + * @param {Array} vpt the transform in the form of context.transform + * @return {fabric.Canvas} instance + * @chainable true + */ + setViewportTransform: function (vpt) { + var activeGroup = this._activeGroup, object, ignoreVpt = false, skipAbsolute = true; + this.viewportTransform = vpt; + for (var i = 0, len = this._objects.length; i < len; i++) { + object = this._objects[i]; + object.group || object.setCoords(ignoreVpt, skipAbsolute); + } + if (activeGroup) { + activeGroup.setCoords(ignoreVpt, skipAbsolute); + } + this.calcViewportBoundaries(); + this.renderAll(); + return this; + }, + + /** + * Sets zoom level of this canvas instance, zoom centered around point + * @param {fabric.Point} point to zoom with respect to + * @param {Number} value to set zoom to, less than 1 zooms out + * @return {fabric.Canvas} instance + * @chainable true + */ + zoomToPoint: function (point, value) { + // TODO: just change the scale, preserve other transformations + var before = point, vpt = this.viewportTransform.slice(0); + point = transformPoint(point, invertTransform(this.viewportTransform)); + vpt[0] = value; + vpt[3] = value; + var after = transformPoint(point, vpt); + vpt[4] += before.x - after.x; + vpt[5] += before.y - after.y; + return this.setViewportTransform(vpt); + }, + + /** + * Sets zoom level of this canvas instance + * @param {Number} value to set zoom to, less than 1 zooms out + * @return {fabric.Canvas} instance + * @chainable true + */ + setZoom: function (value) { + this.zoomToPoint(new fabric.Point(0, 0), value); + return this; + }, + + /** + * Pan viewport so as to place point at top left corner of canvas + * @param {fabric.Point} point to move to + * @return {fabric.Canvas} instance + * @chainable true + */ + absolutePan: function (point) { + var vpt = this.viewportTransform.slice(0); + vpt[4] = -point.x; + vpt[5] = -point.y; + return this.setViewportTransform(vpt); + }, + + /** + * Pans viewpoint relatively + * @param {fabric.Point} point (position vector) to move by + * @return {fabric.Canvas} instance + * @chainable true + */ + relativePan: function (point) { + return this.absolutePan(new fabric.Point( + -point.x - this.viewportTransform[4], + -point.y - this.viewportTransform[5] + )); + }, + + /** + * Returns &lt;canvas> element corresponding to this instance + * @return {HTMLCanvasElement} + */ + getElement: function () { + return this.lowerCanvasEl; + }, + + /** + * @private + * @param {fabric.Object} obj Object that was added + */ + _onObjectAdded: function(obj) { + this.stateful && obj.setupState(); + obj._set('canvas', this); + obj.setCoords(); + this.fire('object:added', { target: obj }); + obj.fire('added'); + }, + + /** + * @private + * @param {fabric.Object} obj Object that was removed + */ + _onObjectRemoved: function(obj) { + this.fire('object:removed', { target: obj }); + obj.fire('removed'); + delete obj.canvas; + }, + + /** + * Clears specified context of canvas element + * @param {CanvasRenderingContext2D} ctx Context to clear + * @return {fabric.Canvas} thisArg + * @chainable + */ + clearContext: function(ctx) { + ctx.clearRect(0, 0, this.width, this.height); + return this; + }, + + /** + * Returns context of canvas where objects are drawn + * @return {CanvasRenderingContext2D} + */ + getContext: function () { + return this.contextContainer; + }, + + /** + * Clears all contexts (background, main, top) of an instance + * @return {fabric.Canvas} thisArg + * @chainable + */ + clear: function () { + this._objects.length = 0; + this.backgroundImage = null; + this.overlayImage = null; + this.backgroundColor = ''; + this.overlayColor = ''; + if (this._hasITextHandlers) { + this.off('mouse:up', this._mouseUpITextHandler); + this._iTextInstances = null; + this._hasITextHandlers = false; + } + this.clearContext(this.contextContainer); + this.fire('canvas:cleared'); + this.renderAll(); + return this; + }, + + /** + * Renders the canvas + * @return {fabric.Canvas} instance + * @chainable + */ + renderAll: function () { + var canvasToDrawOn = this.contextContainer; + this.renderCanvas(canvasToDrawOn, this._objects); + return this; + }, + + /** + * Calculate the position of the 4 corner of canvas with current viewportTransform. + * helps to determinate when an object is in the current rendering viewport using + * object absolute coordinates ( aCoords ) + * @return {Object} points.tl + * @chainable + */ + calcViewportBoundaries: function() { + var points = { }, width = this.getWidth(), height = this.getHeight(), + iVpt = invertTransform(this.viewportTransform); + points.tl = transformPoint({ x: 0, y: 0 }, iVpt); + points.br = transformPoint({ x: width, y: height }, iVpt); + points.tr = new fabric.Point(points.br.x, points.tl.y); + points.bl = new fabric.Point(points.tl.x, points.br.y); + this.vptCoords = points; + return points; + }, + + /** + * Renders background, objects, overlay and controls. + * @param {CanvasRenderingContext2D} ctx + * @param {Array} objects to render + * @return {fabric.Canvas} instance + * @chainable + */ + renderCanvas: function(ctx, objects) { + this.calcViewportBoundaries(); + this.clearContext(ctx); + this.fire('before:render'); + if (this.clipTo) { + fabric.util.clipContext(this, ctx); + } + this._renderBackground(ctx); + + ctx.save(); + //apply viewport transform once for all rendering process + ctx.transform.apply(ctx, this.viewportTransform); + this._renderObjects(ctx, objects); + ctx.restore(); + if (!this.controlsAboveOverlay && this.interactive) { + this.drawControls(ctx); + } + if (this.clipTo) { + ctx.restore(); + } + this._renderOverlay(ctx); + if (this.controlsAboveOverlay && this.interactive) { + this.drawControls(ctx); + } + this.fire('after:render'); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Array} objects to render + */ + _renderObjects: function(ctx, objects) { + for (var i = 0, length = objects.length; i < length; ++i) { + objects[i] && objects[i].render(ctx); + } + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {string} property 'background' or 'overlay' + */ + _renderBackgroundOrOverlay: function(ctx, property) { + var object = this[property + 'Color']; + if (object) { + ctx.fillStyle = object.toLive + ? object.toLive(ctx, this) + : object; + + ctx.fillRect( + object.offsetX || 0, + object.offsetY || 0, + this.width, + this.height); + } + object = this[property + 'Image']; + if (object) { + if (this[property + 'Vpt']) { + ctx.save(); + ctx.transform.apply(ctx, this.viewportTransform); + } + object.render(ctx); + this[property + 'Vpt'] && ctx.restore(); + } + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderBackground: function(ctx) { + this._renderBackgroundOrOverlay(ctx, 'background'); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderOverlay: function(ctx) { + this._renderBackgroundOrOverlay(ctx, 'overlay'); + }, + + /** + * Returns coordinates of a center of canvas. + * Returned value is an object with top and left properties + * @return {Object} object with "top" and "left" number values + */ + getCenter: function () { + return { + top: this.getHeight() / 2, + left: this.getWidth() / 2 + }; + }, + + /** + * Centers object horizontally in the canvas + * You might need to call `setCoords` on an object after centering, to update controls area. + * @param {fabric.Object} object Object to center horizontally + * @return {fabric.Canvas} thisArg + */ + centerObjectH: function (object) { + return this._centerObject(object, new fabric.Point(this.getCenter().left, object.getCenterPoint().y)); + }, + + /** + * Centers object vertically in the canvas + * You might need to call `setCoords` on an object after centering, to update controls area. + * @param {fabric.Object} object Object to center vertically + * @return {fabric.Canvas} thisArg + * @chainable + */ + centerObjectV: function (object) { + return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, this.getCenter().top)); + }, + + /** + * Centers object vertically and horizontally in the canvas + * You might need to call `setCoords` on an object after centering, to update controls area. + * @param {fabric.Object} object Object to center vertically and horizontally + * @return {fabric.Canvas} thisArg + * @chainable + */ + centerObject: function(object) { + var center = this.getCenter(); + + return this._centerObject(object, new fabric.Point(center.left, center.top)); + }, + + /** + * Centers object vertically and horizontally in the viewport + * You might need to call `setCoords` on an object after centering, to update controls area. + * @param {fabric.Object} object Object to center vertically and horizontally + * @return {fabric.Canvas} thisArg + * @chainable + */ + viewportCenterObject: function(object) { + var vpCenter = this.getVpCenter(); + + return this._centerObject(object, vpCenter); + }, + + /** + * Centers object horizontally in the viewport, object.top is unchanged + * You might need to call `setCoords` on an object after centering, to update controls area. + * @param {fabric.Object} object Object to center vertically and horizontally + * @return {fabric.Canvas} thisArg + * @chainable + */ + viewportCenterObjectH: function(object) { + var vpCenter = this.getVpCenter(); + this._centerObject(object, new fabric.Point(vpCenter.x, object.getCenterPoint().y)); + return this; + }, + + /** + * Centers object Vertically in the viewport, object.top is unchanged + * You might need to call `setCoords` on an object after centering, to update controls area. + * @param {fabric.Object} object Object to center vertically and horizontally + * @return {fabric.Canvas} thisArg + * @chainable + */ + viewportCenterObjectV: function(object) { + var vpCenter = this.getVpCenter(); + + return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, vpCenter.y)); + }, + + /** + * Calculate the point in canvas that correspond to the center of actual viewport. + * @return {fabric.Point} vpCenter, viewport center + * @chainable + */ + getVpCenter: function() { + var center = this.getCenter(), + iVpt = invertTransform(this.viewportTransform); + return transformPoint({ x: center.left, y: center.top }, iVpt); + }, + + /** + * @private + * @param {fabric.Object} object Object to center + * @param {fabric.Point} center Center point + * @return {fabric.Canvas} thisArg + * @chainable + */ + _centerObject: function(object, center) { + object.setPositionByOrigin(center, 'center', 'center'); + this.renderAll(); + return this; + }, + + /** + * Returs dataless JSON representation of canvas + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {String} json string + */ + toDatalessJSON: function (propertiesToInclude) { + return this.toDatalessObject(propertiesToInclude); + }, + + /** + * Returns object representation of canvas + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function (propertiesToInclude) { + return this._toObjectMethod('toObject', propertiesToInclude); + }, + + /** + * Returns dataless object representation of canvas + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toDatalessObject: function (propertiesToInclude) { + return this._toObjectMethod('toDatalessObject', propertiesToInclude); + }, + + /** + * @private + */ + _toObjectMethod: function (methodName, propertiesToInclude) { + + var data = { + objects: this._toObjects(methodName, propertiesToInclude) + }; + + extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude)); + + fabric.util.populateWithProperties(this, data, propertiesToInclude); + + return data; + }, + + /** + * @private + */ + _toObjects: function(methodName, propertiesToInclude) { + return this.getObjects().filter(function(object) { + return !object.excludeFromExport; + }).map(function(instance) { + return this._toObject(instance, methodName, propertiesToInclude); + }, this); + }, + + /** + * @private + */ + _toObject: function(instance, methodName, propertiesToInclude) { + var originalValue; + + if (!this.includeDefaultValues) { + originalValue = instance.includeDefaultValues; + instance.includeDefaultValues = false; + } + + var object = instance[methodName](propertiesToInclude); + if (!this.includeDefaultValues) { + instance.includeDefaultValues = originalValue; + } + return object; + }, + + /** + * @private + */ + __serializeBgOverlay: function(methodName, propertiesToInclude) { + var data = { }, bgImage = this.backgroundImage, overlay = this.overlayImage; + + if (this.backgroundColor) { + data.background = this.backgroundColor.toObject + ? this.backgroundColor.toObject(propertiesToInclude) + : this.backgroundColor; + } + + if (this.overlayColor) { + data.overlay = this.overlayColor.toObject + ? this.overlayColor.toObject(propertiesToInclude) + : this.overlayColor; + } + if (bgImage && !bgImage.excludeFromExport) { + data.backgroundImage = this._toObject(bgImage, methodName, propertiesToInclude); + } + if (overlay && !overlay.excludeFromExport) { + data.overlayImage = this._toObject(overlay, methodName, propertiesToInclude); + } + + return data; + }, + + /* _TO_SVG_START_ */ + /** + * When true, getSvgTransform() will apply the StaticCanvas.viewportTransform to the SVG transformation. When true, + * a zoomed canvas will then produce zoomed SVG output. + * @type Boolean + * @default + */ + svgViewportTransformation: true, + + /** + * Returns SVG representation of canvas + * @function + * @param {Object} [options] Options object for SVG output + * @param {Boolean} [options.suppressPreamble=false] If true xml tag is not included + * @param {Object} [options.viewBox] SVG viewbox object + * @param {Number} [options.viewBox.x] x-cooridnate of viewbox + * @param {Number} [options.viewBox.y] y-coordinate of viewbox + * @param {Number} [options.viewBox.width] Width of viewbox + * @param {Number} [options.viewBox.height] Height of viewbox + * @param {String} [options.encoding=UTF-8] Encoding of SVG output + * @param {String} [options.width] desired width of svg with or without units + * @param {String} [options.height] desired height of svg with or without units + * @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation. + * @return {String} SVG string + * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization} + * @see {@link http://jsfiddle.net/fabricjs/jQ3ZZ/|jsFiddle demo} + * @example <caption>Normal SVG output</caption> + * var svg = canvas.toSVG(); + * @example <caption>SVG output without preamble (without &lt;?xml ../>)</caption> + * var svg = canvas.toSVG({suppressPreamble: true}); + * @example <caption>SVG output with viewBox attribute</caption> + * var svg = canvas.toSVG({ + * viewBox: { + * x: 100, + * y: 100, + * width: 200, + * height: 300 + * } + * }); + * @example <caption>SVG output with different encoding (default: UTF-8)</caption> + * var svg = canvas.toSVG({encoding: 'ISO-8859-1'}); + * @example <caption>Modify SVG output with reviver function</caption> + * var svg = canvas.toSVG(null, function(svg) { + * return svg.replace('stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; ', ''); + * }); + */ + toSVG: function(options, reviver) { + options || (options = { }); + + var markup = []; + + this._setSVGPreamble(markup, options); + this._setSVGHeader(markup, options); + + this._setSVGBgOverlayColor(markup, 'backgroundColor'); + this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver); + + this._setSVGObjects(markup, reviver); + + this._setSVGBgOverlayColor(markup, 'overlayColor'); + this._setSVGBgOverlayImage(markup, 'overlayImage', reviver); + + markup.push('</svg>'); + + return markup.join(''); + }, + + /** + * @private + */ + _setSVGPreamble: function(markup, options) { + if (options.suppressPreamble) { + return; + } + markup.push( + '<?xml version="1.0" encoding="', (options.encoding || 'UTF-8'), '" standalone="no" ?>\n', + '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" ', + '"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' + ); + }, + + /** + * @private + */ + _setSVGHeader: function(markup, options) { + var width = options.width || this.width, + height = options.height || this.height, + vpt, viewBox = 'viewBox="0 0 ' + this.width + ' ' + this.height + '" ', + NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS; + + if (options.viewBox) { + viewBox = 'viewBox="' + + options.viewBox.x + ' ' + + options.viewBox.y + ' ' + + options.viewBox.width + ' ' + + options.viewBox.height + '" '; + } + else { + if (this.svgViewportTransformation) { + vpt = this.viewportTransform; + viewBox = 'viewBox="' + + toFixed(-vpt[4] / vpt[0], NUM_FRACTION_DIGITS) + ' ' + + toFixed(-vpt[5] / vpt[3], NUM_FRACTION_DIGITS) + ' ' + + toFixed(this.width / vpt[0], NUM_FRACTION_DIGITS) + ' ' + + toFixed(this.height / vpt[3], NUM_FRACTION_DIGITS) + '" '; + } + } + + markup.push( + '<svg ', + 'xmlns="http://www.w3.org/2000/svg" ', + 'xmlns:xlink="http://www.w3.org/1999/xlink" ', + 'version="1.1" ', + 'width="', width, '" ', + 'height="', height, '" ', + viewBox, + 'xml:space="preserve">\n', + '<desc>Created with Fabric.js ', fabric.version, '</desc>\n', + '<defs>\n', + this.createSVGFontFacesMarkup(), + this.createSVGRefElementsMarkup(), + '</defs>\n' + ); + }, + + /** + * Creates markup containing SVG referenced elements like patterns, gradients etc. + * @return {String} + */ + createSVGRefElementsMarkup: function() { + var _this = this, + markup = ['backgroundColor', 'overlayColor'].map(function(prop) { + var fill = _this[prop]; + if (fill && fill.toLive) { + return fill.toSVG(_this, false); + } + }); + return markup.join(''); + }, + + /** + * Creates markup containing SVG font faces, + * font URLs for font faces must be collected by developers + * and are not extracted from the DOM by fabricjs + * @param {Array} objects Array of fabric objects + * @return {String} + */ + createSVGFontFacesMarkup: function() { + var markup = '', fontList = { }, obj, fontFamily, + style, row, rowIndex, _char, charIndex, + fontPaths = fabric.fontPaths, objects = this.getObjects(); + + for (var i = 0, len = objects.length; i < len; i++) { + obj = objects[i]; + fontFamily = obj.fontFamily; + if (obj.type.indexOf('text') === -1 || fontList[fontFamily] || !fontPaths[fontFamily]) { + continue; + } + fontList[fontFamily] = true; + if (!obj.styles) { + continue; + } + style = obj.styles; + for (rowIndex in style) { + row = style[rowIndex]; + for (charIndex in row) { + _char = row[charIndex]; + fontFamily = _char.fontFamily; + if (!fontList[fontFamily] && fontPaths[fontFamily]) { + fontList[fontFamily] = true; + } + } + } + } + + for (var j in fontList) { + markup += [ + '\t\t@font-face {\n', + '\t\t\tfont-family: \'', j, '\';\n', + '\t\t\tsrc: url(\'', fontPaths[j], '\');\n', + '\t\t}\n' + ].join(''); + } + + if (markup) { + markup = [ + '\t<style type="text/css">', + '<![CDATA[\n', + markup, + '', + '\n' + ].join(''); + } + + return markup; + }, + + /** + * @private + */ + _setSVGObjects: function(markup, reviver) { + var instance; + for (var i = 0, objects = this.getObjects(), len = objects.length; i < len; i++) { + instance = objects[i]; + if (instance.excludeFromExport) { + continue; + } + 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 + */ + _setSVGBgOverlayImage: function(markup, property, reviver) { + if (this[property] && this[property].toSVG) { + markup.push(this[property].toSVG(reviver)); + } + }, + + /** + * @private + */ + _setSVGBgOverlayColor: function(markup, property) { + var filler = this[property]; + if (!filler) { + return; + } + if (filler.toLive) { + var repeat = filler.repeat; + markup.push( + '\n' + ); + } + else { + markup.push( + '\n' + ); + } + }, + /* _TO_SVG_END_ */ + + /** + * Moves an object or the objects of a multiple selection + * to the bottom of the stack of drawn objects + * @param {fabric.Object} object Object to send to back + * @return {fabric.Canvas} thisArg + * @chainable + */ + sendToBack: function (object) { + if (!object) { + return this; + } + var activeGroup = this._activeGroup, + i, obj, objs; + if (object === activeGroup) { + objs = activeGroup._objects; + for (i = objs.length; i--;) { + obj = objs[i]; + removeFromArray(this._objects, obj); + this._objects.unshift(obj); + } + } + else { + removeFromArray(this._objects, object); + this._objects.unshift(object); + } + return this.renderAll && this.renderAll(); + }, + + /** + * Moves an object or the objects of a multiple selection + * to the top of the stack of drawn objects + * @param {fabric.Object} object Object to send + * @return {fabric.Canvas} thisArg + * @chainable + */ + bringToFront: function (object) { + if (!object) { + return this; + } + var activeGroup = this._activeGroup, + i, obj, objs; + if (object === activeGroup) { + objs = activeGroup._objects; + for (i = 0; i < objs.length; i++) { + obj = objs[i]; + removeFromArray(this._objects, obj); + this._objects.push(obj); + } + } + else { + removeFromArray(this._objects, object); + this._objects.push(object); + } + return this.renderAll && this.renderAll(); + }, + + /** + * Moves an object or a selection down in stack of drawn objects + * @param {fabric.Object} object Object to send + * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object + * @return {fabric.Canvas} thisArg + * @chainable + */ + sendBackwards: function (object, intersecting) { + if (!object) { + return this; + } + + var activeGroup = this._activeGroup, + i, obj, idx, newIdx, objs, objsMoved = 0; + + if (object === activeGroup) { + objs = activeGroup._objects; + for (i = 0; i < objs.length; i++) { + obj = objs[i]; + idx = this._objects.indexOf(obj); + if (idx > 0 + objsMoved) { + newIdx = idx - 1; + removeFromArray(this._objects, obj); + this._objects.splice(newIdx, 0, obj); + } + objsMoved++; + } + } + else { + idx = this._objects.indexOf(object); + if (idx !== 0) { + // if object is not on the bottom of stack + newIdx = this._findNewLowerIndex(object, idx, intersecting); + removeFromArray(this._objects, object); + this._objects.splice(newIdx, 0, object); + } + } + this.renderAll && this.renderAll(); + return this; + }, + + /** + * @private + */ + _findNewLowerIndex: function(object, idx, intersecting) { + var newIdx; + + if (intersecting) { + newIdx = idx; + + // traverse down the stack looking for the nearest intersecting object + for (var i = idx - 1; i >= 0; --i) { + + var isIntersecting = object.intersectsWithObject(this._objects[i]) || + object.isContainedWithinObject(this._objects[i]) || + this._objects[i].isContainedWithinObject(object); + + if (isIntersecting) { + newIdx = i; + break; + } + } + } + else { + newIdx = idx - 1; + } + + return newIdx; + }, + + /** + * Moves an object or a selection up in stack of drawn objects + * @param {fabric.Object} object Object to send + * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object + * @return {fabric.Canvas} thisArg + * @chainable + */ + bringForward: function (object, intersecting) { + if (!object) { + return this; + } + + var activeGroup = this._activeGroup, + i, obj, idx, newIdx, objs, objsMoved = 0; + + if (object === activeGroup) { + objs = activeGroup._objects; + for (i = objs.length; i--;) { + obj = objs[i]; + idx = this._objects.indexOf(obj); + if (idx < this._objects.length - 1 - objsMoved) { + newIdx = idx + 1; + removeFromArray(this._objects, obj); + this._objects.splice(newIdx, 0, obj); + } + objsMoved++; + } + } + else { + idx = this._objects.indexOf(object); + if (idx !== this._objects.length - 1) { + // if object is not on top of stack (last item in an array) + newIdx = this._findNewUpperIndex(object, idx, intersecting); + removeFromArray(this._objects, object); + this._objects.splice(newIdx, 0, object); + } + } + this.renderAll && this.renderAll(); + return this; + }, + + /** + * @private + */ + _findNewUpperIndex: function(object, idx, intersecting) { + var newIdx; + + if (intersecting) { + newIdx = idx; + + // traverse up the stack looking for the nearest intersecting object + for (var i = idx + 1; i < this._objects.length; ++i) { + + var isIntersecting = object.intersectsWithObject(this._objects[i]) || + object.isContainedWithinObject(this._objects[i]) || + this._objects[i].isContainedWithinObject(object); + + if (isIntersecting) { + newIdx = i; + break; + } + } + } + else { + newIdx = idx + 1; + } + + return newIdx; + }, + + /** + * Moves an object to specified level in stack of drawn objects + * @param {fabric.Object} object Object to send + * @param {Number} index Position to move to + * @return {fabric.Canvas} thisArg + * @chainable + */ + moveTo: function (object, index) { + removeFromArray(this._objects, object); + this._objects.splice(index, 0, object); + return this.renderAll && this.renderAll(); + }, + + /** + * Clears a canvas element and removes all event listeners + * @return {fabric.Canvas} thisArg + * @chainable + */ + dispose: function () { + this.clear(); + return this; + }, + + /** + * Returns a string representation of an instance + * @return {String} string representation of an instance + */ + toString: function () { + return '#'; + } + }); + + extend(fabric.StaticCanvas.prototype, fabric.Observable); + extend(fabric.StaticCanvas.prototype, fabric.Collection); + extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter); + + extend(fabric.StaticCanvas, /** @lends fabric.StaticCanvas */ { + + /** + * @static + * @type String + * @default + */ + EMPTY_JSON: '{"objects": [], "background": "white"}', + + /** + * Provides a way to check support of some of the canvas methods + * (either those of HTMLCanvasElement itself, or rendering context) + * + * @param {String} methodName Method to check support for; + * Could be one of "getImageData", "toDataURL", "toDataURLWithQuality" or "setLineDash" + * @return {Boolean | null} `true` if method is supported (or at least exists), + * `null` if canvas element or context can not be initialized + */ + supports: function (methodName) { + var el = fabric.util.createCanvasElement(); + + if (!el || !el.getContext) { + return null; + } + + var ctx = el.getContext('2d'); + if (!ctx) { + return null; + } + + switch (methodName) { + + case 'getImageData': + return typeof ctx.getImageData !== 'undefined'; + + case 'setLineDash': + return typeof ctx.setLineDash !== 'undefined'; + + case 'toDataURL': + return typeof el.toDataURL !== 'undefined'; + + case 'toDataURLWithQuality': + try { + el.toDataURL('image/jpeg', 0); + return true; + } + catch (e) { } + return false; + + default: + return null; + } + } + }); + + /** + * Returns JSON representation of canvas + * @function + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {String} JSON string + * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization} + * @see {@link http://jsfiddle.net/fabricjs/pec86/|jsFiddle demo} + * @example JSON without additional properties + * var json = canvas.toJSON(); + * @example JSON with additional properties included + * var json = canvas.toJSON(['lockMovementX', 'lockMovementY', 'lockRotation', 'lockScalingX', 'lockScalingY', 'lockUniScaling']); + * @example JSON without default values + * canvas.includeDefaultValues = false; + * var json = canvas.toJSON(); + */ + fabric.StaticCanvas.prototype.toJSON = fabric.StaticCanvas.prototype.toObject; + +})(); + + +/** + * BaseBrush class + * @class fabric.BaseBrush + * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo} + */ +fabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ { + + /** + * Color of a brush + * @type String + * @default + */ + color: 'rgb(0, 0, 0)', + + /** + * Width of a brush + * @type Number + * @default + */ + width: 1, + + /** + * Shadow object representing shadow of this shape. + * Backwards incompatibility note: This property replaces "shadowColor" (String), "shadowOffsetX" (Number), + * "shadowOffsetY" (Number) and "shadowBlur" (Number) since v1.2.12 + * @type fabric.Shadow + * @default + */ + shadow: null, + + /** + * Line endings style of a brush (one of "butt", "round", "square") + * @type String + * @default + */ + strokeLineCap: 'round', + + /** + * Corner style of a brush (one of "bevil", "round", "miter") + * @type String + * @default + */ + strokeLineJoin: 'round', + + /** + * Stroke Dash Array. + * @type Array + * @default + */ + strokeDashArray: null, + + /** + * Sets shadow of an object + * @param {Object|String} [options] Options object or string (e.g. "2px 2px 10px rgba(0,0,0,0.2)") + * @return {fabric.Object} thisArg + * @chainable + */ + setShadow: function(options) { + this.shadow = new fabric.Shadow(options); + return this; + }, + + /** + * Sets brush styles + * @private + */ + _setBrushStyles: function() { + var ctx = this.canvas.contextTop; + + ctx.strokeStyle = this.color; + ctx.lineWidth = this.width; + ctx.lineCap = this.strokeLineCap; + ctx.lineJoin = this.strokeLineJoin; + if (this.strokeDashArray && fabric.StaticCanvas.supports('setLineDash')) { + ctx.setLineDash(this.strokeDashArray); + } + }, + + /** + * Sets brush shadow styles + * @private + */ + _setShadow: function() { + if (!this.shadow) { + return; + } + + var ctx = this.canvas.contextTop, + zoom = this.canvas.getZoom(); + + ctx.shadowColor = this.shadow.color; + ctx.shadowBlur = this.shadow.blur * zoom; + ctx.shadowOffsetX = this.shadow.offsetX * zoom; + ctx.shadowOffsetY = this.shadow.offsetY * zoom; + }, + + /** + * Removes brush shadow styles + * @private + */ + _resetShadow: function() { + var ctx = this.canvas.contextTop; + + ctx.shadowColor = ''; + ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0; + } +}); + + +(function() { + + /** + * PencilBrush class + * @class fabric.PencilBrush + * @extends fabric.BaseBrush + */ + fabric.PencilBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.PencilBrush.prototype */ { + + /** + * Constructor + * @param {fabric.Canvas} canvas + * @return {fabric.PencilBrush} Instance of a pencil brush + */ + initialize: function(canvas) { + this.canvas = canvas; + this._points = []; + }, + + /** + * Inovoked on mouse down + * @param {Object} pointer + */ + onMouseDown: function(pointer) { + this._prepareForDrawing(pointer); + // capture coordinates immediately + // this allows to draw dots (when movement never occurs) + this._captureDrawingPath(pointer); + this._render(); + }, + + /** + * Inovoked on mouse move + * @param {Object} pointer + */ + onMouseMove: function(pointer) { + this._captureDrawingPath(pointer); + // redraw curve + // clear top canvas + this.canvas.clearContext(this.canvas.contextTop); + this._render(); + }, + + /** + * Invoked on mouse up + */ + onMouseUp: function() { + this._finalizeAndAddPath(); + }, + + /** + * @private + * @param {Object} pointer Actual mouse position related to the canvas. + */ + _prepareForDrawing: function(pointer) { + + var p = new fabric.Point(pointer.x, pointer.y); + + this._reset(); + this._addPoint(p); + + this.canvas.contextTop.moveTo(p.x, p.y); + }, + + /** + * @private + * @param {fabric.Point} point Point to be added to points array + */ + _addPoint: function(point) { + if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) { + return; + } + this._points.push(point); + }, + + /** + * Clear points array and set contextTop canvas style. + * @private + */ + _reset: function() { + this._points.length = 0; + + this._setBrushStyles(); + this._setShadow(); + }, + + /** + * @private + * @param {Object} pointer Actual mouse position related to the canvas. + */ + _captureDrawingPath: function(pointer) { + var pointerPoint = new fabric.Point(pointer.x, pointer.y); + this._addPoint(pointerPoint); + }, + + /** + * Draw a smooth path on the topCanvas using quadraticCurveTo + * @private + */ + _render: function() { + var ctx = this.canvas.contextTop, i, len, + v = this.canvas.viewportTransform, + p1 = this._points[0], + p2 = this._points[1]; + + ctx.save(); + ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]); + ctx.beginPath(); + + //if we only have 2 points in the path and they are the same + //it means that the user only clicked the canvas without moving the mouse + //then we should be drawing a dot. A path isn't drawn between two identical dots + //that's why we set them apart a bit + if (this._points.length === 2 && p1.x === p2.x && p1.y === p2.y) { + var width = this.width / 1000; + p1 = new fabric.Point(p1.x, p1.y); + p2 = new fabric.Point(p2.x, p2.y); + p1.x -= width; + p2.x += width; + } + ctx.moveTo(p1.x, p1.y); + + for (i = 1, len = this._points.length; i < len; i++) { + // we pick the point between pi + 1 & pi + 2 as the + // end point and p1 as our control point. + var midPoint = p1.midPointFrom(p2); + ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y); + + p1 = this._points[i]; + p2 = this._points[i + 1]; + } + // Draw last line as a straight line while + // we wait for the next point to be able to calculate + // the bezier control point + ctx.lineTo(p1.x, p1.y); + ctx.stroke(); + ctx.restore(); + }, + + /** + * Converts points to SVG path + * @param {Array} points Array of points + * @return {String} SVG path + */ + convertPointsToSVGPath: function(points) { + var path = [], i, width = this.width / 1000, + p1 = new fabric.Point(points[0].x, points[0].y), + p2 = new fabric.Point(points[1].x, points[1].y), + len = points.length, multSignX = 1, multSignY = 1, manyPoints = len > 2; + + if (manyPoints) { + multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1; + multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1; + } + path.push('M ', p1.x - multSignX * width, ' ', p1.y - multSignY * width, ' '); + for (i = 1; i < len; i++) { + if (!p1.eq(p2)) { + var midPoint = p1.midPointFrom(p2); + // p1 is our bezier control point + // midpoint is our endpoint + // start point is p(i-1) value. + path.push('Q ', p1.x, ' ', p1.y, ' ', midPoint.x, ' ', midPoint.y, ' '); + } + p1 = points[i]; + if ((i + 1) < points.length) { + p2 = points[i + 1]; + } + } + if (manyPoints) { + multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1; + multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1; + } + path.push('L ', p1.x + multSignX * width, ' ', p1.y + multSignY * width); + return path; + }, + + /** + * Creates fabric.Path object to add on canvas + * @param {String} pathData Path data + * @return {fabric.Path} Path to add on canvas + */ + 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' + }); + var position = new fabric.Point(path.left, path.top); + path.originX = fabric.Object.prototype.originX; + path.originY = fabric.Object.prototype.originY; + position = path.translateToGivenOrigin( + position, 'center', 'center', path.originX, path.originY); + path.top = position.y; + path.left = position.x; + if (this.shadow) { + this.shadow.affectStroke = true; + path.setShadow(this.shadow); + } + + return path; + }, + + /** + * On mouseup after drawing the path on contextTop canvas + * we use the points captured to create an new fabric path object + * and add it to the fabric canvas. + */ + _finalizeAndAddPath: function() { + var ctx = this.canvas.contextTop; + ctx.closePath(); + + var pathData = this.convertPointsToSVGPath(this._points).join(''); + if (pathData === 'M 0 0 Q 0 0 0 0 L 0 0') { + // do not create 0 width/height paths, as they are + // rendered inconsistently across browsers + // Firefox 4, for example, renders a dot, + // whereas Chrome 10 renders nothing + this.canvas.renderAll(); + return; + } + + var path = this.createPath(pathData); + + this.canvas.add(path); + path.setCoords(); + + this.canvas.clearContext(this.canvas.contextTop); + this._resetShadow(); + this.canvas.renderAll(); + + // fire event 'path' created + this.canvas.fire('path:created', { path: path }); + } + }); +})(); + + +/** + * CircleBrush class + * @class fabric.CircleBrush + */ +fabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.CircleBrush.prototype */ { + + /** + * Width of a brush + * @type Number + * @default + */ + width: 10, + + /** + * Constructor + * @param {fabric.Canvas} canvas + * @return {fabric.CircleBrush} Instance of a circle brush + */ + initialize: function(canvas) { + this.canvas = canvas; + this.points = []; + }, + + /** + * Invoked inside on mouse down and mouse move + * @param {Object} pointer + */ + drawDot: function(pointer) { + var point = this.addPoint(pointer), + ctx = this.canvas.contextTop, + v = this.canvas.viewportTransform; + ctx.save(); + ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]); + + ctx.fillStyle = point.fill; + ctx.beginPath(); + ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false); + ctx.closePath(); + ctx.fill(); + + ctx.restore(); + }, + + /** + * Invoked on mouse down + */ + onMouseDown: function(pointer) { + this.points.length = 0; + this.canvas.clearContext(this.canvas.contextTop); + this._setShadow(); + this.drawDot(pointer); + }, + + /** + * Invoked on mouse move + * @param {Object} pointer + */ + onMouseMove: function(pointer) { + this.drawDot(pointer); + }, + + /** + * Invoked on mouse up + */ + onMouseUp: function() { + var originalRenderOnAddRemove = this.canvas.renderOnAddRemove; + this.canvas.renderOnAddRemove = false; + + var circles = []; + + for (var i = 0, len = this.points.length; i < len; i++) { + var point = this.points[i], + circle = new fabric.Circle({ + radius: point.radius, + left: point.x, + top: point.y, + originX: 'center', + originY: 'center', + fill: point.fill + }); + + this.shadow && circle.setShadow(this.shadow); + + circles.push(circle); + } + var group = new fabric.Group(circles, { originX: 'center', originY: 'center' }); + group.canvas = this.canvas; + + this.canvas.add(group); + this.canvas.fire('path:created', { path: group }); + + this.canvas.clearContext(this.canvas.contextTop); + this._resetShadow(); + this.canvas.renderOnAddRemove = originalRenderOnAddRemove; + this.canvas.renderAll(); + }, + + /** + * @param {Object} pointer + * @return {fabric.Point} Just added pointer point + */ + addPoint: function(pointer) { + var pointerPoint = new fabric.Point(pointer.x, pointer.y), + + circleRadius = fabric.util.getRandomInt( + Math.max(0, this.width - 20), this.width + 20) / 2, + + circleColor = new fabric.Color(this.color) + .setAlpha(fabric.util.getRandomInt(0, 100) / 100) + .toRgba(); + + pointerPoint.radius = circleRadius; + pointerPoint.fill = circleColor; + + this.points.push(pointerPoint); + + return pointerPoint; + } +}); + + +/** + * SprayBrush class + * @class fabric.SprayBrush + */ +fabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric.SprayBrush.prototype */ { + + /** + * Width of a spray + * @type Number + * @default + */ + width: 10, + + /** + * Density of a spray (number of dots per chunk) + * @type Number + * @default + */ + density: 20, + + /** + * Width of spray dots + * @type Number + * @default + */ + dotWidth: 1, + + /** + * Width variance of spray dots + * @type Number + * @default + */ + dotWidthVariance: 1, + + /** + * Whether opacity of a dot should be random + * @type Boolean + * @default + */ + randomOpacity: false, + + /** + * Whether overlapping dots (rectangles) should be removed (for performance reasons) + * @type Boolean + * @default + */ + optimizeOverlapping: true, + + /** + * Constructor + * @param {fabric.Canvas} canvas + * @return {fabric.SprayBrush} Instance of a spray brush + */ + initialize: function(canvas) { + this.canvas = canvas; + this.sprayChunks = []; + }, + + /** + * Invoked on mouse down + * @param {Object} pointer + */ + onMouseDown: function(pointer) { + this.sprayChunks.length = 0; + this.canvas.clearContext(this.canvas.contextTop); + this._setShadow(); + + this.addSprayChunk(pointer); + this.render(); + }, + + /** + * Invoked on mouse move + * @param {Object} pointer + */ + onMouseMove: function(pointer) { + this.addSprayChunk(pointer); + this.render(); + }, + + /** + * Invoked on mouse up + */ + onMouseUp: function() { + var originalRenderOnAddRemove = this.canvas.renderOnAddRemove; + this.canvas.renderOnAddRemove = false; + + var rects = []; + + for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) { + var sprayChunk = this.sprayChunks[i]; + + for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) { + + var rect = new fabric.Rect({ + width: sprayChunk[j].width, + height: sprayChunk[j].width, + left: sprayChunk[j].x + 1, + top: sprayChunk[j].y + 1, + originX: 'center', + originY: 'center', + fill: this.color + }); + + this.shadow && rect.setShadow(this.shadow); + rects.push(rect); + } + } + + if (this.optimizeOverlapping) { + rects = this._getOptimizedRects(rects); + } + + var group = new fabric.Group(rects, { originX: 'center', originY: 'center' }); + group.canvas = this.canvas; + + this.canvas.add(group); + this.canvas.fire('path:created', { path: group }); + + this.canvas.clearContext(this.canvas.contextTop); + this._resetShadow(); + this.canvas.renderOnAddRemove = originalRenderOnAddRemove; + this.canvas.renderAll(); + }, + + /** + * @private + * @param {Array} rects + */ + _getOptimizedRects: function(rects) { + + // avoid creating duplicate rects at the same coordinates + var uniqueRects = { }, key; + + for (var i = 0, len = rects.length; i < len; i++) { + key = rects[i].left + '' + rects[i].top; + if (!uniqueRects[key]) { + uniqueRects[key] = rects[i]; + } + } + var uniqueRectsArray = []; + for (key in uniqueRects) { + uniqueRectsArray.push(uniqueRects[key]); + } + + return uniqueRectsArray; + }, + + /** + * Renders brush + */ + render: function() { + var ctx = this.canvas.contextTop; + ctx.fillStyle = this.color; + + var v = this.canvas.viewportTransform; + ctx.save(); + ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]); + + for (var i = 0, len = this.sprayChunkPoints.length; i < len; i++) { + var point = this.sprayChunkPoints[i]; + if (typeof point.opacity !== 'undefined') { + ctx.globalAlpha = point.opacity; + } + ctx.fillRect(point.x, point.y, point.width, point.width); + } + ctx.restore(); + }, + + /** + * @param {Object} pointer + */ + addSprayChunk: function(pointer) { + this.sprayChunkPoints = []; + + var x, y, width, radius = this.width / 2; + + for (var i = 0; i < this.density; i++) { + + x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius); + y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius); + + if (this.dotWidthVariance) { + width = fabric.util.getRandomInt( + // bottom clamp width to 1 + Math.max(1, this.dotWidth - this.dotWidthVariance), + this.dotWidth + this.dotWidthVariance); + } + else { + width = this.dotWidth; + } + + var point = new fabric.Point(x, y); + point.width = width; + + if (this.randomOpacity) { + point.opacity = fabric.util.getRandomInt(0, 100) / 100; + } + + this.sprayChunkPoints.push(point); + } + + this.sprayChunks.push(this.sprayChunkPoints); + } +}); + + +/** + * PatternBrush class + * @class fabric.PatternBrush + * @extends fabric.BaseBrush + */ +fabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fabric.PatternBrush.prototype */ { + + getPatternSrc: function() { + + var dotWidth = 20, + dotDistance = 5, + patternCanvas = fabric.document.createElement('canvas'), + patternCtx = patternCanvas.getContext('2d'); + + patternCanvas.width = patternCanvas.height = dotWidth + dotDistance; + + patternCtx.fillStyle = this.color; + patternCtx.beginPath(); + patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false); + patternCtx.closePath(); + patternCtx.fill(); + + return patternCanvas; + }, + + getPatternSrcFunction: function() { + return String(this.getPatternSrc).replace('this.color', '"' + this.color + '"'); + }, + + /** + * Creates "pattern" instance property + */ + getPattern: function() { + return this.canvas.contextTop.createPattern(this.source || this.getPatternSrc(), 'repeat'); + }, + + /** + * Sets brush styles + */ + _setBrushStyles: function() { + this.callSuper('_setBrushStyles'); + this.canvas.contextTop.strokeStyle = this.getPattern(); + }, + + /** + * Creates path + */ + createPath: function(pathData) { + var path = this.callSuper('createPath', pathData), + topLeft = path._getLeftTopCoords().scalarAdd(path.strokeWidth / 2); + + path.stroke = new fabric.Pattern({ + source: this.source || this.getPatternSrcFunction(), + offsetX: -topLeft.x, + offsetY: -topLeft.y + }); + return path; + } +}); + + +(function() { + + 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 = 0.5; + + /** + * Canvas class + * @class fabric.Canvas + * @extends fabric.StaticCanvas + * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#canvas} + * @see {@link fabric.Canvas#initialize} for constructor definition + * + * @fires object:added + * @fires object:modified + * @fires object:rotating + * @fires object:scaling + * @fires object:moving + * @fires object:selected + * + * @fires before:selection:cleared + * @fires selection:cleared + * @fires selection:created + * + * @fires path:created + * @fires mouse:down + * @fires mouse:move + * @fires mouse:up + * @fires mouse:over + * @fires mouse:out + * + */ + fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ { + + /** + * Constructor + * @param {HTMLElement | String} el <canvas> element to initialize instance on + * @param {Object} [options] Options object + * @return {Object} thisArg + */ + initialize: function(el, options) { + options || (options = { }); + + this._initStatic(el, options); + this._initInteractive(); + this._createCacheCanvas(); + }, + + /** + * When true, objects can be transformed by one side (unproportionally) + * @type Boolean + * @default + */ + uniScaleTransform: false, + + /** + * Indicates which key enable unproportional scaling + * values: 'altKey', 'shiftKey', 'ctrlKey'. + * If `null` or 'none' or any other string that is not a modifier key + * feature is disabled feature disabled. + * @since 1.6.2 + * @type String + * @default + */ + uniScaleKey: 'shiftKey', + + /** + * When true, objects use center point as the origin of scale transformation. + * Backwards incompatibility note: This property replaces "centerTransform" (Boolean). + * @since 1.3.4 + * @type Boolean + * @default + */ + centeredScaling: false, + + /** + * When true, objects use center point as the origin of rotate transformation. + * Backwards incompatibility note: This property replaces "centerTransform" (Boolean). + * @since 1.3.4 + * @type Boolean + * @default + */ + centeredRotation: false, + + /** + * Indicates which key enable centered Transfrom + * values: 'altKey', 'shiftKey', 'ctrlKey'. + * If `null` or 'none' or any other string that is not a modifier key + * feature is disabled feature disabled. + * @since 1.6.2 + * @type String + * @default + */ + centeredKey: 'altKey', + + /** + * Indicates which key enable alternate action on corner + * values: 'altKey', 'shiftKey', 'ctrlKey'. + * If `null` or 'none' or any other string that is not a modifier key + * feature is disabled feature disabled. + * @since 1.6.2 + * @type String + * @default + */ + altActionKey: 'shiftKey', + + /** + * Indicates that canvas is interactive. This property should not be changed. + * @type Boolean + * @default + */ + interactive: true, + + /** + * Indicates whether group selection should be enabled + * @type Boolean + * @default + */ + selection: true, + + /** + * Indicates which key enable multiple click selection + * values: 'altKey', 'shiftKey', 'ctrlKey'. + * If `null` or 'none' or any other string that is not a modifier key + * feature is disabled feature disabled. + * @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'. + * If `null` or 'none' or any other string that is not a modifier key + * feature is disabled feature disabled. + * @since 1.6.5 + * @type null|String + * @default + */ + altSelectionKey: null, + + /** + * Color of selection + * @type String + * @default + */ + selectionColor: 'rgba(100, 100, 255, 0.3)', // blue + + /** + * Default dash array pattern + * If not empty the selection border is dashed + * @type Array + */ + selectionDashArray: [], + + /** + * Color of the border of selection (usually slightly darker than color of selection itself) + * @type String + * @default + */ + selectionBorderColor: 'rgba(255, 255, 255, 0.3)', + + /** + * Width of a line used in object/group selection + * @type Number + * @default + */ + selectionLineWidth: 1, + + /** + * Default cursor value used when hovering over an object on canvas + * @type String + * @default + */ + hoverCursor: 'move', + + /** + * Default cursor value used when moving an object on canvas + * @type String + * @default + */ + moveCursor: 'move', + + /** + * Default cursor value used for the entire canvas + * @type String + * @default + */ + defaultCursor: 'default', + + /** + * Cursor value used during free drawing + * @type String + * @default + */ + freeDrawingCursor: 'crosshair', + + /** + * Cursor value used for rotation point + * @type String + * @default + */ + rotationCursor: 'crosshair', + + /** + * Default element class that's given to wrapper (div) element of canvas + * @type String + * @default + */ + containerClass: 'canvas-container', + + /** + * When true, object detection happens on per-pixel basis rather than on per-bounding-box + * @type Boolean + * @default + */ + perPixelTargetFind: false, + + /** + * Number of pixels around target pixel to tolerate (consider active) during object detection + * @type Number + * @default + */ + targetFindTolerance: 0, + + /** + * When true, target detection is skipped when hovering over canvas. This can be used to improve performance. + * @type Boolean + * @default + */ + skipTargetFind: false, + + /** + * When true, mouse events on canvas (mousedown/mousemove/mouseup) result in free drawing. + * After mousedown, mousemove creates a shape, + * and then mouseup finalizes it and adds an instance of `fabric.Path` onto canvas. + * @tutorial {@link http://fabricjs.com/fabric-intro-part-4#free_drawing} + * @type Boolean + * @default + */ + 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 + * @type Boolean + * @default + */ + preserveObjectStacking: false, + + /** + * Indicates the angle that an object will lock to while rotating. + * @type Number + * @since 1.6.7 + * @default + */ + snapAngle: 0, + + /** + * Indicates the distance from the snapAngle the rotation will lock to the snapAngle. + * When `null`, the snapThreshold will default to the snapAngle. + * @type null|Number + * @since 1.6.7 + * @default + */ + snapThreshold: null, + + /** + * 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, + + /** + * Indicates if the canvas can fire middle click events + * @type Boolean + * @since 1.7.8 + * @default + */ + fireMiddleClick: false, + + /** + * @private + */ + _initInteractive: function() { + this._currentTransform = null; + this._groupSelector = null; + this._initWrapperElement(); + this._createUpperCanvas(); + this._initEventListeners(); + + this._initRetinaScaling(); + + this.freeDrawingBrush = fabric.PencilBrush && new fabric.PencilBrush(this); + + this.calcOffset(); + }, + + /** + * Divides objects in two groups, one to render immediately + * and one to render as activeGroup. + * @return {Array} objects to render immediately and pushes the other in the activeGroup. + */ + _chooseObjectsToRender: function() { + var activeGroup = this.getActiveGroup(), + activeObject = this.getActiveObject(), + object, objsToRender = [], activeGroupObjects = []; + + if ((activeGroup || activeObject) && !this.preserveObjectStacking) { + for (var i = 0, length = this._objects.length; i < length; i++) { + object = this._objects[i]; + if ((!activeGroup || !activeGroup.contains(object)) && object !== activeObject) { + objsToRender.push(object); + } + else { + activeGroupObjects.push(object); + } + } + if (activeGroup) { + activeGroup._set('_objects', activeGroupObjects); + objsToRender.push(activeGroup); + } + activeObject && objsToRender.push(activeObject); + } + else { + objsToRender = this._objects; + } + return objsToRender; + }, + + /** + * Renders both the top canvas and the secondary container canvas. + * @return {fabric.Canvas} instance + * @chainable + */ + renderAll: function () { + if (this.contextTopDirty && !this._groupSelector && !this.isDrawingMode) { + this.clearContext(this.contextTop); + this.contextTopDirty = false; + } + var canvasToDrawOn = this.contextContainer; + this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender()); + return this; + }, + + /** + * Method to render only the top canvas. + * Also used to render the group selection box. + * @return {fabric.Canvas} thisArg + * @chainable + */ + renderTop: function () { + var ctx = this.contextTop; + this.clearContext(ctx); + + // we render the top context - last object + if (this.selection && this._groupSelector) { + this._drawSelection(ctx); + } + + this.fire('after:render'); + this.contextTopDirty = true; + return this; + }, + + /** + * Resets the current transform to its original values and chooses the type of resizing based on the event + * @private + */ + _resetCurrentTransform: function() { + var t = this._currentTransform; + + t.target.set({ + scaleX: t.original.scaleX, + scaleY: t.original.scaleY, + skewX: t.original.skewX, + skewY: t.original.skewY, + left: t.original.left, + 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.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; + } + }, + + /** + * Checks if point is contained within an area of given object + * @param {Event} e Event object + * @param {fabric.Object} target Object to test against + * @param {Object} [point] x,y object of point coordinates we want to check. + * @return {Boolean} true if point is contained within an area of given object + */ + containsPoint: function (e, target, point) { + var ignoreZoom = true, + pointer = point || this.getPointer(e, ignoreZoom), + xy; + + if (target.group && target.group === this.getActiveGroup()) { + xy = this._normalizePointer(target.group, pointer); + } + else { + xy = { x: pointer.x, y: pointer.y }; + } + // http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html + // http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html + return (target.containsPoint(xy) || target._findTargetCorner(pointer)); + }, + + /** + * @private + */ + _normalizePointer: function (object, pointer) { + var m = object.calcTransformMatrix(), + invertedM = fabric.util.invertTransform(m), + vptPointer = this.restorePointerVpt(pointer); + return fabric.util.transformPoint(vptPointer, invertedM); + }, + + /** + * Returns true if object is transparent at a certain location + * @param {fabric.Object} target Object to check + * @param {Number} x Left coordinate + * @param {Number} y Top coordinate + * @return {Boolean} + */ + isTargetTransparent: function (target, x, y) { + var hasBorders = target.hasBorders, + transparentCorners = target.transparentCorners, + ctx = this.contextCache, + originalColor = target.selectionBackgroundColor; + + target.hasBorders = target.transparentCorners = false; + target.selectionBackgroundColor = ''; + + ctx.save(); + ctx.transform.apply(ctx, this.viewportTransform); + target.render(ctx); + ctx.restore(); + + target.active && target._renderControls(ctx); + + target.hasBorders = hasBorders; + target.transparentCorners = transparentCorners; + target.selectionBackgroundColor = originalColor; + + var isTransparent = fabric.util.isTransparent( + ctx, x, y, this.targetFindTolerance); + + this.clearContext(ctx); + + return isTransparent; + }, + + /** + * @private + * @param {Event} e Event object + * @param {fabric.Object} target + */ + _shouldClearSelection: function (e, target) { + var activeGroup = this.getActiveGroup(), + activeObject = this.getActiveObject(); + + return ( + !target + || + (target && + activeGroup && + !activeGroup.contains(target) && + activeGroup !== target && + !e[this.selectionKey]) + || + (target && !target.evented) + || + (target && + !target.selectable && + activeObject && + activeObject !== target) + ); + }, + + /** + * @private + * @param {fabric.Object} target + */ + _shouldCenterTransform: function (target) { + if (!target) { + return; + } + + var t = this._currentTransform, + centerTransform; + + if (t.action === 'scale' || t.action === 'scaleX' || t.action === 'scaleY') { + centerTransform = this.centeredScaling || target.centeredScaling; + } + else if (t.action === 'rotate') { + centerTransform = this.centeredRotation || target.centeredRotation; + } + + return centerTransform ? !t.altKey : t.altKey; + }, + + /** + * @private + */ + _getOriginFromCorner: function(target, corner) { + var origin = { + x: target.originX, + y: target.originY + }; + + if (corner === 'ml' || corner === 'tl' || corner === 'bl') { + origin.x = 'right'; + } + else if (corner === 'mr' || corner === 'tr' || corner === 'br') { + origin.x = 'left'; + } + + if (corner === 'tl' || corner === 'mt' || corner === 'tr') { + origin.y = 'bottom'; + } + else if (corner === 'bl' || corner === 'mb' || corner === 'br') { + origin.y = 'top'; + } + + return origin; + }, + + /** + * @private + */ + _getActionFromCorner: function(target, corner, e) { + if (!corner) { + return 'drag'; + } + + switch (corner) { + case 'mtr': + return 'rotate'; + case 'ml': + case 'mr': + return e[this.altActionKey] ? 'skewY' : 'scaleX'; + case 'mt': + case 'mb': + return e[this.altActionKey] ? 'skewX' : 'scaleY'; + default: + return 'scale'; + } + }, + + /** + * @private + * @param {Event} e Event object + * @param {fabric.Object} target + */ + _setupCurrentTransform: function (e, target) { + if (!target) { + return; + } + + var pointer = this.getPointer(e), + corner = target._findTargetCorner(this.getPointer(e, true)), + action = this._getActionFromCorner(target, corner, e), + origin = this._getOriginFromCorner(target, corner); + + this._currentTransform = { + target: target, + action: action, + corner: corner, + scaleX: target.scaleX, + scaleY: target.scaleY, + skewX: target.skewX, + skewY: target.skewY, + offsetX: pointer.x - target.left, + offsetY: pointer.y - target.top, + originX: origin.x, + originY: origin.y, + ex: pointer.x, + 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, + mouseYSign: 1, + shiftKey: e.shiftKey, + altKey: e[this.centeredKey] + }; + + this._currentTransform.original = { + left: target.left, + top: target.top, + scaleX: target.scaleX, + scaleY: target.scaleY, + skewX: target.skewX, + skewY: target.skewY, + originX: origin.x, + originY: origin.y + }; + + this._resetCurrentTransform(); + }, + + /** + * Translates object by "setting" its left/top + * @private + * @param {Number} x pointer's x coordinate + * @param {Number} y pointer's y coordinate + * @return {Boolean} true if the translation occurred + */ + _translateObject: function (x, y) { + var transform = this._currentTransform, + target = transform.target, + newLeft = x - transform.offsetX, + newTop = y - transform.offsetY, + moveX = !target.get('lockMovementX') && target.left !== newLeft, + moveY = !target.get('lockMovementY') && target.top !== newTop; + + moveX && target.set('left', newLeft); + moveY && target.set('top', newTop); + return moveX || moveY; + }, + + /** + * Check if we are increasing a positive skew or lower it, + * checking mouse direction and pressed corner. + * @private + */ + _changeSkewTransformOrigin: function(mouseMove, t, by) { + var property = 'originX', origins = { 0: 'center' }, + skew = t.target.skewX, originA = 'left', originB = 'right', + corner = t.corner === 'mt' || t.corner === 'ml' ? 1 : -1, + flipSign = 1; + + mouseMove = mouseMove > 0 ? 1 : -1; + if (by === 'y') { + skew = t.target.skewY; + originA = 'top'; + originB = 'bottom'; + property = 'originY'; + } + origins[-1] = originA; + origins[1] = originB; + + t.target.flipX && (flipSign *= -1); + t.target.flipY && (flipSign *= -1); + + if (skew === 0) { + t.skewSign = -corner * mouseMove * flipSign; + t[property] = origins[-mouseMove]; + } + else { + skew = skew > 0 ? 1 : -1; + t.skewSign = skew; + t[property] = origins[skew * corner * flipSign]; + } + }, + + /** + * Skew object by mouse events + * @private + * @param {Number} x pointer's x coordinate + * @param {Number} y pointer's y coordinate + * @param {String} by Either 'x' or 'y' + * @return {Boolean} true if the skewing occurred + */ + _skewObject: function (x, y, by) { + var t = this._currentTransform, + target = t.target, skewed = false, + lockSkewingX = target.get('lockSkewingX'), + lockSkewingY = target.get('lockSkewingY'); + + if ((lockSkewingX && by === 'x') || (lockSkewingY && by === 'y')) { + return false; + } + + // Get the constraint point + 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]; + constraintPosition = target.translateToOriginPoint(center, t.originX, t.originY); + // Actually skew the object + skewed = this._setObjectSkew(actualMouseByOrigin, t, by, dim); + t.lastX = x; + t.lastY = y; + // Make sure the constraints apply + target.setPositionByOrigin(constraintPosition, t.originX, t.originY); + return skewed; + }, + + /** + * Set object skew + * @private + * @return {Boolean} true if the skewing occurred + */ + _setObjectSkew: function(localMouse, transform, by, _dim) { + var target = transform.target, newValue, skewed = false, + skewSign = transform.skewSign, newDim, dimNoSkew, + otherBy, _otherBy, _by, newDimMouse, skewX, skewY; + + if (by === 'x') { + otherBy = 'y'; + _otherBy = 'Y'; + _by = 'X'; + skewX = 0; + skewY = target.skewY; + } + else { + otherBy = 'x'; + _otherBy = 'X'; + _by = 'Y'; + skewX = target.skewX; + skewY = 0; + } + + dimNoSkew = target._getTransformedDimensions(skewX, skewY); + newDimMouse = 2 * Math.abs(localMouse) - dimNoSkew[by]; + if (newDimMouse <= 2) { + newValue = 0; + } + else { + newValue = skewSign * Math.atan((newDimMouse / target['scale' + _by]) / + (dimNoSkew[otherBy] / target['scale' + _otherBy])); + newValue = fabric.util.radiansToDegrees(newValue); + } + skewed = target['skew' + _by] !== newValue; + target.set('skew' + _by, newValue); + if (target['skew' + _otherBy] !== 0) { + newDim = target._getTransformedDimensions(); + newValue = (_dim[otherBy] / newDim[otherBy]) * target['scale' + _otherBy]; + target.set('scale' + _otherBy, newValue); + } + return skewed; + }, + + /** + * Scales object by invoking its scaleX/scaleY methods + * @private + * @param {Number} x pointer's x coordinate + * @param {Number} y pointer's y coordinate + * @param {String} by Either 'x' or 'y' - specifies dimension constraint by which to scale an object. + * When not provided, an object is scaled by both dimensions equally + * @return {Boolean} true if the scaling occurred + */ + _scaleObject: function (x, y, by) { + var t = this._currentTransform, + target = t.target, + lockScalingX = target.get('lockScalingX'), + lockScalingY = target.get('lockScalingY'), + lockScalingFlip = target.get('lockScalingFlip'); + + if (lockScalingX && lockScalingY) { + return false; + } + + // Get the constraint point + var constraintPosition = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY), + localMouse = target.toLocalPoint(new fabric.Point(x, y), t.originX, t.originY), + dim = target._getTransformedDimensions(), scaled = false; + + this._setLocalMouse(localMouse, t); + + // Actually scale the object + scaled = this._setObjectScale(localMouse, t, lockScalingX, lockScalingY, by, lockScalingFlip, dim); + + // Make sure the constraints apply + target.setPositionByOrigin(constraintPosition, t.originX, t.originY); + return scaled; + }, + + /** + * @private + * @return {Boolean} true if the scaling occurred + */ + _setObjectScale: function(localMouse, transform, lockScalingX, lockScalingY, by, lockScalingFlip, _dim) { + var target = transform.target, forbidScalingX = false, forbidScalingY = false, scaled = false, + changeX, changeY, scaleX, scaleY; + + scaleX = localMouse.x * target.scaleX / _dim.x; + scaleY = localMouse.y * target.scaleY / _dim.y; + changeX = target.scaleX !== scaleX; + changeY = target.scaleY !== scaleY; + + if (lockScalingFlip && scaleX <= 0 && scaleX < target.scaleX) { + forbidScalingX = true; + } + + if (lockScalingFlip && scaleY <= 0 && scaleY < target.scaleY) { + forbidScalingY = true; + } + + if (by === 'equally' && !lockScalingX && !lockScalingY) { + forbidScalingX || forbidScalingY || (scaled = this._scaleObjectEqually(localMouse, target, transform, _dim)); + } + else if (!by) { + forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX)); + forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY)); + } + else if (by === 'x' && !target.get('lockUniScaling')) { + forbidScalingX || lockScalingX || (target.set('scaleX', scaleX) && (scaled = scaled || changeX)); + } + else if (by === 'y' && !target.get('lockUniScaling')) { + forbidScalingY || lockScalingY || (target.set('scaleY', scaleY) && (scaled = scaled || changeY)); + } + transform.newScaleX = scaleX; + transform.newScaleY = scaleY; + forbidScalingX || forbidScalingY || this._flipObject(transform, by); + return scaled; + }, + + /** + * @private + * @return {Boolean} true if the scaling occurred + */ + _scaleObjectEqually: function(localMouse, target, transform, _dim) { + + var dist = localMouse.y + localMouse.x, + lastDist = _dim.y * transform.original.scaleY / target.scaleY + + _dim.x * transform.original.scaleX / target.scaleX, + scaled, signX = localMouse.x / Math.abs(localMouse.x), + signY = localMouse.y / Math.abs(localMouse.y); + + // We use transform.scaleX/Y instead of target.scaleX/Y + // because the object may have a min scale and we'll loose the proportions + transform.newScaleX = signX * Math.abs(transform.original.scaleX * dist / lastDist); + transform.newScaleY = signY * Math.abs(transform.original.scaleY * dist / lastDist); + scaled = transform.newScaleX !== target.scaleX || transform.newScaleY !== target.scaleY; + target.set('scaleX', transform.newScaleX); + target.set('scaleY', transform.newScaleY); + return scaled; + }, + + /** + * @private + */ + _flipObject: function(transform, by) { + if (transform.newScaleX < 0 && by !== 'y') { + if (transform.originX === 'left') { + transform.originX = 'right'; + } + else if (transform.originX === 'right') { + transform.originX = 'left'; + } + } + + if (transform.newScaleY < 0 && by !== 'x') { + if (transform.originY === 'top') { + transform.originY = 'bottom'; + } + else if (transform.originY === 'bottom') { + transform.originY = 'top'; + } + } + }, + + /** + * @private + */ + _setLocalMouse: function(localMouse, t) { + var target = t.target, zoom = this.getZoom(), + padding = target.padding / zoom; + + if (t.originX === 'right') { + localMouse.x *= -1; + } + else if (t.originX === 'center') { + localMouse.x *= t.mouseXSign * 2; + if (localMouse.x < 0) { + t.mouseXSign = -t.mouseXSign; + } + } + + if (t.originY === 'bottom') { + localMouse.y *= -1; + } + else if (t.originY === 'center') { + localMouse.y *= t.mouseYSign * 2; + if (localMouse.y < 0) { + t.mouseYSign = -t.mouseYSign; + } + } + + // adjust the mouse coordinates when dealing with padding + if (abs(localMouse.x) > padding) { + if (localMouse.x < 0) { + localMouse.x += padding; + } + else { + localMouse.x -= padding; + } + } + else { // mouse is within the padding, set to 0 + localMouse.x = 0; + } + + if (abs(localMouse.y) > padding) { + if (localMouse.y < 0) { + localMouse.y += padding; + } + else { + localMouse.y -= padding; + } + } + else { + localMouse.y = 0; + } + }, + + /** + * Rotates object by invoking its rotate method + * @private + * @param {Number} x pointer's x coordinate + * @param {Number} y pointer's y coordinate + * @return {Boolean} true if the rotation occurred + */ + _rotateObject: function (x, y) { + + var t = this._currentTransform; + + if (t.target.get('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), + hasRoated = 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; + + if (Math.abs(angle - leftAngleLocked) < snapThreshold) { + angle = leftAngleLocked; + } + else if (Math.abs(angle - rightAngleLocked) < snapThreshold) { + angle = rightAngleLocked; + } + } + + // normalize angle to positive value + if (angle < 0) { + angle = 360 + angle; + } + angle %= 360; + + if (t.target.angle === angle) { + hasRoated = false; + } + else { + t.target.angle = angle; + } + + return hasRoated; + }, + + /** + * Set the cursor type of the canvas element + * @param {String} value Cursor type of the canvas element. + * @see http://www.w3.org/TR/css3-ui/#cursor + */ + setCursor: function (value) { + this.upperCanvasEl.style.cursor = value; + }, + + /** + * @param {fabric.Object} target to reset transform + * @private + */ + _resetObjectTransform: function (target) { + target.scaleX = 1; + target.scaleY = 1; + target.skewX = 0; + target.skewY = 0; + target.setAngle(0); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx to draw the selection on + */ + _drawSelection: function (ctx) { + var groupSelector = this._groupSelector, + left = groupSelector.left, + top = groupSelector.top, + aleft = abs(left), + atop = abs(top); + + 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; + + // selection border + 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); + fabric.util.drawDashedLine(ctx, px, py + atop - 1, px + aleft, py + atop - 1, this.selectionDashArray); + fabric.util.drawDashedLine(ctx, px, py, px, py + atop, this.selectionDashArray); + fabric.util.drawDashedLine(ctx, px + aleft - 1, py, px + aleft - 1, py + atop, this.selectionDashArray); + + 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 + ); + } + }, + + /** + * Method that determines what object we are clicking on + * the skipGroup parameter is for internal use, is needed for shift+click action + * @param {Event} e mouse event + * @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through + */ + findTarget: function (e, skipGroup) { + if (this.skipTargetFind) { + return; + } + + var ignoreZoom = true, + pointer = this.getPointer(e, ignoreZoom), + activeGroup = this.getActiveGroup(), + activeObject = this.getActiveObject(), + activeTarget, activeTargetSubs; + // first check current group (if one exists) + // active group does not check sub targets like normal groups. + // if active group just exits. + this.targets = []; + if (activeGroup && !skipGroup && activeGroup === this._searchPossibleTargets([activeGroup], pointer)) { + this._fireOverOutEvents(activeGroup, e); + return activeGroup; + } + // 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 && activeObject === this._searchPossibleTargets([activeObject], pointer)) { + if (!this.preserveObjectStacking) { + this._fireOverOutEvents(activeObject, e); + return activeObject; + } + else { + activeTarget = activeObject; + activeTargetSubs = this.targets; + this.targets = []; + } + } + + var target = this._searchPossibleTargets(this._objects, pointer); + if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) { + target = activeTarget; + this.targets = activeTargetSubs; + } + this._fireOverOutEvents(target, e); + return target; + }, + + /** + * @private + */ + _fireOverOutEvents: function(target, e) { + var overOpt, outOpt, hoveredTarget = this._hoveredTarget; + if (hoveredTarget !== target) { + overOpt = { e: e, target: target, previousTarget: this._hoveredTarget }; + outOpt = { e: e, target: this._hoveredTarget, nextTarget: target }; + this._hoveredTarget = target; + } + if (target) { + if (hoveredTarget !== target) { + if (hoveredTarget) { + this.fire('mouse:out', outOpt); + hoveredTarget.fire('mouseout', outOpt); + } + this.fire('mouse:over', overOpt); + target.fire('mouseover', overOpt); + } + } + else if (hoveredTarget) { + this.fire('mouse:out', outOpt); + hoveredTarget.fire('mouseout', outOpt); + } + }, + + /** + * @private + */ + _checkTarget: function(pointer, obj) { + if (obj && + obj.visible && + obj.evented && + this.containsPoint(null, obj, pointer)){ + if ((this.perPixelTargetFind || obj.perPixelTargetFind) && !obj.isEditing) { + var isTransparent = this.isTargetTransparent(obj, pointer.x, pointer.y); + if (!isTransparent) { + return true; + } + } + else { + return true; + } + } + }, + + /** + * @private + */ + _searchPossibleTargets: function(objects, pointer) { + + // Cache all targets where their bounding box contains point. + var target, i = objects.length, normalizedPointer, subTarget; + // Do not check for currently grouped objects, since we check the parent group itself. + // untill we call this function specifically to search inside the activeGroup + while (i--) { + if (this._checkTarget(pointer, objects[i])) { + target = objects[i]; + if (target.type === 'group' && target.subTargetCheck) { + normalizedPointer = this._normalizePointer(target, pointer); + subTarget = this._searchPossibleTargets(target._objects, normalizedPointer); + subTarget && this.targets.push(subTarget); + } + break; + } + } + return target; + }, + + /** + * Returns pointer coordinates without the effect of the viewport + * @param {Object} pointer with "x" and "y" number values + * @return {Object} object with "x" and "y" number values + */ + restorePointerVpt: function(pointer) { + return fabric.util.transformPoint( + pointer, + fabric.util.invertTransform(this.viewportTransform) + ); + }, + + /** + * Returns pointer coordinates relative to canvas. + * Can return coordinates with or without viewportTransform. + * ignoreZoom false gives back coordinates that represent + * the point clicked on canvas element. + * ignoreZoom true gives back coordinates after being processed + * by the viewportTransform ( sort of coordinates of what is displayed + * on the canvas where you are clicking. + * To interact with your shapes top and left you want to use ignoreZoom true + * most of the time, while ignoreZoom false will give you coordinates + * compatible with the object.oCoords system. + * of the time. + * @param {Event} e + * @param {Boolean} ignoreZoom + * @return {Object} object with "x" and "y" number values + */ + getPointer: function (e, ignoreZoom, upperCanvasEl) { + if (!upperCanvasEl) { + upperCanvasEl = this.upperCanvasEl; + } + var pointer = getPointer(e), + bounds = upperCanvasEl.getBoundingClientRect(), + boundsWidth = bounds.width || 0, + boundsHeight = bounds.height || 0, + cssScale; + + if (!boundsWidth || !boundsHeight ) { + if ('top' in bounds && 'bottom' in bounds) { + boundsHeight = Math.abs( bounds.top - bounds.bottom ); + } + if ('right' in bounds && 'left' in bounds) { + boundsWidth = Math.abs( bounds.right - bounds.left ); + } + } + + this.calcOffset(); + + pointer.x = pointer.x - this._offset.left; + pointer.y = pointer.y - this._offset.top; + if (!ignoreZoom) { + pointer = this.restorePointerVpt(pointer); + } + + if (boundsWidth === 0 || boundsHeight === 0) { + // If bounds are not available (i.e. not visible), do not apply scale. + cssScale = { width: 1, height: 1 }; + } + else { + cssScale = { + width: upperCanvasEl.width / boundsWidth, + height: upperCanvasEl.height / boundsHeight + }; + } + + return { + x: pointer.x * cssScale.width, + y: pointer.y * cssScale.height + }; + }, + + /** + * @private + * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized + */ + _createUpperCanvas: function () { + var lowerCanvasClass = this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/, ''); + + if (this.upperCanvasEl) { + this.upperCanvasEl.className = ''; + } + else { + this.upperCanvasEl = this._createCanvasElement(); + } + fabric.util.addClass(this.upperCanvasEl, 'upper-canvas ' + lowerCanvasClass); + + this.wrapperEl.appendChild(this.upperCanvasEl); + + this._copyCanvasStyle(this.lowerCanvasEl, this.upperCanvasEl); + this._applyCanvasStyle(this.upperCanvasEl); + this.contextTop = this.upperCanvasEl.getContext('2d'); + }, + + /** + * @private + */ + _createCacheCanvas: function () { + this.cacheCanvasEl = this._createCanvasElement(); + this.cacheCanvasEl.setAttribute('width', this.width); + this.cacheCanvasEl.setAttribute('height', this.height); + this.contextCache = this.cacheCanvasEl.getContext('2d'); + }, + + /** + * @private + */ + _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); + }, + + /** + * @private + * @param {HTMLElement} element canvas element to apply styles on + */ + _applyCanvasStyle: function (element) { + var width = this.getWidth() || element.width, + height = this.getHeight() || element.height; + + fabric.util.setStyle(element, { + position: 'absolute', + width: width + 'px', + height: height + 'px', + left: 0, + top: 0, + 'touch-action': 'none' + }); + element.width = width; + element.height = height; + fabric.util.makeElementUnselectable(element); + }, + + /** + * Copys the the entire inline style from one element (fromEl) to another (toEl) + * @private + * @param {Element} fromEl Element style is copied from + * @param {Element} toEl Element copied style is applied to + */ + _copyCanvasStyle: function (fromEl, toEl) { + toEl.style.cssText = fromEl.style.cssText; + }, + + /** + * Returns context of canvas where object selection is drawn + * @return {CanvasRenderingContext2D} + */ + getSelectionContext: function() { + return this.contextTop; + }, + + /** + * Returns <canvas> element on which object selection is drawn + * @return {HTMLCanvasElement} + */ + getSelectionElement: function () { + return this.upperCanvasEl; + }, + + /** + * @private + * @param {Object} object + */ + _setActiveObject: function(object) { + var obj = this._activeObject; + if (obj) { + obj.set('active', false); + if (object !== obj && obj.onDeselect && typeof obj.onDeselect === 'function') { + obj.onDeselect(); + } + } + this._activeObject = object; + object.set('active', true); + }, + + /** + * Sets given object as the only active object on canvas + * @param {fabric.Object} object Object to set as an active one + * @param {Event} [e] Event (passed along when firing "object:selected") + * @return {fabric.Canvas} thisArg + * @chainable + */ + setActiveObject: function (object, e) { + var currentActiveObject = this.getActiveObject(); + if (currentActiveObject && currentActiveObject !== object) { + currentActiveObject.fire('deselected', { e: e }); + } + this._setActiveObject(object); + this.fire('object:selected', { target: object, e: e }); + object.fire('selected', { e: e }); + this.renderAll(); + return this; + }, + + /** + * Returns currently active object + * @return {fabric.Object} active object + */ + getActiveObject: function () { + return this._activeObject; + }, + + /** + * @private + * @param {fabric.Object} obj Object that was removed + */ + _onObjectRemoved: function(obj) { + // removing active object should fire "selection:cleared" events + if (this.getActiveObject() === obj) { + this.fire('before:selection:cleared', { target: obj }); + this._discardActiveObject(); + this.fire('selection:cleared', { target: obj }); + obj.fire('deselected'); + } + if (this._hoveredTarget === obj) { + this._hoveredTarget = null; + } + this.callSuper('_onObjectRemoved', obj); + }, + + /** + * @private + */ + _discardActiveObject: function() { + var obj = this._activeObject; + if (obj) { + obj.set('active', false); + if (obj.onDeselect && typeof obj.onDeselect === 'function') { + obj.onDeselect(); + } + } + this._activeObject = null; + }, + + /** + * Discards currently active object and fire events. If the function is called by fabric + * as a consequence of a mouse event, the event is passed as a parmater and + * sent to the fire function for the custom events. When used as a method the + * e param does not have any application. + * @param {event} e + * @return {fabric.Canvas} thisArg + * @chainable + */ + discardActiveObject: function (e) { + var activeObject = this._activeObject; + if (activeObject) { + this.fire('before:selection:cleared', { target: activeObject, e: e }); + this._discardActiveObject(); + this.fire('selection:cleared', { e: e }); + activeObject.fire('deselected', { e: e }); + } + return this; + }, + + /** + * @private + * @param {fabric.Group} group + */ + _setActiveGroup: function(group) { + this._activeGroup = group; + if (group) { + group.set('active', true); + } + }, + + /** + * Sets active group to a specified one. If the function is called by fabric + * as a consequence of a mouse event, the event is passed as a parmater and + * sent to the fire function for the custom events. When used as a method the + * e param does not have any application. + * @param {fabric.Group} group Group to set as a current one + * @param {Event} e Event object + * @return {fabric.Canvas} thisArg + * @chainable + */ + setActiveGroup: function (group, e) { + this._setActiveGroup(group); + if (group) { + this.fire('object:selected', { target: group, e: e }); + group.fire('selected', { e: e }); + } + return this; + }, + + /** + * Returns currently active group + * @return {fabric.Group} Current group + */ + getActiveGroup: function () { + return this._activeGroup; + }, + + /** + * @private + */ + _discardActiveGroup: function() { + var g = this.getActiveGroup(); + if (g) { + g.destroy(); + } + this.setActiveGroup(null); + }, + + /** + * Discards currently active group and fire events If the function is called by fabric + * as a consequence of a mouse event, the event is passed as a parmater and + * sent to the fire function for the custom events. When used as a method the + * e param does not have any application. + * @return {fabric.Canvas} thisArg + * @chainable + */ + discardActiveGroup: function (e) { + var g = this.getActiveGroup(); + if (g) { + this.fire('before:selection:cleared', { e: e, target: g }); + this._discardActiveGroup(); + this.fire('selection:cleared', { e: e }); + } + return this; + }, + + /** + * Deactivates all objects on canvas, removing any active group or object + * @return {fabric.Canvas} thisArg + * @chainable + */ + deactivateAll: function () { + var allObjects = this.getObjects(), + i = 0, + len = allObjects.length, + obj; + for ( ; i < len; i++) { + obj = allObjects[i]; + obj && obj.set('active', false); + } + this._discardActiveGroup(); + this._discardActiveObject(); + return this; + }, + + /** + * Deactivates all objects and dispatches appropriate events If the function is called by fabric + * as a consequence of a mouse event, the event is passed as a parmater and + * sent to the fire function for the custom events. When used as a method the + * e param does not have any application. + * @return {fabric.Canvas} thisArg + * @chainable + */ + deactivateAllWithDispatch: function (e) { + var allObjects = this.getObjects(), + i = 0, + len = allObjects.length, + obj; + for ( ; i < len; i++) { + obj = allObjects[i]; + obj && obj.set('active', false); + } + this.discardActiveGroup(e); + this.discardActiveObject(e); + return this; + }, + + /** + * Clears a canvas element and removes all event listeners + * @return {fabric.Canvas} thisArg + * @chainable + */ + dispose: function () { + fabric.StaticCanvas.prototype.dispose.call(this); + var wrapper = this.wrapperEl; + this.removeListeners(); + wrapper.removeChild(this.upperCanvasEl); + wrapper.removeChild(this.lowerCanvasEl); + delete this.upperCanvasEl; + if (wrapper.parentNode) { + wrapper.parentNode.replaceChild(this.lowerCanvasEl, this.wrapperEl); + } + delete this.wrapperEl; + return this; + }, + + /** + * Clears all contexts (background, main, top) of an instance + * @return {fabric.Canvas} thisArg + * @chainable + */ + clear: function () { + this.discardActiveGroup(); + this.discardActiveObject(); + this.clearContext(this.contextTop); + return this.callSuper('clear'); + }, + + /** + * Draws objects' controls (borders/controls) + * @param {CanvasRenderingContext2D} ctx Context to render controls on + */ + drawControls: function(ctx) { + var activeGroup = this.getActiveGroup(); + + if (activeGroup) { + activeGroup._renderControls(ctx); + } + else { + this._drawObjectsControls(ctx); + } + }, + + /** + * @private + */ + _drawObjectsControls: function(ctx) { + for (var i = 0, len = this._objects.length; i < len; ++i) { + if (!this._objects[i] || !this._objects[i].active) { + continue; + } + this._objects[i]._renderControls(ctx); + } + }, + + /** + * @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) { + if (instance.group && instance.group === this.getActiveGroup()) { + //Copy all the positionally relevant properties across now + var originalValues = {}, + layoutProps = ['angle', 'flipX', 'flipY', 'left', 'scaleX', 'scaleY', 'skewX', 'skewY', 'top']; + 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, + // where "prototype" property is enumerable and overrides existing prototype + for (var prop in fabric.StaticCanvas) { + if (prop !== 'prototype') { + fabric.Canvas[prop] = fabric.StaticCanvas[prop]; + } + } + + if (fabric.isTouchSupported) { + /** @ignore */ + fabric.Canvas.prototype._setCursorFromEvent = function() { }; + } + + /** + * @ignore + * @class fabric.Element + * @alias fabric.Canvas + * @deprecated Use {@link fabric.Canvas} instead. + * @constructor + */ + fabric.Element = fabric.Canvas; +})(); + + +(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, + RIGHT_CLICK = 3, MIDDLE_CLICK = 2, LEFT_CLICK = 1; + + function checkClick(e, value) { + return 'which' in e ? e.which === value : e.button === value - 1; + } + + fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ { + + /** + * Map of cursor style values for each of the object controls + * @private + */ + cursorMap: [ + 'n-resize', + 'ne-resize', + 'e-resize', + 'se-resize', + 's-resize', + 'sw-resize', + 'w-resize', + 'nw-resize' + ], + + /** + * Adds mouse listeners to canvas + * @private + */ + _initEventListeners: function () { + // in case we initialized the class twice. This should not happen normally + // but in some kind of applications where the canvas element may be changed + // this is a workaround to having double listeners. + this.removeListeners(); + this._bindEvents(); + + addListener(fabric.window, 'resize', this._onResize); + + // mouse events + addListener(this.upperCanvasEl, 'mousedown', this._onMouseDown); + addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove); + addListener(this.upperCanvasEl, 'mouseout', this._onMouseOut); + addListener(this.upperCanvasEl, 'mouseenter', this._onMouseEnter); + addListener(this.upperCanvasEl, 'wheel', this._onMouseWheel); + addListener(this.upperCanvasEl, 'contextmenu', this._onContextMenu); + + // touch events + addListener(this.upperCanvasEl, 'touchstart', this._onMouseDown, { passive: false }); + addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove, { passive: false }); + + if (typeof eventjs !== 'undefined' && 'add' in eventjs) { + eventjs.add(this.upperCanvasEl, 'gesture', this._onGesture); + eventjs.add(this.upperCanvasEl, 'drag', this._onDrag); + eventjs.add(this.upperCanvasEl, 'orientation', this._onOrientationChange); + eventjs.add(this.upperCanvasEl, 'shake', this._onShake); + eventjs.add(this.upperCanvasEl, 'longpress', this._onLongPress); + } + }, + + /** + * @private + */ + _bindEvents: function() { + if (this.eventsBinded) { + // for any reason we pass here twice we do not want to bind events twice. + return; + } + this._onMouseDown = this._onMouseDown.bind(this); + this._onMouseMove = this._onMouseMove.bind(this); + this._onMouseUp = this._onMouseUp.bind(this); + this._onResize = this._onResize.bind(this); + this._onGesture = this._onGesture.bind(this); + this._onDrag = this._onDrag.bind(this); + this._onShake = this._onShake.bind(this); + this._onLongPress = this._onLongPress.bind(this); + this._onOrientationChange = this._onOrientationChange.bind(this); + this._onMouseWheel = this._onMouseWheel.bind(this); + this._onMouseOut = this._onMouseOut.bind(this); + this._onMouseEnter = this._onMouseEnter.bind(this); + this._onContextMenu = this._onContextMenu.bind(this); + this.eventsBinded = true; + }, + + /** + * Removes all event listeners + */ + removeListeners: function() { + removeListener(fabric.window, 'resize', this._onResize); + + removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown); + removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove); + removeListener(this.upperCanvasEl, 'mouseout', this._onMouseOut); + removeListener(this.upperCanvasEl, 'mouseenter', this._onMouseEnter); + 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) { + eventjs.remove(this.upperCanvasEl, 'gesture', this._onGesture); + eventjs.remove(this.upperCanvasEl, 'drag', this._onDrag); + eventjs.remove(this.upperCanvasEl, 'orientation', this._onOrientationChange); + eventjs.remove(this.upperCanvasEl, 'shake', this._onShake); + eventjs.remove(this.upperCanvasEl, 'longpress', this._onLongPress); + } + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js gesture + * @param {Event} [self] Inner Event object + */ + _onGesture: function(e, self) { + this.__onTransformGesture && this.__onTransformGesture(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js drag + * @param {Event} [self] Inner Event object + */ + _onDrag: function(e, self) { + this.__onDrag && this.__onDrag(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on wheel event + */ + _onMouseWheel: function(e) { + this.__onMouseWheel(e); + }, + + /** + * @private + * @param {Event} e Event object fired on mousedown + */ + _onMouseOut: function(e) { + var target = this._hoveredTarget; + this.fire('mouse:out', { target: target, e: e }); + this._hoveredTarget = null; + target && target.fire('mouseout', { e: e }); + if (this._iTextInstances) { + this._iTextInstances.forEach(function(obj) { + if (obj.isEditing) { + obj.hiddenTextarea.focus(); + } + }); + } + }, + + /** + * @private + * @param {Event} e Event object fired on mouseenter + */ + _onMouseEnter: function(e) { + if (!this.findTarget(e)) { + this.fire('mouse:over', { target: null, e: e }); + this._hoveredTarget = null; + } + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js orientation change + * @param {Event} [self] Inner Event object + */ + _onOrientationChange: function(e, self) { + this.__onOrientationChange && this.__onOrientationChange(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js shake + * @param {Event} [self] Inner Event object + */ + _onShake: function(e, self) { + this.__onShake && this.__onShake(e, self); + }, + + /** + * @private + * @param {Event} [e] Event object fired on Event.js shake + * @param {Event} [self] Inner Event object + */ + _onLongPress: function(e, self) { + 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 + */ + _onMouseDown: function (e) { + this.__onMouseDown(e); + + addListener(fabric.document, 'touchend', this._onMouseUp, { passive: false }); + addListener(fabric.document, 'touchmove', this._onMouseMove, { passive: false }); + + removeListener(this.upperCanvasEl, 'mousemove', this._onMouseMove); + removeListener(this.upperCanvasEl, 'touchmove', this._onMouseMove); + + if (e.type === 'touchstart') { + // Unbind mousedown to prevent double triggers from touch devices + removeListener(this.upperCanvasEl, 'mousedown', this._onMouseDown); + } + else { + addListener(fabric.document, 'mouseup', this._onMouseUp); + addListener(fabric.document, 'mousemove', this._onMouseMove); + } + }, + + /** + * @private + * @param {Event} e Event object fired on mouseup + */ + _onMouseUp: function (e) { + this.__onMouseUp(e); + + removeListener(fabric.document, 'mouseup', this._onMouseUp); + removeListener(fabric.document, 'touchend', this._onMouseUp); + + removeListener(fabric.document, 'mousemove', this._onMouseMove); + removeListener(fabric.document, 'touchmove', this._onMouseMove); + + addListener(this.upperCanvasEl, 'mousemove', this._onMouseMove); + addListener(this.upperCanvasEl, 'touchmove', this._onMouseMove, { passive: false }); + + if (e.type === 'touchend') { + // Wait 400ms before rebinding mousedown to prevent double triggers + // from touch devices + var _this = this; + setTimeout(function() { + addListener(_this.upperCanvasEl, 'mousedown', _this._onMouseDown); + }, 400); + } + }, + + /** + * @private + * @param {Event} e Event object fired on mousemove + */ + _onMouseMove: function (e) { + !this.allowTouchScrolling && e.preventDefault && e.preventDefault(); + this.__onMouseMove(e); + }, + + /** + * @private + */ + _onResize: function () { + this.calcOffset(); + }, + + /** + * Decides whether the canvas should be redrawn in mouseup and mousedown events. + * @private + * @param {Object} target + * @param {Object} pointer + */ + _shouldRender: function(target, pointer) { + var activeObject = this.getActiveGroup() || this.getActiveObject(); + + if (activeObject && activeObject.isEditing && target === activeObject) { + // if we mouse up/down over a editing textbox a cursor change, + // there is no need to re render + return false; + } + return !!( + (target && ( + target.isMoving || + target !== activeObject)) + || + (!target && !!activeObject) + || + (!target && !activeObject && !this._groupSelector) + || + (pointer && + this._previousPointer && + this.selection && ( + pointer.x !== this._previousPointer.x || + pointer.y !== this._previousPointer.y)) + ); + }, + + /** + * Method that defines the actions when mouse is released on canvas. + * The method resets the currentTransform parameters, store the image corner + * position in the image object and render the canvas on top. + * @private + * @param {Event} e Event object fired on mouseup + */ + __onMouseUp: function (e) { + + var target; + // if right/middle click just fire events and return + // target undefined will make the _handleEvent search the target + if (checkClick(e, RIGHT_CLICK)) { + if (this.fireRightClick) { + this._handleEvent(e, 'up', target, RIGHT_CLICK); + } + return; + } + + if (checkClick(e, MIDDLE_CLICK)) { + if (this.fireMiddleClick) { + this._handleEvent(e, 'up', target, MIDDLE_CLICK); + } + return; + } + + if (this.isDrawingMode && this._isCurrentlyDrawing) { + this._onMouseUpInDrawingMode(e); + return; + } + + var searchTarget = true, transform = this._currentTransform, + groupSelector = this._groupSelector, + isClick = (!groupSelector || (groupSelector.left === 0 && groupSelector.top === 0)); + + if (transform) { + this._finalizeCurrentTransform(e); + searchTarget = !transform.actionPerformed; + } + + target = searchTarget ? this.findTarget(e, true) : transform.target; + + var shouldRender = this._shouldRender(target, this.getPointer(e)); + + if (target || !isClick) { + this._maybeGroupObjects(e); + } + else { + // those are done by default on mouse up + // by _maybeGroupObjects, we are skipping it in case of no target find + this._groupSelector = null; + this._currentTransform = null; + } + + if (target) { + target.isMoving = false; + } + this._setCursorFromEvent(e, target); + this._handleEvent(e, 'up', target ? target : null, LEFT_CLICK, isClick); + target && (target.__corner = 0); + shouldRender && this.renderAll(); + }, + + /** + * @private + * Handle event firing for target and subtargets + * @param {Event} e event from mouse + * @param {String} eventType event to fire (up, down or move) + * @param {fabric.Object} targetObj receiving event + * @param {Number} [button] button used in the event 1 = left, 2 = middle, 3 = right + * @param {Boolean} isClick for left button only, indicates that the mouse up happened without move. + */ + _handleEvent: function(e, eventType, targetObj, button, isClick) { + var target = typeof targetObj === 'undefined' ? this.findTarget(e) : targetObj, + targets = this.targets || [], + options = { + e: e, + target: target, + subTargets: targets, + button: button || LEFT_CLICK, + isClick: isClick || false + }; + this.fire('mouse:' + eventType, options); + target && target.fire('mouse' + eventType, options); + for (var i = 0; i < targets.length; i++) { + targets[i].fire('mouse' + eventType, options); + } + }, + + /** + * @private + * @param {Event} e send the mouse event that generate the finalize down, so it can be used in the event + */ + _finalizeCurrentTransform: function(e) { + + var transform = this._currentTransform, + target = transform.target; + + if (target._scaling) { + target._scaling = false; + } + + target.setCoords(); + this._restoreOriginXY(target); + + if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) { + this.fire('object:modified', { target: target, e: e }); + target.fire('modified', { e: e }); + } + }, + + /** + * @private + * @param {Object} target Object to restore + */ + _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; + } + }, + + /** + * @private + * @param {Event} e Event object fired on mousedown + */ + _onMouseDownInDrawingMode: function(e) { + this._isCurrentlyDrawing = true; + this.discardActiveObject(e).renderAll(); + if (this.clipTo) { + fabric.util.clipContext(this, this.contextTop); + } + var pointer = this.getPointer(e); + this.freeDrawingBrush.onMouseDown(pointer); + this._handleEvent(e, 'down'); + }, + + /** + * @private + * @param {Event} e Event object fired on mousemove + */ + _onMouseMoveInDrawingMode: function(e) { + if (this._isCurrentlyDrawing) { + var pointer = this.getPointer(e); + this.freeDrawingBrush.onMouseMove(pointer); + } + this.setCursor(this.freeDrawingCursor); + this._handleEvent(e, 'move'); + }, + + /** + * @private + * @param {Event} e Event object fired on mouseup + */ + _onMouseUpInDrawingMode: function(e) { + this._isCurrentlyDrawing = false; + if (this.clipTo) { + this.contextTop.restore(); + } + this.freeDrawingBrush.onMouseUp(); + this._handleEvent(e, 'up'); + }, + + /** + * Method that defines the actions when mouse is clicked on canvas. + * The method inits the currentTransform parameters and renders all the + * canvas so the current image can be placed on the top canvas and the rest + * in on the container one. + * @private + * @param {Event} e Event object fired on mousedown + */ + __onMouseDown: function (e) { + + var target = this.findTarget(e); + + // if right click just fire events + if (checkClick(e, RIGHT_CLICK)) { + if (this.fireRightClick) { + this._handleEvent(e, 'down', target ? target : null, RIGHT_CLICK); + } + return; + } + + if (checkClick(e, MIDDLE_CLICK)) { + if (this.fireMiddleClick) { + this._handleEvent(e, 'down', target ? target : null, MIDDLE_CLICK); + } + return; + } + + if (this.isDrawingMode) { + this._onMouseDownInDrawingMode(e); + return; + } + + // ignore if some object is being transformed at this moment + if (this._currentTransform) { + return; + } + + // save pointer for check in __onMouseUp event + var pointer = this.getPointer(e, true); + this._previousPointer = pointer; + + var shouldRender = this._shouldRender(target, pointer), + shouldGroup = this._shouldGroup(e, target); + + if (this._shouldClearSelection(e, target)) { + this.deactivateAllWithDispatch(e); + } + else if (shouldGroup) { + this._handleGrouping(e, target); + target = this.getActiveGroup(); + } + + if (this.selection && (!target || (!target.selectable && !target.isEditing))) { + this._groupSelector = { + ex: pointer.x, + ey: pointer.y, + top: 0, + left: 0 + }; + } + + if (target) { + if (target.selectable && (target.__corner || !shouldGroup)) { + this._beforeTransform(e, target); + this._setupCurrentTransform(e, target); + } + var activeObject = this.getActiveObject(); + if (target !== this.getActiveGroup() && target !== activeObject) { + this.deactivateAll(); + if (target.selectable) { + activeObject && activeObject.fire('deselected', { e: e }); + this.setActiveObject(target, e); + } + } + } + this._handleEvent(e, 'down', target ? target : null); + // we must renderAll so that we update the visuals + shouldRender && this.renderAll(); + }, + + /** + * @private + */ + _beforeTransform: function(e, target) { + this.stateful && target.saveState(); + + // determine if it's a drag or rotate case + if (target._findTargetCorner(this.getPointer(e))) { + this.onBeforeScaleRotate(target); + } + + }, + + /** + * @private + * @param {Object} target Object for that origin is set to center + */ + _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; + }, + + /** + * @private + * @param {Object} target Object for that center is set to origin + */ + _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; + }, + + /** + * Method that defines the actions when mouse is hovering the canvas. + * The currentTransform parameter will definde whether the user is rotating/scaling/translating + * an image or neither of them (only hovering). A group selection is also possible and would cancel + * all any other type of action. + * In case of an image transformation only the top canvas will be rendered. + * @private + * @param {Event} e Event object fired on mousemove + */ + __onMouseMove: function (e) { + + var target, pointer; + + if (this.isDrawingMode) { + this._onMouseMoveInDrawingMode(e); + return; + } + if (typeof e.touches !== 'undefined' && e.touches.length > 1) { + return; + } + + var groupSelector = this._groupSelector; + + // We initially clicked in an empty area, so we draw a box for multiple selection + if (groupSelector) { + pointer = this.getPointer(e, true); + + groupSelector.left = pointer.x - groupSelector.ex; + groupSelector.top = pointer.y - groupSelector.ey; + + this.renderTop(); + } + else if (!this._currentTransform) { + target = this.findTarget(e); + this._setCursorFromEvent(e, target); + } + else { + this._transformObject(e); + } + this._handleEvent(e, 'move', target ? target : null); + }, + + /** + * Method that defines actions when an Event Mouse Wheel + * @param {Event} e Event object fired on mouseup + */ + __onMouseWheel: function(e) { + this._handleEvent(e, 'wheel'); + }, + + /** + * @private + * @param {Event} e Event fired on mousemove + */ + _transformObject: function(e) { + var pointer = this.getPointer(e), + transform = this._currentTransform; + + transform.reset = false; + transform.target.isMoving = true; + transform.shiftKey = e.shiftKey; + transform.altKey = e[this.centeredKey]; + + this._beforeScaleTransform(e, transform); + this._performTransformAction(e, transform, pointer); + + transform.actionPerformed && this.renderAll(); + }, + + /** + * @private + */ + _performTransformAction: function(e, transform, pointer) { + var x = pointer.x, + y = pointer.y, + target = transform.target, + action = transform.action, + actionPerformed = false; + + if (action === 'rotate') { + (actionPerformed = this._rotateObject(x, y)) && this._fire('rotating', target, e); + } + else if (action === 'scale') { + (actionPerformed = this._onScale(e, transform, x, y)) && this._fire('scaling', target, e); + } + else if (action === 'scaleX') { + (actionPerformed = this._scaleObject(x, y, 'x')) && this._fire('scaling', target, e); + } + else if (action === 'scaleY') { + (actionPerformed = this._scaleObject(x, y, 'y')) && this._fire('scaling', target, e); + } + else if (action === 'skewX') { + (actionPerformed = this._skewObject(x, y, 'x')) && this._fire('skewing', target, e); + } + else if (action === 'skewY') { + (actionPerformed = this._skewObject(x, y, 'y')) && this._fire('skewing', target, e); + } + else { + actionPerformed = this._translateObject(x, y); + if (actionPerformed) { + this._fire('moving', target, e); + this.setCursor(target.moveCursor || this.moveCursor); + } + } + transform.actionPerformed = transform.actionPerformed || actionPerformed; + }, + + /** + * @private + */ + _fire: function(eventName, target, e) { + this.fire('object:' + eventName, { target: target, e: e }); + target.fire(eventName, { e: e }); + }, + + /** + * @private + */ + _beforeScaleTransform: function(e, transform) { + if (transform.action === 'scale' || transform.action === 'scaleX' || transform.action === 'scaleY') { + var centerTransform = this._shouldCenterTransform(transform.target); + + // Switch from a normal resize to center-based + if ((centerTransform && (transform.originX !== 'center' || transform.originY !== 'center')) || + // Switch from center-based resize to normal one + (!centerTransform && transform.originX === 'center' && transform.originY === 'center') + ) { + this._resetCurrentTransform(); + transform.reset = true; + } + } + }, + + /** + * @private + * @param {Event} e Event object + * @param {Object} transform current tranform + * @param {Number} x mouse position x from origin + * @param {Number} y mouse poistion y from origin + * @return {Boolean} true if the scaling occurred + */ + _onScale: function(e, transform, x, y) { + if ((e[this.uniScaleKey] || this.uniScaleTransform) && !transform.target.get('lockUniScaling')) { + transform.currentAction = 'scale'; + return this._scaleObject(x, y); + } + else { + // Switch from a normal resize to proportional + if (!transform.reset && transform.currentAction === 'scale') { + this._resetCurrentTransform(); + } + + transform.currentAction = 'scaleEqually'; + return this._scaleObject(x, y, 'equally'); + } + }, + + /** + * Sets the cursor depending on where the canvas is being hovered. + * Note: very buggy in Opera + * @param {Event} e Event object + * @param {Object} target Object that the mouse is hovering, if so. + */ + _setCursorFromEvent: function (e, target) { + if (!target) { + this.setCursor(this.defaultCursor); + return false; + } + + var hoverCursor = target.hoverCursor || this.hoverCursor, + activeGroup = this.getActiveGroup(), + // only show proper corner when group selection is not active + corner = target._findTargetCorner + && (!activeGroup || !activeGroup.contains(target)) + && target._findTargetCorner(this.getPointer(e, true)); + + if (!corner) { + this.setCursor(hoverCursor); + } + else { + this._setCornerCursor(corner, target, e); + } + //actually unclear why it should return something + //is never evaluated + return true; + }, + + /** + * @private + */ + _setCornerCursor: function(corner, target, e) { + if (corner in cursorOffset) { + this.setCursor(this._getRotatedCornerCursor(corner, target, e)); + } + else if (corner === 'mtr' && target.hasRotatingPoint) { + this.setCursor(this.rotationCursor); + } + else { + this.setCursor(this.defaultCursor); + return false; + } + }, + + /** + * @private + */ + _getRotatedCornerCursor: function(corner, target, e) { + var n = Math.round((target.getAngle() % 360) / 45); + + if (n < 0) { + n += 8; // full circle ahead + } + n += cursorOffset[corner]; + if (e[this.altActionKey] && cursorOffset[corner] % 2 === 0) { + //if we are holding shift and we are on a mx corner... + n += 2; + } + // normalize n to be from 0 to 7 + n %= 8; + + return this.cursorMap[n]; + } + }); +})(); + + +(function() { + + var min = Math.min, + max = Math.max; + + fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ { + + /** + * @private + * @param {Event} e Event object + * @param {fabric.Object} target + * @return {Boolean} + */ + _shouldGroup: function(e, target) { + var activeObject = this.getActiveObject(); + return e[this.selectionKey] && target && target.selectable && + (this.getActiveGroup() || (activeObject && activeObject !== target)) + && this.selection; + }, + + /** + * @private + * @param {Event} e Event object + * @param {fabric.Object} target + */ + _handleGrouping: function (e, target) { + var activeGroup = this.getActiveGroup(); + + if (target === activeGroup) { + // if it's a group, find target again, using activeGroup objects + target = this.findTarget(e, true); + // if even object is not found, bail out + if (!target) { + return; + } + } + if (activeGroup) { + this._updateActiveGroup(target, e); + } + else { + this._createActiveGroup(target, e); + } + + if (this._activeGroup) { + this._activeGroup.saveCoords(); + } + }, + + /** + * @private + */ + _updateActiveGroup: function(target, e) { + var activeGroup = this.getActiveGroup(); + + if (activeGroup.contains(target)) { + + activeGroup.removeWithUpdate(target); + target.set('active', false); + + if (activeGroup.size() === 1) { + // remove group alltogether if after removal it only contains 1 object + this.discardActiveGroup(e); + // activate last remaining object + this.setActiveObject(activeGroup.item(0), e); + return; + } + } + else { + activeGroup.addWithUpdate(target); + } + this.fire('selection:created', { target: activeGroup, e: e }); + activeGroup.set('active', true); + }, + + /** + * @private + */ + _createActiveGroup: function(target, e) { + + if (this._activeObject && target !== this._activeObject) { + + var group = this._createGroup(target); + group.addWithUpdate(); + + this.setActiveGroup(group, e); + this._activeObject = null; + + this.fire('selection:created', { target: group, e: e }); + } + + target.set('active', true); + }, + + /** + * @private + * @param {Object} target + */ + _createGroup: function(target) { + + var objects = this.getObjects(), + isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target), + groupObjects = isActiveLower + ? [this._activeObject, target] + : [target, this._activeObject]; + this._activeObject.isEditing && this._activeObject.exitEditing(); + return new fabric.Group(groupObjects, { + canvas: this + }); + }, + + /** + * @private + * @param {Event} e mouse event + */ + _groupSelectedObjects: function (e) { + + var group = this._collectObjects(); + + // do not create group for 1 element only + if (group.length === 1) { + this.setActiveObject(group[0], e); + } + else if (group.length > 1) { + group = new fabric.Group(group.reverse(), { + canvas: this + }); + group.addWithUpdate(); + this.setActiveGroup(group, e); + group.saveCoords(); + this.fire('selection:created', { target: group, e: e }); + this.renderAll(); + } + }, + + /** + * @private + */ + _collectObjects: function() { + var group = [], + currentObject, + x1 = this._groupSelector.ex, + y1 = this._groupSelector.ey, + x2 = x1 + this._groupSelector.left, + y2 = y1 + this._groupSelector.top, + selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)), + selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)), + isClick = x1 === x2 && y1 === y2; + + for (var i = this._objects.length; i--; ) { + currentObject = this._objects[i]; + + if (!currentObject || !currentObject.selectable || !currentObject.visible) { + continue; + } + + if (currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2) || + currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2) || + currentObject.containsPoint(selectionX1Y1) || + currentObject.containsPoint(selectionX2Y2) + ) { + currentObject.set('active', true); + group.push(currentObject); + + // only add one object if it's a click + if (isClick) { + break; + } + } + } + + return group; + }, + + /** + * @private + */ + _maybeGroupObjects: function(e) { + if (this.selection && this._groupSelector) { + this._groupSelectedObjects(e); + } + + var activeGroup = this.getActiveGroup(); + if (activeGroup) { + activeGroup.setObjectsCoords().setCoords(); + activeGroup.isMoving = false; + this.setCursor(this.defaultCursor); + } + + // clear selection and current transformation + this._groupSelector = null; + this._currentTransform = null; + } + }); + +})(); + + +(function () { + + var supportQuality = fabric.StaticCanvas.supports('toDataURLWithQuality'); + + fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { + + /** + * 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 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); + }, + + /** + * @private + */ + __toDataURLWithMultiplier: function(format, quality, cropping, multiplier) { + + var origWidth = this.getWidth(), + origHeight = this.getHeight(), + scaledWidth = (cropping.width || this.getWidth()) * multiplier, + scaledHeight = (cropping.height || 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; + // 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 }, { backstoreOnly: true }); + } + 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 }, { backstoreOnly: true }); + return data; + }, + + /** + * @private + */ + __toDataURL: function(format, quality) { + + var canvasEl = this.contextContainer.canvas; + // to avoid common confusion https://github.com/kangax/fabric.js/issues/806 + if (format === 'jpg') { + format = 'jpeg'; + } + + var data = supportQuality + ? canvasEl.toDataURL('image/' + format, quality) + : canvasEl.toDataURL('image/' + format); + + 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 + }); + }, + }); + +})(); + + +fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { + + /** + * Populates canvas with data from the specified dataless JSON. + * JSON format must conform to the one of {@link fabric.Canvas#toDatalessJSON} + * @deprecated since 1.2.2 + * @param {String|Object} json JSON string or object + * @param {Function} callback Callback, invoked when json is parsed + * and corresponding objects (e.g: {@link fabric.Image}) + * are initialized + * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created. + * @return {fabric.Canvas} instance + * @chainable + * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization} + */ + loadFromDatalessJSON: function (json, callback, reviver) { + return this.loadFromJSON(json, callback, reviver); + }, + + /** + * Populates canvas with data from the specified JSON. + * JSON format must conform to the one of {@link fabric.Canvas#toJSON} + * @param {String|Object} json JSON string or object + * @param {Function} callback Callback, invoked when json is parsed + * and corresponding objects (e.g: {@link fabric.Image}) + * are initialized + * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created. + * @return {fabric.Canvas} instance + * @chainable + * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization} + * @see {@link http://jsfiddle.net/fabricjs/fmgXt/|jsFiddle demo} + * @example loadFromJSON + * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas)); + * @example loadFromJSON with reviver + * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) { + * // `o` = json object + * // `object` = fabric.Object instance + * // ... do some stuff ... + * }); + */ + loadFromJSON: function (json, callback, reviver) { + if (!json) { + return; + } + + // serialize if it wasn't already + var serialized = (typeof json === 'string') + ? JSON.parse(json) + : fabric.util.object.clone(json); + + var _this = this, + renderOnAddRemove = this.renderOnAddRemove; + this.renderOnAddRemove = false; + + this._enlivenObjects(serialized.objects, function (enlivenedObjects) { + _this.clear(); + _this._setBgOverlay(serialized, function () { + enlivenedObjects.forEach(function(obj, index) { + // we splice the array just in case some custom classes restored from JSON + // will add more object to canvas at canvas init. + _this.insertAt(obj, index); + }); + _this.renderOnAddRemove = renderOnAddRemove; + // remove parts i cannot set as options + delete serialized.objects; + delete serialized.backgroundImage; + delete serialized.overlayImage; + delete serialized.background; + delete serialized.overlay; + // this._initOptions does too many things to just + // call it. Normally loading an Object from JSON + // create the Object instance. Here the Canvas is + // already an instance and we are just loading things over it + _this._setOptions(serialized); + _this.renderAll(); + callback && callback(); + }); + }, reviver); + return this; + }, + + /** + * @private + * @param {Object} serialized Object with background and overlay information + * @param {Function} callback Invoked after all background and overlay images/patterns loaded + */ + _setBgOverlay: function(serialized, callback) { + var loaded = { + backgroundColor: false, + overlayColor: false, + backgroundImage: false, + overlayImage: false + }; + + if (!serialized.backgroundImage && !serialized.overlayImage && !serialized.background && !serialized.overlay) { + callback && callback(); + return; + } + + var cbIfLoaded = function () { + if (loaded.backgroundImage && loaded.overlayImage && loaded.backgroundColor && loaded.overlayColor) { + callback && callback(); + } + }; + + this.__setBgOverlay('backgroundImage', serialized.backgroundImage, loaded, cbIfLoaded); + this.__setBgOverlay('overlayImage', serialized.overlayImage, loaded, cbIfLoaded); + this.__setBgOverlay('backgroundColor', serialized.background, loaded, cbIfLoaded); + this.__setBgOverlay('overlayColor', serialized.overlay, loaded, cbIfLoaded); + }, + + /** + * @private + * @param {String} property Property to set (backgroundImage, overlayImage, backgroundColor, overlayColor) + * @param {(Object|String)} value Value to set + * @param {Object} loaded Set loaded property to true if property is set + * @param {Object} callback Callback function to invoke after property is set + */ + __setBgOverlay: function(property, value, loaded, callback) { + var _this = this; + + if (!value) { + loaded[property] = true; + callback && callback(); + return; + } + + if (property === 'backgroundImage' || property === 'overlayImage') { + fabric.util.enlivenObjects([value], function(enlivedObject){ + _this[property] = enlivedObject[0]; + loaded[property] = true; + callback && callback(); + }); + } + else { + this['set' + fabric.util.string.capitalize(property, true)](value, function() { + loaded[property] = true; + callback && callback(); + }); + } + }, + + /** + * @private + * @param {Array} objects + * @param {Function} callback + * @param {Function} [reviver] + */ + _enlivenObjects: function (objects, callback, reviver) { + if (!objects || objects.length === 0) { + callback && callback([]); + return; + } + + fabric.util.enlivenObjects(objects, function(enlivenedObjects) { + callback && callback(enlivenedObjects); + }, null, reviver); + }, + + /** + * @private + * @param {String} format + * @param {Function} callback + */ + _toDataURL: function (format, callback) { + this.clone(function (clone) { + callback(clone.toDataURL(format)); + }); + }, + + /** + * @private + * @param {String} format + * @param {Number} multiplier + * @param {Function} callback + */ + _toDataURLWithMultiplier: function (format, multiplier, callback) { + this.clone(function (clone) { + callback(clone.toDataURLWithMultiplier(format, multiplier)); + }); + }, + + /** + * Clones canvas instance + * @param {Object} [callback] Receives cloned instance as a first argument + * @param {Array} [properties] Array of properties to include in the cloned canvas and children + */ + clone: function (callback, properties) { + var data = JSON.stringify(this.toJSON(properties)); + this.cloneWithoutData(function(clone) { + clone.loadFromJSON(data, function() { + callback && callback(clone); + }); + }); + }, + + /** + * Clones canvas instance without cloning existing data. + * This essentially copies canvas dimensions, clipping properties, etc. + * but leaves data empty (so that you can populate it with your own) + * @param {Object} [callback] Receives cloned instance as a first argument + */ + cloneWithoutData: function(callback) { + var el = fabric.document.createElement('canvas'); + + el.width = this.getWidth(); + el.height = this.getHeight(); + + var clone = new fabric.Canvas(el); + clone.clipTo = this.clipTo; + if (this.backgroundImage) { + clone.setBackgroundImage(this.backgroundImage.src, function() { + clone.renderAll(); + callback && callback(clone); + }); + clone.backgroundImageOpacity = this.backgroundImageOpacity; + clone.backgroundImageStretch = this.backgroundImageStretch; + } + else { + callback && callback(clone); + } + } +}); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + clone = fabric.util.object.clone, + toFixed = fabric.util.toFixed, + capitalize = fabric.util.string.capitalize, + degreesToRadians = fabric.util.degreesToRadians, + supportsLineDash = fabric.StaticCanvas.supports('setLineDash'), + objectCaching = !fabric.isLikelyNode, + ALIASING_LIMIT = 2; + + if (fabric.Object) { + return; + } + + /** + * Root object class from which all 2d shape classes inherit from + * @class fabric.Object + * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#objects} + * @see {@link fabric.Object#initialize} for constructor definition + * + * @fires added + * @fires removed + * + * @fires selected + * @fires deselected + * @fires modified + * @fires rotating + * @fires scaling + * @fires moving + * @fires skewing + * + * @fires mousedown + * @fires mouseup + * @fires mouseover + * @fires mouseout + * @fires mousewheel + */ + fabric.Object = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.Object.prototype */ { + + /** + * Retrieves object's {@link fabric.Object#clipTo|clipping function} + * @method getClipTo + * @memberOf fabric.Object.prototype + * @return {Function} + */ + + /** + * Sets object's {@link fabric.Object#clipTo|clipping function} + * @method setClipTo + * @memberOf fabric.Object.prototype + * @param {Function} clipTo Clipping function + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#transformMatrix|transformMatrix} + * @method getTransformMatrix + * @memberOf fabric.Object.prototype + * @return {Array} transformMatrix + */ + + /** + * Sets object's {@link fabric.Object#transformMatrix|transformMatrix} + * @method setTransformMatrix + * @memberOf fabric.Object.prototype + * @param {Array} transformMatrix + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#visible|visible} state + * @method getVisible + * @memberOf fabric.Object.prototype + * @return {Boolean} True if visible + */ + + /** + * Sets object's {@link fabric.Object#visible|visible} state + * @method setVisible + * @memberOf fabric.Object.prototype + * @param {Boolean} value visible value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#shadow|shadow} + * @method getShadow + * @memberOf fabric.Object.prototype + * @return {Object} Shadow instance + */ + + /** + * Retrieves object's {@link fabric.Object#stroke|stroke} + * @method getStroke + * @memberOf fabric.Object.prototype + * @return {String} stroke value + */ + + /** + * Sets object's {@link fabric.Object#stroke|stroke} + * @method setStroke + * @memberOf fabric.Object.prototype + * @param {String} value stroke value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#strokeWidth|strokeWidth} + * @method getStrokeWidth + * @memberOf fabric.Object.prototype + * @return {Number} strokeWidth value + */ + + /** + * Sets object's {@link fabric.Object#strokeWidth|strokeWidth} + * @method setStrokeWidth + * @memberOf fabric.Object.prototype + * @param {Number} value strokeWidth value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#originX|originX} + * @method getOriginX + * @memberOf fabric.Object.prototype + * @return {String} originX value + */ + + /** + * Sets object's {@link fabric.Object#originX|originX} + * @method setOriginX + * @memberOf fabric.Object.prototype + * @param {String} value originX value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#originY|originY} + * @method getOriginY + * @memberOf fabric.Object.prototype + * @return {String} originY value + */ + + /** + * Sets object's {@link fabric.Object#originY|originY} + * @method setOriginY + * @memberOf fabric.Object.prototype + * @param {String} value originY value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#fill|fill} + * @method getFill + * @memberOf fabric.Object.prototype + * @return {String} Fill value + */ + + /** + * Sets object's {@link fabric.Object#fill|fill} + * @method setFill + * @memberOf fabric.Object.prototype + * @param {String} value Fill value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#opacity|opacity} + * @method getOpacity + * @memberOf fabric.Object.prototype + * @return {Number} Opacity value (0-1) + */ + + /** + * Sets object's {@link fabric.Object#opacity|opacity} + * @method setOpacity + * @memberOf fabric.Object.prototype + * @param {Number} value Opacity value (0-1) + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#angle|angle} (in degrees) + * @method getAngle + * @memberOf fabric.Object.prototype + * @return {Number} + */ + + /** + * Retrieves object's {@link fabric.Object#top|top position} + * @method getTop + * @memberOf fabric.Object.prototype + * @return {Number} Top value (in pixels) + */ + + /** + * Sets object's {@link fabric.Object#top|top position} + * @method setTop + * @memberOf fabric.Object.prototype + * @param {Number} value Top value (in pixels) + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#left|left position} + * @method getLeft + * @memberOf fabric.Object.prototype + * @return {Number} Left value (in pixels) + */ + + /** + * Sets object's {@link fabric.Object#left|left position} + * @method setLeft + * @memberOf fabric.Object.prototype + * @param {Number} value Left value (in pixels) + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#scaleX|scaleX} value + * @method getScaleX + * @memberOf fabric.Object.prototype + * @return {Number} scaleX value + */ + + /** + * Sets object's {@link fabric.Object#scaleX|scaleX} value + * @method setScaleX + * @memberOf fabric.Object.prototype + * @param {Number} value scaleX value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#scaleY|scaleY} value + * @method getScaleY + * @memberOf fabric.Object.prototype + * @return {Number} scaleY value + */ + + /** + * Sets object's {@link fabric.Object#scaleY|scaleY} value + * @method setScaleY + * @memberOf fabric.Object.prototype + * @param {Number} value scaleY value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#flipX|flipX} value + * @method getFlipX + * @memberOf fabric.Object.prototype + * @return {Boolean} flipX value + */ + + /** + * Sets object's {@link fabric.Object#flipX|flipX} value + * @method setFlipX + * @memberOf fabric.Object.prototype + * @param {Boolean} value flipX value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Retrieves object's {@link fabric.Object#flipY|flipY} value + * @method getFlipY + * @memberOf fabric.Object.prototype + * @return {Boolean} flipY value + */ + + /** + * Sets object's {@link fabric.Object#flipY|flipY} value + * @method setFlipY + * @memberOf fabric.Object.prototype + * @param {Boolean} value flipY value + * @return {fabric.Object} thisArg + * @chainable + */ + + /** + * Type of an object (rect, circle, path, etc.). + * Note that this property is meant to be read-only and not meant to be modified. + * If you modify, certain parts of Fabric (such as JSON loading) won't work correctly. + * @type String + * @default + */ + type: 'object', + + /** + * Horizontal origin of transformation of an object (one of "left", "right", "center") + * See http://jsfiddle.net/1ow02gea/40/ on how originX/originY affect objects in groups + * @type String + * @default + */ + originX: 'left', + + /** + * Vertical origin of transformation of an object (one of "top", "bottom", "center") + * See http://jsfiddle.net/1ow02gea/40/ on how originX/originY affect objects in groups + * @type String + * @default + */ + originY: 'top', + + /** + * Top position of an object. Note that by default it's relative to object top. You can change this by setting originY={top/center/bottom} + * @type Number + * @default + */ + top: 0, + + /** + * Left position of an object. Note that by default it's relative to object left. You can change this by setting originX={left/center/right} + * @type Number + * @default + */ + left: 0, + + /** + * Object width + * @type Number + * @default + */ + width: 0, + + /** + * Object height + * @type Number + * @default + */ + height: 0, + + /** + * Object scale factor (horizontal) + * @type Number + * @default + */ + scaleX: 1, + + /** + * Object scale factor (vertical) + * @type Number + * @default + */ + scaleY: 1, + + /** + * When true, an object is rendered as flipped horizontally + * @type Boolean + * @default + */ + flipX: false, + + /** + * When true, an object is rendered as flipped vertically + * @type Boolean + * @default + */ + flipY: false, + + /** + * Opacity of an object + * @type Number + * @default + */ + opacity: 1, + + /** + * Angle of rotation of an object (in degrees) + * @type Number + * @default + */ + angle: 0, + + /** + * Angle of skew on x axes of an object (in degrees) + * @type Number + * @default + */ + skewX: 0, + + /** + * Angle of skew on y axes of an object (in degrees) + * @type Number + * @default + */ + skewY: 0, + + /** + * Size of object's controlling corners (in pixels) + * @type Number + * @default + */ + cornerSize: 13, + + /** + * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill) + * @type Boolean + * @default + */ + transparentCorners: true, + + /** + * Default cursor value used when hovering over this object on canvas + * @type String + * @default + */ + hoverCursor: null, + + /** + * Default cursor value used when moving this object on canvas + * @type String + * @default + */ + moveCursor: null, + + /** + * Padding between object and its controlling borders (in pixels) + * @type Number + * @default + */ + padding: 0, + + /** + * Color of controlling borders of an object (when it's active) + * @type String + * @default + */ + borderColor: 'rgba(102,153,255,0.75)', + + /** + * Array specifying dash pattern of an object's borders (hasBorder must be true) + * @since 1.6.2 + * @type Array + */ + borderDashArray: null, + + /** + * Color of controlling corners of an object (when it's active) + * @type String + * @default + */ + cornerColor: 'rgba(102,153,255,0.5)', + + /** + * Color of controlling corners of an object (when it's active and transparentCorners false) + * @since 1.6.2 + * @type String + * @default + */ + cornerStrokeColor: null, + + /** + * Specify style of control, 'rect' or 'circle' + * @since 1.6.2 + * @type String + */ + cornerStyle: 'rect', + + /** + * Array specifying dash pattern of an object's control (hasBorder must be true) + * @since 1.6.2 + * @type Array + */ + cornerDashArray: null, + + /** + * When true, this object will use center point as the origin of transformation + * when being scaled via the controls. + * Backwards incompatibility note: This property replaces "centerTransform" (Boolean). + * @since 1.3.4 + * @type Boolean + * @default + */ + centeredScaling: false, + + /** + * When true, this object will use center point as the origin of transformation + * when being rotated via the controls. + * Backwards incompatibility note: This property replaces "centerTransform" (Boolean). + * @since 1.3.4 + * @type Boolean + * @default + */ + centeredRotation: true, + + /** + * Color of object's fill + * @type String + * @default + */ + fill: 'rgb(0,0,0)', + + /** + * Fill rule used to fill an object + * accepted values are nonzero, evenodd + * Backwards incompatibility note: This property was used for setting globalCompositeOperation until v1.4.12 (use `fabric.Object#globalCompositeOperation` instead) + * @type String + * @default + */ + fillRule: 'nonzero', + + /** + * Composite rule used for canvas globalCompositeOperation + * @type String + * @default + */ + globalCompositeOperation: 'source-over', + + /** + * Background color of an object. + * @type String + * @default + */ + backgroundColor: '', + + /** + * Selection Background color of an object. colored layer behind the object when it is active. + * does not mix good with globalCompositeOperation methods. + * @type String + * @default + */ + selectionBackgroundColor: '', + + /** + * When defined, an object is rendered via stroke and this property specifies its color + * @type String + * @default + */ + stroke: null, + + /** + * Width of a stroke used to render this object + * @type Number + * @default + */ + strokeWidth: 1, + + /** + * Array specifying dash pattern of an object's stroke (stroke must be defined) + * @type Array + */ + strokeDashArray: null, + + /** + * Line endings style of an object's stroke (one of "butt", "round", "square") + * @type String + * @default + */ + strokeLineCap: 'butt', + + /** + * Corner style of an object's stroke (one of "bevil", "round", "miter") + * @type String + * @default + */ + strokeLineJoin: 'miter', + + /** + * Maximum miter length (used for strokeLineJoin = "miter") of an object's stroke + * @type Number + * @default + */ + strokeMiterLimit: 10, + + /** + * Shadow object representing shadow of this shape + * @type fabric.Shadow + * @default + */ + shadow: null, + + /** + * Opacity of object's controlling borders when object is active and moving + * @type Number + * @default + */ + borderOpacityWhenMoving: 0.4, + + /** + * Scale factor of object's controlling borders + * @type Number + * @default + */ + borderScaleFactor: 1, + + /** + * Transform matrix (similar to SVG's transform matrix) + * @type Array + */ + transformMatrix: null, + + /** + * Minimum allowed scale value of an object + * @type Number + * @default + */ + minScaleLimit: 0.01, + + /** + * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection). + * But events still fire on it. + * @type Boolean + * @default + */ + selectable: true, + + /** + * When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4 + * @type Boolean + * @default + */ + evented: true, + + /** + * When set to `false`, an object is not rendered on canvas + * @type Boolean + * @default + */ + visible: true, + + /** + * When set to `false`, object's controls are not displayed and can not be used to manipulate object + * @type Boolean + * @default + */ + hasControls: true, + + /** + * When set to `false`, object's controlling borders are not rendered + * @type Boolean + * @default + */ + hasBorders: true, + + /** + * When set to `false`, object's controlling rotating point will not be visible or selectable + * @type Boolean + * @default + */ + hasRotatingPoint: true, + + /** + * Offset for object's controlling rotating point (when enabled via `hasRotatingPoint`) + * @type Number + * @default + */ + rotatingPointOffset: 40, + + /** + * When set to `true`, objects are "found" on canvas on per-pixel basis rather than according to bounding box + * @type Boolean + * @default + */ + perPixelTargetFind: false, + + /** + * When `false`, default object's values are not included in its serialization + * @type Boolean + * @default + */ + includeDefaultValues: true, + + /** + * Function that determines clipping of an object (context is passed as a first argument) + * Note that context origin is at the object's center point (not left/top corner) + * @type Function + */ + clipTo: null, + + /** + * When `true`, object horizontal movement is locked + * @type Boolean + * @default + */ + lockMovementX: false, + + /** + * When `true`, object vertical movement is locked + * @type Boolean + * @default + */ + lockMovementY: false, + + /** + * When `true`, object rotation is locked + * @type Boolean + * @default + */ + lockRotation: false, + + /** + * When `true`, object horizontal scaling is locked + * @type Boolean + * @default + */ + lockScalingX: false, + + /** + * When `true`, object vertical scaling is locked + * @type Boolean + * @default + */ + lockScalingY: false, + + /** + * When `true`, object non-uniform scaling is locked + * @type Boolean + * @default + */ + lockUniScaling: false, + + /** + * When `true`, object horizontal skewing is locked + * @type Boolean + * @default + */ + lockSkewingX: false, + + /** + * When `true`, object vertical skewing is locked + * @type Boolean + * @default + */ + lockSkewingY: false, + + /** + * When `true`, object cannot be flipped by scaling into negative values + * @type Boolean + * @default + */ + lockScalingFlip: false, + + /** + * When `true`, object is not exported in SVG or OBJECT/JSON + * since 1.6.3 + * @type Boolean + * @default + */ + excludeFromExport: false, + + /** + * When `true`, object is cached on an additional canvas. + * default to true + * since 1.7.0 + * @type Boolean + * @default true + */ + objectCaching: objectCaching, + + /** + * When `true`, object properties are checked for cache invalidation. In some particular + * situation you may want this to be disabled ( spray brush, very big pathgroups, groups) + * or if your application does not allow you to modify properties for groups child you want + * to disable it for groups. + * default to false + * since 1.7.0 + * @type Boolean + * @default false + */ + statefullCache: false, + + /** + * When `true`, cache does not get updated during scaling. The picture will get blocky if scaled + * too much and will be redrawn with correct details at the end of scaling. + * this setting is performance and application dependant. + * default to true + * since 1.7.0 + * @type Boolean + * @default true + */ + noScaleCache: true, + + /** + * When set to `true`, object's cache will be rerendered next render call. + * since 1.7.0 + * @type Boolean + * @default true + */ + dirty: true, + + /** + * List of properties to consider when checking if state + * of an object is changed (fabric.Object#hasStateChanged) + * as well as for history (undo/redo) purposes + * @type Array + */ + stateProperties: ( + 'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' + + 'stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit ' + + 'angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor ' + + 'skewX skewY fillRule' + ).split(' '), + + /** + * List of properties to consider when checking if cache needs refresh + * @type Array + */ + cacheProperties: ( + 'fill stroke strokeWidth strokeDashArray width height' + + ' strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor' + ).split(' '), + + /** + * Constructor + * @param {Object} [options] Options object + */ + initialize: function(options) { + options = options || { }; + if (options) { + this.setOptions(options); + } + }, + + /** + * Create a the canvas used to keep the cached copy of the object + * @private + */ + _createCacheCanvas: function() { + this._cacheProperties = {}; + this._cacheCanvas = fabric.document.createElement('canvas'); + this._cacheContext = this._cacheCanvas.getContext('2d'); + this._updateCacheCanvas(); + }, + + /** + * Limit the cache dimensions so that X * Y do not cross fabric.perfLimitSizeTotal + * and each side do not cross fabric.cacheSideLimit + * those numbers are configurable so that you can get as much detail as you want + * making bargain with performances. + * @param {Object} dims + * @param {Object} dims.width width of canvas + * @param {Object} dims.height height of canvas + * @param {Object} dims.zoomX zoomX zoom value to unscale the canvas before drawing cache + * @param {Object} dims.zoomY zoomY zoom value to unscale the canvas before drawing cache + * @return {Object}.width width of canvas + * @return {Object}.height height of canvas + * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache + * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache + */ + _limitCacheSize: function(dims) { + var perfLimitSizeTotal = fabric.perfLimitSizeTotal, + width = dims.width, height = dims.height, + max = fabric.maxCacheSideLimit, min = fabric.minCacheSideLimit; + if (width <= max && height <= max && width * height <= perfLimitSizeTotal) { + if (width < min) { + dims.width = min; + } + if (height < min) { + dims.height = min; + } + return dims; + } + var ar = width / height, limitedDims = fabric.util.limitDimsByArea(ar, perfLimitSizeTotal), + capValue = fabric.util.capValue, + x = capValue(min, limitedDims.x, max), + y = capValue(min, limitedDims.y, max); + if (width > x) { + dims.zoomX /= width / x; + dims.width = x; + dims.capped = true; + } + if (height > y) { + dims.zoomY /= height / y; + dims.height = y; + dims.capped = true; + } + return dims; + }, + + /** + * Return the dimension and the zoom level needed to create a cache canvas + * big enough to host the object to be cached. + * @private + * @param {Object} dim.x width of object to be cached + * @param {Object} dim.y height of object to be cached + * @return {Object}.width width of canvas + * @return {Object}.height height of canvas + * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache + * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache + */ + _getCacheCanvasDimensions: function() { + var zoom = this.canvas && this.canvas.getZoom() || 1, + objectScale = this.getObjectScaling(), + retina = this.canvas && this.canvas._isRetinaScaling() ? fabric.devicePixelRatio : 1, + dim = this._getNonTransformedDimensions(), + zoomX = objectScale.scaleX * zoom * retina, + zoomY = objectScale.scaleY * zoom * retina, + width = dim.x * zoomX, + height = dim.y * zoomY; + return { + width: width + ALIASING_LIMIT, + height: height + ALIASING_LIMIT, + zoomX: zoomX, + zoomY: zoomY, + x: dim.x, + y: dim.y + }; + }, + + /** + * Update width and height of the canvas for cache + * returns true or false if canvas needed resize. + * @private + * @return {Boolean} true if the canvas has been resized + */ + _updateCacheCanvas: function() { + if (this.noScaleCache && this.canvas && this.canvas._currentTransform) { + var target = this.canvas._currentTransform.target, + action = this.canvas._currentTransform.action; + if (this === target && action.slice && action.slice(0, 5) === 'scale') { + return false; + } + } + var canvas = this._cacheCanvas, + dims = this._limitCacheSize(this._getCacheCanvasDimensions()), + minCacheSize = fabric.minCacheSideLimit, + width = dims.width, height = dims.height, drawingWidth, drawingHeight, + zoomX = dims.zoomX, zoomY = dims.zoomY, + dimensionsChanged = width !== this.cacheWidth || height !== this.cacheHeight, + zoomChanged = this.zoomX !== zoomX || this.zoomY !== zoomY, + shouldRedraw = dimensionsChanged || zoomChanged, + additionalWidth = 0, additionalHeight = 0, shouldResizeCanvas = false; + if (dimensionsChanged) { + var canvasWidth = this._cacheCanvas.width, + canvasHeight = this._cacheCanvas.height, + sizeGrowing = width > canvasWidth || height > canvasHeight, + sizeShrinking = (width < canvasWidth * 0.9 || height < canvasHeight * 0.9) && + canvasWidth > minCacheSize && canvasHeight > minCacheSize; + shouldResizeCanvas = sizeGrowing || sizeShrinking; + if (sizeGrowing && !dims.capped && (width > minCacheSize || height > minCacheSize)) { + additionalWidth = width * 0.1; + additionalHeight = height * 0.1; + } + } + if (shouldRedraw) { + if (shouldResizeCanvas) { + canvas.width = Math.ceil(width + additionalWidth); + canvas.height = Math.ceil(height + additionalHeight); + } + else { + this._cacheContext.setTransform(1, 0, 0, 1, 0, 0); + this._cacheContext.clearRect(0, 0, canvas.width, canvas.height); + } + drawingWidth = dims.x * zoomX / 2; + drawingHeight = dims.y * zoomY / 2; + this.cacheTranslationX = Math.round(canvas.width / 2 - drawingWidth) + drawingWidth; + this.cacheTranslationY = Math.round(canvas.height / 2 - drawingHeight) + drawingHeight; + this.cacheWidth = width; + this.cacheHeight = height; + this._cacheContext.translate(this.cacheTranslationX, this.cacheTranslationY); + this._cacheContext.scale(zoomX, zoomY); + this.zoomX = zoomX; + this.zoomY = zoomY; + return true; + } + return false; + }, + + /** + * Sets object's properties from options + * @param {Object} [options] Options object + */ + setOptions: function(options) { + this._setOptions(options); + this._initGradient(options.fill, 'fill'); + this._initGradient(options.stroke, 'stroke'); + this._initClipping(options); + this._initPattern(options.fill, 'fill'); + this._initPattern(options.stroke, 'stroke'); + }, + + /** + * Transforms context when rendering an object + * @param {CanvasRenderingContext2D} ctx Context + * @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node + */ + transform: function(ctx, fromLeft) { + if (this.group && !this.group._transformDone && this.group === this.canvas._activeGroup) { + this.group.transform(ctx); + } + var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint(); + ctx.translate(center.x, center.y); + this.angle && ctx.rotate(degreesToRadians(this.angle)); + ctx.scale( + this.scaleX * (this.flipX ? -1 : 1), + this.scaleY * (this.flipY ? -1 : 1) + ); + this.skewX && ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0); + this.skewY && ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0); + }, + + /** + * Returns an object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} Object representation of an instance + */ + toObject: function(propertiesToInclude) { + var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, + + object = { + type: this.type, + originX: this.originX, + originY: this.originY, + left: toFixed(this.left, NUM_FRACTION_DIGITS), + top: toFixed(this.top, NUM_FRACTION_DIGITS), + width: toFixed(this.width, NUM_FRACTION_DIGITS), + height: toFixed(this.height, NUM_FRACTION_DIGITS), + fill: (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill, + stroke: (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke, + strokeWidth: toFixed(this.strokeWidth, NUM_FRACTION_DIGITS), + strokeDashArray: this.strokeDashArray ? this.strokeDashArray.concat() : this.strokeDashArray, + strokeLineCap: this.strokeLineCap, + strokeLineJoin: this.strokeLineJoin, + strokeMiterLimit: toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS), + scaleX: toFixed(this.scaleX, NUM_FRACTION_DIGITS), + scaleY: toFixed(this.scaleY, NUM_FRACTION_DIGITS), + angle: toFixed(this.getAngle(), NUM_FRACTION_DIGITS), + flipX: this.flipX, + flipY: this.flipY, + opacity: toFixed(this.opacity, NUM_FRACTION_DIGITS), + 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() : null, + skewX: toFixed(this.skewX, NUM_FRACTION_DIGITS), + skewY: toFixed(this.skewY, NUM_FRACTION_DIGITS) + }; + + fabric.util.populateWithProperties(this, object, propertiesToInclude); + + if (!this.includeDefaultValues) { + object = this._removeDefaultValues(object); + } + + return object; + }, + + /** + * Returns (dataless) object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} Object representation of an instance + */ + toDatalessObject: function(propertiesToInclude) { + // will be overwritten by subclasses + return this.toObject(propertiesToInclude); + }, + + /** + * @private + * @param {Object} object + */ + _removeDefaultValues: function(object) { + var prototype = fabric.util.getKlass(object.type).prototype, + stateProperties = prototype.stateProperties; + stateProperties.forEach(function(prop) { + if (object[prop] === prototype[prop]) { + delete object[prop]; + } + var isArray = Object.prototype.toString.call(object[prop]) === '[object Array]' && + Object.prototype.toString.call(prototype[prop]) === '[object Array]'; + + // basically a check for [] === [] + if (isArray && object[prop].length === 0 && prototype[prop].length === 0) { + delete object[prop]; + } + }); + + return object; + }, + + /** + * Returns a string representation of an instance + * @return {String} + */ + toString: function() { + return '#'; + }, + + /** + * Return the object scale factor counting also the group scaling + * @return {Object} object with scaleX and scaleY properties + */ + getObjectScaling: function() { + var scaleX = this.scaleX, scaleY = this.scaleY; + if (this.group) { + var scaling = this.group.getObjectScaling(); + scaleX *= scaling.scaleX; + scaleY *= scaling.scaleY; + } + return { scaleX: scaleX, scaleY: scaleY }; + }, + + /** + * @private + * @param {String} key + * @param {*} value + * @return {fabric.Object} thisArg + */ + _set: function(key, value) { + var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY'), + isChanged = this[key] !== value; + + if (shouldConstrainValue) { + value = this._constrainScale(value); + } + if (key === 'scaleX' && value < 0) { + this.flipX = !this.flipX; + value *= -1; + } + else if (key === 'scaleY' && value < 0) { + this.flipY = !this.flipY; + value *= -1; + } + else if (key === 'shadow' && value && !(value instanceof fabric.Shadow)) { + value = new fabric.Shadow(value); + } + else if (key === 'dirty' && this.group) { + this.group.set('dirty', value); + } + + this[key] = value; + + if (isChanged && this.cacheProperties.indexOf(key) > -1) { + if (this.group) { + this.group.set('dirty', true); + } + this.dirty = true; + } + + if (isChanged && this.group && this.stateProperties.indexOf(key) > -1) { + this.group.set('dirty', true); + } + + if (key === 'width' || key === 'height') { + this.minScaleLimit = Math.min(0.1, 1 / Math.max(this.width, this.height)); + } + + return this; + }, + + /** + * This callback function is called by the parent group of an object every + * time a non-delegated property changes on the group. It is passed the key + * and value as parameters. Not adding in this function's signature to avoid + * Travis build error about unused variables. + */ + setOnGroup: function() { + // implemented by sub-classes, as needed. + }, + + /** + * Sets sourcePath of an object + * @param {String} value Value to set sourcePath to + * @return {fabric.Object} thisArg + * @chainable + */ + setSourcePath: function(value) { + this.sourcePath = value; + return this; + }, + + /** + * Retrieves viewportTransform from Object's canvas if possible + * @method getViewportTransform + * @memberOf fabric.Object.prototype + * @return {Boolean} + */ + getViewportTransform: function() { + if (this.canvas && this.canvas.viewportTransform) { + return this.canvas.viewportTransform; + } + return fabric.iMatrix.concat(); + }, + + /* + * @private + * return if the object would be visible in rendering + * @memberOf fabric.Object.prototype + * @return {Boolean} + */ + isNotVisible: function() { + return this.opacity === 0 || (this.width === 0 && this.height === 0) || !this.visible; + }, + + /** + * Renders an object on a specified context + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} [noTransform] When true, context is not transformed + */ + render: function(ctx, noTransform) { + // do not render if width/height are zeros or object is not visible + if (this.isNotVisible()) { + return; + } + if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) { + return; + } + ctx.save(); + //setup fill rule for current object + this._setupCompositeOperation(ctx); + this.drawSelectionBackground(ctx); + if (!noTransform) { + this.transform(ctx); + } + this._setOpacity(ctx); + this._setShadow(ctx); + if (this.transformMatrix) { + ctx.transform.apply(ctx, this.transformMatrix); + } + this.clipTo && fabric.util.clipContext(this, ctx); + if (this.shouldCache(noTransform)) { + if (!this._cacheCanvas) { + this._createCacheCanvas(); + } + if (this.isCacheDirty(noTransform)) { + this.statefullCache && this.saveState({ propertySet: 'cacheProperties' }); + this.drawObject(this._cacheContext, noTransform); + this.dirty = false; + } + this.drawCacheOnCanvas(ctx); + } + else { + this._removeCacheCanvas(); + this.dirty = false; + this.drawObject(ctx, noTransform); + if (noTransform && this.objectCaching && this.statefullCache) { + this.saveState({ propertySet: 'cacheProperties' }); + } + } + this.clipTo && ctx.restore(); + ctx.restore(); + }, + + /** + * Remove cacheCanvas and its dimensions from the objects + */ + _removeCacheCanvas: function() { + this._cacheCanvas = null; + this.cacheWidth = 0; + this.cacheHeight = 0; + }, + + /** + * When set to `true`, force the object to have its own cache, even if it is inside a group + * it may be needed when your object behave in a particular way on the cache and always needs + * its own isolated canvas to render correctly. + * This function is created to be subclassed by custom classes. + * since 1.7.12 + * @type function + * @return false + */ + needsItsOwnCache: function() { + return false; + }, + + /** + * Decide if the object should cache or not. + * objectCaching is a global flag, wins over everything + * needsItsOwnCache should be used when the object drawing method requires + * a cache step. None of the fabric classes requires it. + * Generally you do not cache objects in groups because the group outside is cached. + * @param {Boolean} noTransform if rendereing in pathGroup, caching is not supported at object level + * @return {Boolean} + */ + shouldCache: function(noTransform) { + return !noTransform && this.objectCaching && + (!this.group || this.needsItsOwnCache() || !this.group.isCaching()); + }, + + /** + * Check if this object or a child object will cast a shadow + * used by Group.shouldCache to know if child has a shadow recursively + * @return {Boolean} + */ + willDrawShadow: function() { + return !!this.shadow && (this.shadow.offsetX !== 0 || this.shadow.offsetY !== 0); + }, + + /** + * Execute the drawing operation for an object on a specified context + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} [noTransform] When true, context is not transformed + */ + drawObject: function(ctx, noTransform) { + this._renderBackground(ctx); + this._setStrokeStyles(ctx); + this._setFillStyles(ctx); + this._render(ctx, noTransform); + }, + + /** + * Paint the cached copy of the object on the target context. + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + drawCacheOnCanvas: function(ctx) { + ctx.scale(1 / this.zoomX, 1 / this.zoomY); + ctx.drawImage(this._cacheCanvas, -this.cacheTranslationX, -this.cacheTranslationY); + }, + + /** + * Check if cache is dirty + * @param {Boolean} skipCanvas skip canvas checks because this object is painted + * on parent canvas. + */ + isCacheDirty: function(skipCanvas) { + if (this.isNotVisible()) { + return false; + } + if (this._cacheCanvas && !skipCanvas && this._updateCacheCanvas()) { + // in this case the context is already cleared. + return true; + } + else { + if (this.dirty || (this.statefullCache && this.hasStateChanged('cacheProperties'))) { + if (this._cacheCanvas && !skipCanvas) { + var width = this.cacheWidth / this.zoomX; + var height = this.cacheHeight / this.zoomY; + this._cacheContext.clearRect(-width / 2, -height / 2, width, height); + } + return true; + } + } + return false; + }, + + /** + * Draws a background for the object big as its untrasformed dimensions + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderBackground: function(ctx) { + if (!this.backgroundColor) { + return; + } + var dim = this._getNonTransformedDimensions(); + ctx.fillStyle = this.backgroundColor; + + ctx.fillRect( + -dim.x / 2, + -dim.y / 2, + dim.x, + dim.y + ); + // if there is background color no other shadows + // should be casted + this._removeShadow(ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _setOpacity: function(ctx) { + ctx.globalAlpha *= this.opacity; + }, + + _setStrokeStyles: function(ctx) { + if (this.stroke) { + ctx.lineWidth = this.strokeWidth; + ctx.lineCap = this.strokeLineCap; + ctx.lineJoin = this.strokeLineJoin; + ctx.miterLimit = this.strokeMiterLimit; + ctx.strokeStyle = this.stroke.toLive + ? this.stroke.toLive(ctx, this) + : this.stroke; + } + }, + + _setFillStyles: function(ctx) { + if (this.fill) { + ctx.fillStyle = this.fill.toLive + ? this.fill.toLive(ctx, this) + : this.fill; + } + }, + + /** + * @private + * 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 + */ + _setLineDash: function(ctx, dashArray, alternative) { + if (!dashArray) { + return; + } + // Spec requires the concatenation of two copies the dash list when the number of elements is odd + if (1 & dashArray.length) { + dashArray.push.apply(dashArray, dashArray); + } + if (supportsLineDash) { + ctx.setLineDash(dashArray); + } + else { + alternative && alternative(ctx); + } + }, + + /** + * Renders controls and borders for the object + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderControls: function(ctx) { + if (!this.active || (this.group && this.group !== this.canvas.getActiveGroup())) { + return; + } + + var vpt = this.getViewportTransform(), + matrix = this.calcTransformMatrix(), + options; + matrix = fabric.util.multiplyTransformMatrices(vpt, matrix); + options = fabric.util.qrDecompose(matrix); + + ctx.save(); + ctx.translate(options.translateX, options.translateY); + ctx.lineWidth = 1 * this.borderScaleFactor; + if (!this.group) { + ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1; + } + if (this.group && this.group === this.canvas.getActiveGroup()) { + ctx.rotate(degreesToRadians(options.angle)); + this.drawBordersInGroup(ctx, options); + } + else { + ctx.rotate(degreesToRadians(this.angle)); + this.drawBorders(ctx); + } + this.drawControls(ctx); + ctx.restore(); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _setShadow: function(ctx) { + if (!this.shadow) { + return; + } + + var multX = (this.canvas && this.canvas.viewportTransform[0]) || 1, + multY = (this.canvas && this.canvas.viewportTransform[3]) || 1, + scaling = this.getObjectScaling(); + if (this.canvas && this.canvas._isRetinaScaling()) { + multX *= fabric.devicePixelRatio; + multY *= fabric.devicePixelRatio; + } + ctx.shadowColor = this.shadow.color; + ctx.shadowBlur = this.shadow.blur * (multX + multY) * (scaling.scaleX + scaling.scaleY) / 4; + ctx.shadowOffsetX = this.shadow.offsetX * multX * scaling.scaleX; + ctx.shadowOffsetY = this.shadow.offsetY * multY * scaling.scaleY; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _removeShadow: function(ctx) { + if (!this.shadow) { + return; + } + + ctx.shadowColor = ''; + ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Object} filler fabric.Pattern or fabric.Gradient + */ + _applyPatternGradientTransform: function(ctx, filler) { + if (!filler.toLive) { + return; + } + var transform = filler.gradientTransform || filler.patternTransform; + if (transform) { + ctx.transform.apply(ctx, transform); + } + var offsetX = -this.width / 2 + filler.offsetX || 0, + offsetY = -this.height / 2 + filler.offsetY || 0; + ctx.translate(offsetX, offsetY); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderFill: function(ctx) { + if (!this.fill) { + return; + } + + ctx.save(); + this._applyPatternGradientTransform(ctx, this.fill); + if (this.fillRule === 'evenodd') { + ctx.fill('evenodd'); + } + else { + ctx.fill(); + } + ctx.restore(); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderStroke: function(ctx) { + if (!this.stroke || this.strokeWidth === 0) { + return; + } + + if (this.shadow && !this.shadow.affectStroke) { + this._removeShadow(ctx); + } + + ctx.save(); + this._setLineDash(ctx, this.strokeDashArray, this._renderDashedStroke); + this._applyPatternGradientTransform(ctx, this.stroke); + ctx.stroke(); + ctx.restore(); + }, + + /** + * 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 + */ + clone: function(callback, propertiesToInclude) { + if (this.constructor.fromObject) { + return this.constructor.fromObject(this.toObject(propertiesToInclude), callback); + } + return new fabric.Object(this.toObject(propertiesToInclude)); + }, + + /** + * Creates an instance of fabric.Image out of an object + * @param {Function} callback callback, invoked with an instance as a first argument + * @param {Object} [options] for clone as image, passed to toDataURL + * @param {Boolean} [options.enableRetinaScaling] enable retina scaling for the cloned image + * @return {fabric.Object} thisArg + */ + cloneAsImage: function(callback, options) { + var dataUrl = this.toDataURL(options); + fabric.util.loadImage(dataUrl, function(img) { + if (callback) { + callback(new fabric.Image(img)); + } + }); + return this; + }, + + /** + * Converts an object into a data-url-like string + * @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 + * @param {Boolean} [options.enableRetina] Enable retina scaling for clone image. Introduce in 1.6.4 + * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format + */ + toDataURL: function(options) { + options || (options = { }); + + var el = fabric.util.createCanvasElement(), + boundingRect = this.getBoundingRect(); + + 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'; + } + + if (options.format === 'jpeg') { + canvas.backgroundColor = '#fff'; + } + + var origParams = { + active: this.get('active'), + left: this.getLeft(), + top: this.getTop() + }; + + this.set('active', false); + this.setPositionByOrigin(new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2), 'center', 'center'); + + var originalCanvas = this.canvas; + canvas.add(this); + var data = canvas.toDataURL(options); + + this.set(origParams).setCoords(); + this.canvas = originalCanvas; + + canvas.dispose(); + canvas = null; + + return data; + }, + + /** + * Returns true if specified type is identical to the type of an instance + * @param {String} type Type to check against + * @return {Boolean} + */ + isType: function(type) { + return this.type === type; + }, + + /** + * Returns complexity of an instance + * @return {Number} complexity of this instance (is 1 unless subclassed) + */ + complexity: function() { + return 1; + }, + + /** + * Returns a JSON representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} JSON + */ + toJSON: function(propertiesToInclude) { + // delegate, not alias + return this.toObject(propertiesToInclude); + }, + + /** + * Sets gradient (fill or stroke) of an object + * Backwards incompatibility note: This method was named "setGradientFill" until v1.1.0 + * @param {String} property Property name 'stroke' or 'fill' + * @param {Object} [options] Options object + * @param {String} [options.type] Type of gradient 'radial' or 'linear' + * @param {Number} [options.x1=0] x-coordinate of start point + * @param {Number} [options.y1=0] y-coordinate of start point + * @param {Number} [options.x2=0] x-coordinate of end point + * @param {Number} [options.y2=0] y-coordinate of end point + * @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 + * @return {fabric.Object} thisArg + * @chainable + * @see {@link http://jsfiddle.net/fabricjs/58y8b/|jsFiddle demo} + * @example Set linear gradient + * object.setGradient('fill', { + * type: 'linear', + * x1: -object.width / 2, + * y1: 0, + * x2: object.width / 2, + * y2: 0, + * colorStops: { + * 0: 'red', + * 0.5: '#005555', + * 1: 'rgba(0,0,255,0.5)' + * } + * }); + * canvas.renderAll(); + * @example Set radial gradient + * object.setGradient('fill', { + * type: 'radial', + * x1: 0, + * y1: 0, + * x2: 0, + * y2: 0, + * r1: object.width / 2, + * r2: 10, + * colorStops: { + * 0: 'red', + * 0.5: '#005555', + * 1: 'rgba(0,0,255,0.5)' + * } + * }); + * canvas.renderAll(); + */ + setGradient: function(property, options) { + options || (options = { }); + + var gradient = { colorStops: [] }; + + gradient.type = options.type || (options.r1 || options.r2 ? 'radial' : 'linear'); + gradient.coords = { + x1: options.x1, + y1: options.y1, + x2: options.x2, + y2: options.y2 + }; + + if (options.r1 || options.r2) { + gradient.coords.r1 = options.r1; + gradient.coords.r2 = options.r2; + } + + gradient.gradientTransform = options.gradientTransform; + fabric.Gradient.prototype.addColorStop.call(gradient, options.colorStops); + + return this.set(property, fabric.Gradient.forObject(this, gradient)); + }, + + /** + * Sets pattern fill of an object + * @param {Object} options Options object + * @param {(String|HTMLImageElement)} options.source Pattern source + * @param {String} [options.repeat=repeat] Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat) + * @param {Number} [options.offsetX=0] Pattern horizontal offset from object's left/top corner + * @param {Number} [options.offsetY=0] Pattern vertical offset from object's left/top corner + * @return {fabric.Object} thisArg + * @chainable + * @see {@link http://jsfiddle.net/fabricjs/QT3pa/|jsFiddle demo} + * @example Set pattern + * fabric.util.loadImage('http://fabricjs.com/assets/escheresque_ste.png', function(img) { + * object.setPatternFill({ + * source: img, + * repeat: 'repeat' + * }); + * canvas.renderAll(); + * }); + */ + setPatternFill: function(options) { + return this.set('fill', new fabric.Pattern(options)); + }, + + /** + * Sets {@link fabric.Object#shadow|shadow} of an object + * @param {Object|String} [options] Options object or string (e.g. "2px 2px 10px rgba(0,0,0,0.2)") + * @param {String} [options.color=rgb(0,0,0)] Shadow color + * @param {Number} [options.blur=0] Shadow blur + * @param {Number} [options.offsetX=0] Shadow horizontal offset + * @param {Number} [options.offsetY=0] Shadow vertical offset + * @return {fabric.Object} thisArg + * @chainable + * @see {@link http://jsfiddle.net/fabricjs/7gvJG/|jsFiddle demo} + * @example Set shadow with string notation + * object.setShadow('2px 2px 10px rgba(0,0,0,0.2)'); + * canvas.renderAll(); + * @example Set shadow with object notation + * object.setShadow({ + * color: 'red', + * blur: 10, + * offsetX: 20, + * offsetY: 20 + * }); + * canvas.renderAll(); + */ + setShadow: function(options) { + return this.set('shadow', options ? new fabric.Shadow(options) : null); + }, + + /** + * Sets "color" of an instance (alias of `set('fill', …)`) + * @param {String} color Color value + * @return {fabric.Object} thisArg + * @chainable + */ + setColor: function(color) { + this.set('fill', color); + return this; + }, + + /** + * Sets "angle" of an instance + * @param {Number} angle Angle value (in degrees) + * @return {fabric.Object} thisArg + * @chainable + */ + setAngle: function(angle) { + var shouldCenterOrigin = (this.originX !== 'center' || this.originY !== 'center') && this.centeredRotation; + + if (shouldCenterOrigin) { + this._setOriginToCenter(); + } + + this.set('angle', angle); + + if (shouldCenterOrigin) { + this._resetOrigin(); + } + + return this; + }, + + /** + * Centers object horizontally on canvas to which it was added last. + * You might need to call `setCoords` on an object after centering, to update controls area. + * @return {fabric.Object} thisArg + * @chainable + */ + centerH: function () { + this.canvas && this.canvas.centerObjectH(this); + return this; + }, + + /** + * Centers object horizontally on current viewport of canvas to which it was added last. + * You might need to call `setCoords` on an object after centering, to update controls area. + * @return {fabric.Object} thisArg + * @chainable + */ + viewportCenterH: function () { + this.canvas && this.canvas.viewportCenterObjectH(this); + return this; + }, + + /** + * Centers object vertically on canvas to which it was added last. + * You might need to call `setCoords` on an object after centering, to update controls area. + * @return {fabric.Object} thisArg + * @chainable + */ + centerV: function () { + this.canvas && this.canvas.centerObjectV(this); + return this; + }, + + /** + * Centers object vertically on current viewport of canvas to which it was added last. + * You might need to call `setCoords` on an object after centering, to update controls area. + * @return {fabric.Object} thisArg + * @chainable + */ + viewportCenterV: function () { + this.canvas && this.canvas.viewportCenterObjectV(this); + return this; + }, + + /** + * Centers object vertically and horizontally on canvas to which is was added last + * You might need to call `setCoords` on an object after centering, to update controls area. + * @return {fabric.Object} thisArg + * @chainable + */ + center: function () { + this.canvas && this.canvas.centerObject(this); + return this; + }, + + /** + * Centers object on current viewport of canvas to which it was added last. + * You might need to call `setCoords` on an object after centering, to update controls area. + * @return {fabric.Object} thisArg + * @chainable + */ + viewportCenter: function () { + this.canvas && this.canvas.viewportCenterObject(this); + return this; + }, + + /** + * Removes object from canvas to which it was added last + * @return {fabric.Object} thisArg + * @chainable + */ + remove: function() { + if (this.canvas) { + if (this.group && this.group === this.canvas._activeGroup) { + this.group.remove(this); + } + this.canvas.remove(this); + } + return this; + }, + + /** + * Returns coordinates of a pointer relative to an object + * @param {Event} e Event to operate upon + * @param {Object} [pointer] Pointer to operate upon (instead of event) + * @return {Object} Coordinates of a pointer (x, y) + */ + getLocalPointer: function(e, pointer) { + pointer = pointer || this.canvas.getPointer(e); + var pClicked = new fabric.Point(pointer.x, pointer.y), + objectLeftTop = this._getLeftTopCoords(); + if (this.angle) { + pClicked = fabric.util.rotatePoint( + pClicked, objectLeftTop, degreesToRadians(-this.angle)); + } + return { + x: pClicked.x - objectLeftTop.x, + y: pClicked.y - objectLeftTop.y + }; + }, + + /** + * Sets canvas globalCompositeOperation for specific object + * custom composition operation for the particular object can be specifed using globalCompositeOperation property + * @param {CanvasRenderingContext2D} ctx Rendering canvas context + */ + _setupCompositeOperation: function (ctx) { + if (this.globalCompositeOperation) { + ctx.globalCompositeOperation = this.globalCompositeOperation; + } + } + }); + + fabric.util.createAccessors(fabric.Object); + + /** + * Alias for {@link fabric.Object.prototype.setAngle} + * @alias rotate -> setAngle + * @memberOf fabric.Object + */ + fabric.Object.prototype.rotate = fabric.Object.prototype.setAngle; + + extend(fabric.Object.prototype, fabric.Observable); + + /** + * Defines the number of fraction digits to use when serializing object values. + * You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc. + * @static + * @memberOf fabric.Object + * @constant + * @type Number + */ + fabric.Object.NUM_FRACTION_DIGITS = 2; + + fabric.Object._fromObject = function(className, object, callback, forceAsync, extraParam) { + var klass = fabric[className]; + object = clone(object, true); + if (forceAsync) { + fabric.util.enlivenPatterns([object.fill, object.stroke], function(patterns) { + if (typeof patterns[0] !== 'undefined') { + object.fill = patterns[0]; + } + if (typeof patterns[1] !== 'undefined') { + object.stroke = patterns[1]; + } + var instance = extraParam ? new klass(object[extraParam], object) : new klass(object); + callback && callback(instance); + }); + } + else { + var instance = extraParam ? new klass(object[extraParam], object) : new klass(object); + callback && callback(instance); + return instance; + } + }; + + /** + * Unique id used internally when creating SVG elements + * @static + * @memberOf fabric.Object + * @type Number + */ + fabric.Object.__uid = 0; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function() { + + var degreesToRadians = fabric.util.degreesToRadians, + originXOffset = { + left: -0.5, + center: 0, + right: 0.5 + }, + originYOffset = { + top: -0.5, + center: 0, + bottom: 0.5 + }; + + fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + + /** + * Translates the coordinates from origin to center coordinates (based on the object's dimensions) + * @param {fabric.Point} point The point which corresponds to the originX and originY params + * @param {String} fromOriginX Horizontal origin: 'left', 'center' or 'right' + * @param {String} fromOriginY Vertical origin: 'top', 'center' or 'bottom' + * @param {String} toOriginX Horizontal origin: 'left', 'center' or 'right' + * @param {String} toOriginY Vertical origin: 'top', 'center' or 'bottom' + * @return {fabric.Point} + */ + translateToGivenOrigin: function(point, fromOriginX, fromOriginY, toOriginX, toOriginY) { + var x = point.x, + y = point.y, + offsetX, offsetY, dim; + + if (typeof fromOriginX === 'string') { + fromOriginX = originXOffset[fromOriginX]; + } + else { + fromOriginX -= 0.5; + } + + if (typeof toOriginX === 'string') { + toOriginX = originXOffset[toOriginX]; + } + else { + toOriginX -= 0.5; + } + + offsetX = toOriginX - fromOriginX; + + if (typeof fromOriginY === 'string') { + fromOriginY = originYOffset[fromOriginY]; + } + else { + fromOriginY -= 0.5; + } + + if (typeof toOriginY === 'string') { + toOriginY = originYOffset[toOriginY]; + } + else { + toOriginY -= 0.5; + } + + offsetY = toOriginY - fromOriginY; + + if (offsetX || offsetY) { + dim = this._getTransformedDimensions(); + x = point.x + offsetX * dim.x; + y = point.y + offsetY * dim.y; + } + + return new fabric.Point(x, y); + }, + + /** + * Translates the coordinates from origin to center coordinates (based on the object's dimensions) + * @param {fabric.Point} point The point which corresponds to the originX and originY params + * @param {String} originX Horizontal origin: 'left', 'center' or 'right' + * @param {String} originY Vertical origin: 'top', 'center' or 'bottom' + * @return {fabric.Point} + */ + translateToCenterPoint: function(point, originX, originY) { + var p = this.translateToGivenOrigin(point, originX, originY, 'center', 'center'); + if (this.angle) { + return fabric.util.rotatePoint(p, point, degreesToRadians(this.angle)); + } + return p; + }, + + /** + * Translates the coordinates from center to origin coordinates (based on the object's dimensions) + * @param {fabric.Point} center The point which corresponds to center of the object + * @param {String} originX Horizontal origin: 'left', 'center' or 'right' + * @param {String} originY Vertical origin: 'top', 'center' or 'bottom' + * @return {fabric.Point} + */ + translateToOriginPoint: function(center, originX, originY) { + var p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY); + if (this.angle) { + return fabric.util.rotatePoint(p, center, degreesToRadians(this.angle)); + } + return p; + }, + + /** + * Returns the real center coordinates of the object + * @return {fabric.Point} + */ + getCenterPoint: function() { + var leftTop = new fabric.Point(this.left, this.top); + return this.translateToCenterPoint(leftTop, this.originX, this.originY); + }, + + /** + * Returns the coordinates of the object based on center coordinates + * @param {fabric.Point} point The point which corresponds to the originX and originY params + * @return {fabric.Point} + */ + // getOriginPoint: function(center) { + // return this.translateToOriginPoint(center, this.originX, this.originY); + // }, + + /** + * Returns the coordinates of the object as if it has a different origin + * @param {String} originX Horizontal origin: 'left', 'center' or 'right' + * @param {String} originY Vertical origin: 'top', 'center' or 'bottom' + * @return {fabric.Point} + */ + getPointByOrigin: function(originX, originY) { + var center = this.getCenterPoint(); + return this.translateToOriginPoint(center, originX, originY); + }, + + /** + * Returns the point in local coordinates + * @param {fabric.Point} point The point relative to the global coordinate system + * @param {String} originX Horizontal origin: 'left', 'center' or 'right' + * @param {String} originY Vertical origin: 'top', 'center' or 'bottom' + * @return {fabric.Point} + */ + toLocalPoint: function(point, originX, originY) { + var center = this.getCenterPoint(), + p, p2; + + if (typeof originX !== 'undefined' && typeof originY !== 'undefined' ) { + p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY); + } + else { + p = new fabric.Point(this.left, this.top); + } + + p2 = new fabric.Point(point.x, point.y); + if (this.angle) { + p2 = fabric.util.rotatePoint(p2, center, -degreesToRadians(this.angle)); + } + return p2.subtractEquals(p); + }, + + /** + * Returns the point in global coordinates + * @param {fabric.Point} The point relative to the local coordinate system + * @return {fabric.Point} + */ + // toGlobalPoint: function(point) { + // return fabric.util.rotatePoint(point, this.getCenterPoint(), degreesToRadians(this.angle)).addEquals(new fabric.Point(this.left, this.top)); + // }, + + /** + * Sets the position of the object taking into consideration the object's origin + * @param {fabric.Point} pos The new position of the object + * @param {String} originX Horizontal origin: 'left', 'center' or 'right' + * @param {String} originY Vertical origin: 'top', 'center' or 'bottom' + * @return {void} + */ + setPositionByOrigin: function(pos, originX, originY) { + var center = this.translateToCenterPoint(pos, originX, originY), + position = this.translateToOriginPoint(center, this.originX, this.originY); + + this.set('left', position.x); + this.set('top', position.y); + }, + + /** + * @param {String} to One of 'left', 'center', 'right' + */ + adjustPosition: function(to) { + var angle = degreesToRadians(this.angle), + hypotFull = this.getWidth(), + xFull = Math.cos(angle) * hypotFull, + yFull = Math.sin(angle) * hypotFull, + offsetFrom, offsetTo; + + //TODO: this function does not consider mixed situation like top, center. + if (typeof this.originX === 'string') { + offsetFrom = originXOffset[this.originX]; + } + else { + offsetFrom = this.originX - 0.5; + } + if (typeof to === 'string') { + offsetTo = originXOffset[to]; + } + else { + offsetTo = to - 0.5; + } + this.left += xFull * (offsetTo - offsetFrom); + this.top += yFull * (offsetTo - offsetFrom); + this.setCoords(); + this.originX = to; + }, + + /** + * Sets the origin/position of the object to it's center point + * @private + * @return {void} + */ + _setOriginToCenter: function() { + this._originalOriginX = this.originX; + this._originalOriginY = this.originY; + + var center = this.getCenterPoint(); + + this.originX = 'center'; + this.originY = 'center'; + + this.left = center.x; + this.top = center.y; + }, + + /** + * Resets the origin/position of the object to it's original origin + * @private + * @return {void} + */ + _resetOrigin: function() { + var originPoint = this.translateToOriginPoint( + this.getCenterPoint(), + this._originalOriginX, + this._originalOriginY); + + this.originX = this._originalOriginX; + this.originY = this._originalOriginY; + + this.left = originPoint.x; + this.top = originPoint.y; + + this._originalOriginX = null; + this._originalOriginY = null; + }, + + /** + * @private + */ + _getLeftTopCoords: function() { + return this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top'); + }, + + /** + * Callback; invoked right before object is about to go from active to inactive + */ + onDeselect: function() { + /* NOOP */ + } + }); + +})(); + + +(function() { + + function getCoords(coords) { + return [ + new fabric.Point(coords.tl.x, coords.tl.y), + new fabric.Point(coords.tr.x, coords.tr.y), + new fabric.Point(coords.br.x, coords.br.y), + new fabric.Point(coords.bl.x, coords.bl.y) + ]; + } + + var degreesToRadians = fabric.util.degreesToRadians, + multiplyMatrices = fabric.util.multiplyTransformMatrices; + + fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + + /** + * Describe object's corner position in canvas element coordinates. + * properties are tl,mt,tr,ml,mr,bl,mb,br,mtr for the main controls. + * each property is an object with x, y and corner. + * The `corner` property contains in a similar manner the 4 points of the + * interactive area of the corner. + * The coordinates depends from this properties: width, height, scaleX, scaleY + * skewX, skewY, angle, strokeWidth, viewportTransform, top, left, padding. + * The coordinates get updated with @method setCoords. + * You can calculate them without updating with @method calcCoords; + * @memberOf fabric.Object.prototype + */ + oCoords: null, + + /** + * Describe object's corner position in canvas object absolute coordinates + * properties are tl,tr,bl,br and describe the four main corner. + * each property is an object with x, y, instance of Fabric.Point. + * The coordinates depends from this properties: width, height, scaleX, scaleY + * skewX, skewY, angle, strokeWidth, top, left. + * Those coordinates are usefull to understand where an object is. They get updated + * with oCoords but they do not need to be updated when zoom or panning change. + * The coordinates get updated with @method setCoords. + * You can calculate them without updating with @method calcCoords(true); + * @memberOf fabric.Object.prototype + */ + aCoords: null, + + /** + * return correct set of coordinates for intersection + */ + getCoords: function(absolute, calculate) { + if (!this.oCoords) { + this.setCoords(); + } + var coords = absolute ? this.aCoords : this.oCoords; + return getCoords(calculate ? this.calcCoords(absolute) : coords); + }, + + /** + * Checks if object intersects with an area formed by 2 points + * @param {Object} pointTL top-left point of area + * @param {Object} pointBR bottom-right point of area + * @param {Boolean} [absolute] use coordinates without viewportTransform + * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords + * @return {Boolean} true if object intersects with an area formed by 2 points + */ + intersectsWithRect: function(pointTL, pointBR, absolute, calculate) { + var coords = this.getCoords(absolute, calculate), + intersection = fabric.Intersection.intersectPolygonRectangle( + coords, + pointTL, + pointBR + ); + return intersection.status === 'Intersection'; + }, + + /** + * Checks if object intersects with another object + * @param {Object} other Object to test + * @param {Boolean} [absolute] use coordinates without viewportTransform + * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords + * @return {Boolean} true if object intersects with another object + */ + intersectsWithObject: function(other, absolute, calculate) { + var intersection = fabric.Intersection.intersectPolygonPolygon( + this.getCoords(absolute, calculate), + other.getCoords(absolute, calculate) + ); + + return intersection.status === 'Intersection' + || other.isContainedWithinObject(this, absolute, calculate) + || this.isContainedWithinObject(other, absolute, calculate); + }, + + /** + * Checks if object is fully contained within area of another object + * @param {Object} other Object to test + * @param {Boolean} [absolute] use coordinates without viewportTransform + * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords + * @return {Boolean} true if object is fully contained within area of another object + */ + isContainedWithinObject: function(other, absolute, calculate) { + var points = this.getCoords(absolute, calculate), + i = 0, lines = other._getImageLines( + calculate ? other.calcCoords(absolute) : absolute ? other.aCoords : other.oCoords + ); + for (; i < 4; i++) { + if (!other.containsPoint(points[i], lines)) { + return false; + } + } + return true; + }, + + /** + * Checks if object is fully contained within area formed by 2 points + * @param {Object} pointTL top-left point of area + * @param {Object} pointBR bottom-right point of area + * @param {Boolean} [absolute] use coordinates without viewportTransform + * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords + * @return {Boolean} true if object is fully contained within area formed by 2 points + */ + isContainedWithinRect: function(pointTL, pointBR, absolute, calculate) { + var boundingRect = this.getBoundingRect(absolute, calculate); + + return ( + boundingRect.left >= pointTL.x && + boundingRect.left + boundingRect.width <= pointBR.x && + boundingRect.top >= pointTL.y && + boundingRect.top + boundingRect.height <= pointBR.y + ); + }, + + /** + * Checks if point is inside the object + * @param {fabric.Point} point Point to check against + * @param {Object} [lines] object returned from @method _getImageLines + * @param {Boolean} [absolute] use coordinates without viewportTransform + * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords + * @return {Boolean} true if point is inside the object + */ + containsPoint: function(point, lines, absolute, calculate) { + var lines = lines || this._getImageLines( + calculate ? this.calcCoords(absolute) : absolute ? this.aCoords : this.oCoords + ), + xPoints = this._findCrossPoints(point, lines); + + // if xPoints is odd then point is inside the object + return (xPoints !== 0 && xPoints % 2 === 1); + }, + + /** + * Checks if object is contained within the canvas with current viewportTransform + * the check is done stopping at first point that appear on screen + * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords + * @return {Boolean} true if object is fully contained within canvas + */ + isOnScreen: function(calculate) { + if (!this.canvas) { + return false; + } + var pointTL = this.canvas.vptCoords.tl, pointBR = this.canvas.vptCoords.br; + var points = this.getCoords(true, calculate), point; + for (var i = 0; i < 4; i++) { + point = points[i]; + if (point.x <= pointBR.x && point.x >= pointTL.x && point.y <= pointBR.y && point.y >= pointTL.y) { + return true; + } + } + // no points on screen, check intersection with absolute coordinates + if (this.intersectsWithRect(pointTL, pointBR, true)) { + return true; + } + // worst case scenario the object is so big that contanins the screen + var centerPoint = { x: (pointTL.x + pointBR.x) / 2, y: (pointTL.y + pointBR.y) / 2 }; + if (this.containsPoint(centerPoint, null, true)) { + return true; + } + return false; + }, + + /** + * Method that returns an object with the object edges in it, given the coordinates of the corners + * @private + * @param {Object} oCoords Coordinates of the object corners + */ + _getImageLines: function(oCoords) { + return { + topline: { + o: oCoords.tl, + d: oCoords.tr + }, + rightline: { + o: oCoords.tr, + d: oCoords.br + }, + bottomline: { + o: oCoords.br, + d: oCoords.bl + }, + leftline: { + o: oCoords.bl, + d: oCoords.tl + } + }; + }, + + /** + * Helper method to determine how many cross points are between the 4 object edges + * and the horizontal line determined by a point on canvas + * @private + * @param {fabric.Point} point Point to check + * @param {Object} lines Coordinates of the object being evaluated + */ + // remove yi, not used but left code here just in case. + _findCrossPoints: function(point, lines) { + var b1, b2, a1, a2, xi, // yi, + xcount = 0, + iLine; + + for (var lineKey in lines) { + iLine = lines[lineKey]; + // optimisation 1: line below point. no cross + if ((iLine.o.y < point.y) && (iLine.d.y < point.y)) { + continue; + } + // optimisation 2: line above point. no cross + if ((iLine.o.y >= point.y) && (iLine.d.y >= point.y)) { + continue; + } + // optimisation 3: vertical line case + if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= point.x)) { + xi = iLine.o.x; + // yi = point.y; + } + // calculate the intersection point + 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; + } + // dont count xi < point.x cases + if (xi >= point.x) { + xcount += 1; + } + // optimisation 4: specific for square images + if (xcount === 2) { + break; + } + } + return xcount; + }, + + /** + * Returns width of an object's bounding rectangle + * @deprecated since 1.0.4 + * @return {Number} width value + */ + getBoundingRectWidth: function() { + return this.getBoundingRect().width; + }, + + /** + * Returns height of an object's bounding rectangle + * @deprecated since 1.0.4 + * @return {Number} height value + */ + getBoundingRectHeight: function() { + return this.getBoundingRect().height; + }, + + /** + * Returns coordinates of object's bounding rectangle (left, top, width, height) + * the box is intented as aligned to axis of canvas. + * @param {Boolean} [absolute] use coordinates without viewportTransform + * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords + * @return {Object} Object with left, top, width, height properties + */ + getBoundingRect: function(absolute, calculate) { + var coords = this.getCoords(absolute, calculate); + return fabric.util.makeBoundingBoxFromPoints(coords); + }, + + /** + * Returns width of an object bounding box counting transformations + * @return {Number} width value + */ + getWidth: function() { + return this._getTransformedDimensions().x; + }, + + /** + * Returns height of an object bounding box counting transformations + * to be renamed in 2.0 + * @return {Number} height value + */ + getHeight: function() { + return this._getTransformedDimensions().y; + }, + + /** + * Makes sure the scale is valid and modifies it if necessary + * @private + * @param {Number} value + * @return {Number} + */ + _constrainScale: function(value) { + if (Math.abs(value) < this.minScaleLimit) { + if (value < 0) { + return -this.minScaleLimit; + } + else { + return this.minScaleLimit; + } + } else if (value !== value) { + return this.minScaleLimit; + } else if (value === 0) { + return 1e-4; + } + return value; + }, + + /** + * Scales an object (equally by x and y) + * @param {Number} value Scale factor + * @return {fabric.Object} thisArg + * @chainable + */ + scale: function(value) { + value = this._constrainScale(value); + + if (value < 0) { + this.flipX = !this.flipX; + this.flipY = !this.flipY; + value *= -1; + } + + this.scaleX = value; + this.scaleY = value; + return this.setCoords(); + }, + + /** + * Scales an object to a given width, with respect to bounding box (scaling by x/y equally) + * @param {Number} value New width value + * @return {fabric.Object} thisArg + * @chainable + */ + scaleToWidth: function(value) { + // adjust to bounding rect factor so that rotated shapes would fit as well + var boundingRectFactor = this.getBoundingRect().width / this.getWidth(); + return this.scale(value / this.width / boundingRectFactor); + }, + + /** + * Scales an object to a given height, with respect to bounding box (scaling by x/y equally) + * @param {Number} value New height value + * @return {fabric.Object} thisArg + * @chainable + */ + scaleToHeight: function(value) { + // adjust to bounding rect factor so that rotated shapes would fit as well + var boundingRectFactor = this.getBoundingRect().height / this.getHeight(); + return this.scale(value / this.height / boundingRectFactor); + }, + + /** + * Calculate and returns the .coords of an object. + * @return {Object} Object with tl, tr, br, bl .... + * @chainable + */ + calcCoords: function(absolute) { + var theta = degreesToRadians(this.angle), + vpt = this.getViewportTransform(), + dim = absolute ? this._getTransformedDimensions() : this._calculateCurrentDimensions(), + currentWidth = dim.x, currentHeight = dim.y, + sinTh = Math.sin(theta), + cosTh = Math.cos(theta), + _angle = currentWidth > 0 ? Math.atan(currentHeight / currentWidth) : 0, + _hypotenuse = (currentWidth / Math.cos(_angle)) / 2, + offsetX = Math.cos(_angle + theta) * _hypotenuse, + offsetY = Math.sin(_angle + theta) * _hypotenuse, + center = this.getCenterPoint(), + // offset added for rotate and scale actions + coords = absolute ? center : fabric.util.transformPoint(center, vpt), + tl = new fabric.Point(coords.x - offsetX, coords.y - offsetY), + 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); + if (!absolute) { + var 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 + + /* setTimeout(function() { + canvas.contextTop.fillStyle = 'green'; + canvas.contextTop.fillRect(mb.x, mb.y, 3, 3); + canvas.contextTop.fillRect(bl.x, bl.y, 3, 3); + canvas.contextTop.fillRect(br.x, br.y, 3, 3); + canvas.contextTop.fillRect(tl.x, tl.y, 3, 3); + canvas.contextTop.fillRect(tr.x, tr.y, 3, 3); + canvas.contextTop.fillRect(ml.x, ml.y, 3, 3); + canvas.contextTop.fillRect(mr.x, mr.y, 3, 3); + canvas.contextTop.fillRect(mt.x, mt.y, 3, 3); + canvas.contextTop.fillRect(mtr.x, mtr.y, 3, 3); + }, 50); */ + + var coords = { + // corners + tl: tl, tr: tr, br: br, bl: bl, + }; + if (!absolute) { + // middle + coords.ml = ml; + coords.mt = mt; + coords.mr = mr; + coords.mb = mb; + // rotating point + coords.mtr = mtr; + } + return coords; + }, + + /** + * Sets corner position coordinates based on current angle, width and height + * See https://github.com/kangax/fabric.js/wiki/When-to-call-setCoords + * @param {Boolean} [ignoreZoom] set oCoords with or without the viewport transform. + * @param {Boolean} [skipAbsolute] skip calculation of aCoords, usefull in setViewportTransform + * @return {fabric.Object} thisArg + * @chainable + */ + setCoords: function(ignoreZoom, skipAbsolute) { + this.oCoords = this.calcCoords(ignoreZoom); + if (!skipAbsolute) { + this.aCoords = this.calcCoords(true); + } + + // set coordinates of the draggable boxes in the corners used to scale/rotate the image + ignoreZoom || (this._setCornerCoords && this._setCornerCoords()); + + 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); + // trying to keep rounding error small, ugly but it works. + if (cos === 6.123233995736766e-17 || cos === -1.8369701987210297e-16) { + cos = 0; + } + return [cos, sin, -sin, cos, 0, 0]; + } + return fabric.iMatrix.concat(); + }, + + /** + * calculate trasform Matrix that represent current transformation from + * object properties. + * @param {Boolean} [skipGroup] return transformMatrix for object and not go upward with parents + * @return {Array} matrix Transform Matrix for the object + */ + calcTransformMatrix: function(skipGroup) { + var center = this.getCenterPoint(), + translateMatrix = [1, 0, 0, 1, center.x, center.y], + rotateMatrix, + dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true), + matrix; + if (this.group && !skipGroup) { + matrix = multiplyMatrices(this.group.calcTransformMatrix(), translateMatrix); + } + else { + matrix = translateMatrix; + } + if (this.angle) { + rotateMatrix = this._calcRotateMatrix(); + matrix = multiplyMatrices(matrix, rotateMatrix); + } + matrix = multiplyMatrices(matrix, dimensionMatrix); + return matrix; + }, + + _calcDimensionsTransformMatrix: function(skewX, skewY, flipping) { + var skewMatrix, + scaleX = this.scaleX * (flipping && this.flipX ? -1 : 1), + scaleY = this.scaleY * (flipping && this.flipY ? -1 : 1), + scaleMatrix = [scaleX, 0, 0, scaleY, 0, 0]; + if (skewX) { + skewMatrix = [1, 0, Math.tan(degreesToRadians(skewX)), 1]; + scaleMatrix = multiplyMatrices(scaleMatrix, skewMatrix, true); + } + if (skewY) { + skewMatrix = [1, Math.tan(degreesToRadians(skewY)), 0, 1]; + scaleMatrix = multiplyMatrices(scaleMatrix, skewMatrix, true); + } + return scaleMatrix; + }, + + /* + * Calculate object dimensions from its properties + * @private + * @return {Object} .x width dimension + * @return {Object} .y height dimension + */ + _getNonTransformedDimensions: function() { + var strokeWidth = this.strokeWidth, + w = this.width + strokeWidth, + h = this.height + strokeWidth; + return { x: w, y: h }; + }, + + /* + * Calculate object bounding boxdimensions from its properties scale, skew. + * @private + * @return {Object} .x width dimension + * @return {Object} .y height dimension + */ + _getTransformedDimensions: function(skewX, skewY) { + if (typeof skewX === 'undefined') { + skewX = this.skewX; + } + if (typeof skewY === 'undefined') { + skewY = this.skewY; + } + var dimensions = this._getNonTransformedDimensions(), + 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 + }], + i, transformMatrix = this._calcDimensionsTransformMatrix(skewX, skewY, false), + bbox; + for (i = 0; i < points.length; i++) { + points[i] = fabric.util.transformPoint(points[i], transformMatrix); + } + bbox = fabric.util.makeBoundingBoxFromPoints(points); + return { x: bbox.width, y: bbox.height }; + }, + + /* + * Calculate object dimensions for controls. include padding and canvas zoom + * private + */ + _calculateCurrentDimensions: function() { + var vpt = this.getViewportTransform(), + dim = this._getTransformedDimensions(), + p = fabric.util.transformPoint(dim, vpt, true); + + return p.scalarAdd(2 * this.padding); + }, + }); +})(); + + +fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + + /** + * Moves an object to the bottom of the stack of drawn objects + * @return {fabric.Object} thisArg + * @chainable + */ + sendToBack: function() { + if (this.group) { + fabric.StaticCanvas.prototype.sendToBack.call(this.group, this); + } + else { + this.canvas.sendToBack(this); + } + return this; + }, + + /** + * Moves an object to the top of the stack of drawn objects + * @return {fabric.Object} thisArg + * @chainable + */ + bringToFront: function() { + if (this.group) { + fabric.StaticCanvas.prototype.bringToFront.call(this.group, this); + } + else { + this.canvas.bringToFront(this); + } + return this; + }, + + /** + * Moves an object down in stack of drawn objects + * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object + * @return {fabric.Object} thisArg + * @chainable + */ + sendBackwards: function(intersecting) { + if (this.group) { + fabric.StaticCanvas.prototype.sendBackwards.call(this.group, this, intersecting); + } + else { + this.canvas.sendBackwards(this, intersecting); + } + return this; + }, + + /** + * Moves an object up in stack of drawn objects + * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object + * @return {fabric.Object} thisArg + * @chainable + */ + bringForward: function(intersecting) { + if (this.group) { + fabric.StaticCanvas.prototype.bringForward.call(this.group, this, intersecting); + } + else { + this.canvas.bringForward(this, intersecting); + } + return this; + }, + + /** + * Moves an object to specified level in stack of drawn objects + * @param {Number} index New position of object + * @return {fabric.Object} thisArg + * @chainable + */ + moveTo: function(index) { + if (this.group) { + fabric.StaticCanvas.prototype.moveTo.call(this.group, this, index); + } + else { + this.canvas.moveTo(this, index); + } + return this; + } +}); + + +/* _TO_SVG_START_ */ +(function() { + + function getSvgColorString(prop, value) { + if (!value) { + return prop + ': none; '; + } + else if (value.toLive) { + return prop + ': url(#SVGID_' + value.id + '); '; + } + else { + var color = new fabric.Color(value), + str = prop + ': ' + color.toRgb() + '; ', + opacity = color.getAlpha(); + if (opacity !== 1) { + //change the color in rgb + opacity + str += prop + '-opacity: ' + opacity.toString() + '; '; + } + return str; + } + } + + fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + /** + * Returns styles-string for svg-export + * @param {Boolean} skipShadow a boolean to skip shadow filter output + * @return {String} + */ + getSvgStyles: function(skipShadow) { + + var fillRule = this.fillRule, + strokeWidth = this.strokeWidth ? this.strokeWidth : '0', + strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none', + strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt', + strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter', + strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4', + opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1', + visibility = this.visible ? '' : ' visibility: hidden;', + filter = skipShadow ? '' : this.getSvgFilter(), + fill = getSvgColorString('fill', this.fill), + stroke = getSvgColorString('stroke', this.stroke); + + 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(''); + }, + + /** + * Returns filter for svg shadow + * @return {String} + */ + getSvgFilter: function() { + return this.shadow ? 'filter: url(#SVGID_' + this.shadow.id + ');' : ''; + }, + + /** + * Returns id attribute for svg output + * @return {String} + */ + getSvgId: function() { + return this.id ? 'id="' + this.id + '" ' : ''; + }, + + /** + * Returns transform-string for svg-export + * @return {String} + */ + getSvgTransform: function() { + if (this.group && this.group.type === 'path-group') { + return ''; + } + var toFixed = fabric.util.toFixed, + angle = this.getAngle(), + skewX = (this.getSkewX() % 360), + skewY = (this.getSkewY() % 360), + center = this.getCenterPoint(), + + NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS, + + translatePart = this.type === 'path-group' ? '' : 'translate(' + + toFixed(center.x, NUM_FRACTION_DIGITS) + + ' ' + + toFixed(center.y, NUM_FRACTION_DIGITS) + + ')', + + anglePart = angle !== 0 + ? (' rotate(' + toFixed(angle, NUM_FRACTION_DIGITS) + ')') + : '', + + scalePart = (this.scaleX === 1 && this.scaleY === 1) + ? '' : + (' scale(' + + toFixed(this.scaleX, NUM_FRACTION_DIGITS) + + ' ' + + toFixed(this.scaleY, NUM_FRACTION_DIGITS) + + ')'), + + skewXPart = skewX !== 0 ? ' skewX(' + toFixed(skewX, NUM_FRACTION_DIGITS) + ')' : '', + + skewYPart = skewY !== 0 ? ' skewY(' + toFixed(skewY, NUM_FRACTION_DIGITS) + ')' : '', + + addTranslateX = this.type === 'path-group' ? this.width : 0, + + flipXPart = this.flipX ? ' matrix(-1 0 0 1 ' + addTranslateX + ' 0) ' : '', + + addTranslateY = this.type === 'path-group' ? this.height : 0, + + flipYPart = this.flipY ? ' matrix(1 0 0 -1 0 ' + addTranslateY + ')' : ''; + + return [ + translatePart, anglePart, scalePart, flipXPart, flipYPart, skewXPart, skewYPart + ].join(''); + }, + + /** + * Returns transform-string for svg-export from the transform matrix of single elements + * @return {String} + */ + getSvgTransformMatrix: function() { + return this.transformMatrix ? ' matrix(' + this.transformMatrix.join(' ') + ') ' : ''; + }, + + /** + * @private + */ + _createBaseSVGMarkup: function() { + var markup = []; + + if (this.fill && this.fill.toLive) { + markup.push(this.fill.toSVG(this, false)); + } + if (this.stroke && this.stroke.toLive) { + markup.push(this.stroke.toSVG(this, false)); + } + if (this.shadow) { + markup.push(this.shadow.toSVG(this)); + } + return markup; + } + }); +})(); +/* _TO_SVG_END_ */ + + +(function() { + + var extend = fabric.util.object.extend, + originalSet = 'stateProperties'; + + /* + 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, firstPass) { + if (origValue === currentValue) { + // if the objects are identical, return + return true; + } + else if (Array.isArray(origValue)) { + if (origValue.length !== currentValue.length) { + return false; + } + for (var i = 0, len = origValue.length; i < len; i++) { + if (!_isEqual(origValue[i], currentValue[i])) { + return false; + } + } + return true; + } + else if (origValue && typeof origValue === 'object') { + var keys = Object.keys(origValue), key; + if (!firstPass && keys.length !== Object.keys(currentValue).length) { + return false; + } + for (var i = 0, len = keys.length; i < len; i++) { + key = keys[i]; + if (!_isEqual(origValue[key], currentValue[key])) { + return false; + } + } + return true; + } + } + + + fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + + /** + * Returns true if object state (one of its state properties) was changed + * @param {String} [propertySet] optional name for the set of property we want to save + * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called + */ + hasStateChanged: function(propertySet) { + propertySet = propertySet || originalSet; + var dashedPropertySet = '_' + propertySet; + if (Object.keys(this[dashedPropertySet]).length < this[propertySet].length) { + return true; + } + return !_isEqual(this[dashedPropertySet], this, true); + }, + + /** + * 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) { + var propertySet = options && options.propertySet || originalSet, + destination = '_' + propertySet; + if (!this[destination]) { + return this.setupState(options); + } + saveProps(this, destination, this[propertySet]); + if (options && options.stateProperties) { + saveProps(this, destination, 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) { + options = options || { }; + var propertySet = options.propertySet || originalSet; + options.propertySet = propertySet; + this['_' + propertySet] = { }; + this.saveState(options); + return this; + } + }); +})(); + + +(function() { + + var degreesToRadians = fabric.util.degreesToRadians, + /* eslint-disable camelcase */ + isVML = function() { return typeof G_vmlCanvasManager !== 'undefined'; }; + /* eslint-enable camelcase */ + fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + + /** + * The object interactivity controls. + * @private + */ + _controlsVisibility: null, + + /** + * Determines which corner has been clicked + * @private + * @param {Object} pointer The pointer indicating the mouse position + * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found + */ + _findTargetCorner: function(pointer) { + if (!this.hasControls || !this.active) { + return false; + } + + var ex = pointer.x, + ey = pointer.y, + xPoints, + lines; + this.__corner = 0; + for (var i in this.oCoords) { + + if (!this.isControlVisible(i)) { + continue; + } + + if (i === 'mtr' && !this.hasRotatingPoint) { + continue; + } + + if (this.get('lockUniScaling') && + (i === 'mt' || i === 'mr' || i === 'mb' || i === 'ml')) { + continue; + } + + lines = this._getImageLines(this.oCoords[i].corner); + + // debugging + + // canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2); + // canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2); + + // canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2); + // canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2); + + // canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2); + // canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2); + + // canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2); + // canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2); + + xPoints = this._findCrossPoints({ x: ex, y: ey }, lines); + if (xPoints !== 0 && xPoints % 2 === 1) { + this.__corner = i; + return i; + } + } + return false; + }, + + /** + * Sets the coordinates of the draggable boxes in the corners of + * the image used to scale/rotate it. + * @private + */ + _setCornerCoords: function() { + var coords = this.oCoords, + newTheta = degreesToRadians(45 - this.angle), + /* Math.sqrt(2 * Math.pow(this.cornerSize, 2)) / 2, */ + /* 0.707106 stands for sqrt(2)/2 */ + cornerHypotenuse = this.cornerSize * 0.707106, + cosHalfOffset = cornerHypotenuse * Math.cos(newTheta), + sinHalfOffset = cornerHypotenuse * Math.sin(newTheta), + x, y; + + for (var point in coords) { + x = coords[point].x; + y = coords[point].y; + coords[point].corner = { + tl: { + x: x - sinHalfOffset, + y: y - cosHalfOffset + }, + tr: { + x: x + cosHalfOffset, + y: y - sinHalfOffset + }, + bl: { + x: x - cosHalfOffset, + y: y + sinHalfOffset + }, + br: { + x: x + sinHalfOffset, + y: y + cosHalfOffset + } + }; + } + }, + + /** + * Draws a colored layer behind the object, inside its selection borders. + * Requires public options: padding, selectionBackgroundColor + * this function is called when the context is transformed + * has checks to be skipped when the object is on a staticCanvas + * @param {CanvasRenderingContext2D} ctx Context to draw on + * @return {fabric.Object} thisArg + * @chainable + */ + drawSelectionBackground: function(ctx) { + if (!this.selectionBackgroundColor || this.group || !this.active || + (this.canvas && !this.canvas.interactive)) { + return this; + } + ctx.save(); + var center = this.getCenterPoint(), wh = this._calculateCurrentDimensions(), + vpt = this.canvas.viewportTransform; + ctx.translate(center.x, center.y); + 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.restore(); + return this; + }, + + /** + * Draws borders of an object's bounding box. + * Requires public properties: width, height + * Requires public options: padding, borderColor + * @param {CanvasRenderingContext2D} ctx Context to draw on + * @return {fabric.Object} thisArg + * @chainable + */ + drawBorders: function(ctx) { + if (!this.hasBorders) { + return this; + } + + var wh = this._calculateCurrentDimensions(), + strokeWidth = 1 / this.borderScaleFactor, + width = wh.x + strokeWidth, + height = wh.y + strokeWidth; + + ctx.save(); + ctx.strokeStyle = this.borderColor; + this._setLineDash(ctx, this.borderDashArray, null); + + ctx.strokeRect( + -width / 2, + -height / 2, + width, + height + ); + + if (this.hasRotatingPoint && this.isControlVisible('mtr') && !this.get('lockRotation') && this.hasControls) { + + var rotateHeight = -height / 2; + + ctx.beginPath(); + ctx.moveTo(0, rotateHeight); + ctx.lineTo(0, rotateHeight - this.rotatingPointOffset); + ctx.closePath(); + ctx.stroke(); + } + + ctx.restore(); + return this; + }, + + /** + * Draws borders of an object's bounding box when it is inside a group. + * Requires public properties: width, height + * Requires public options: padding, borderColor + * @param {CanvasRenderingContext2D} ctx Context to draw on + * @param {object} options object representing current object parameters + * @return {fabric.Object} thisArg + * @chainable + */ + drawBordersInGroup: function(ctx, options) { + if (!this.hasBorders) { + return this; + } + + var p = this._getNonTransformedDimensions(), + matrix = fabric.util.customTransformMatrix(options.scaleX, options.scaleY, options.skewX), + wh = fabric.util.transformPoint(p, matrix), + strokeWidth = 1 / this.borderScaleFactor, + width = wh.x + strokeWidth, + height = wh.y + strokeWidth; + + ctx.save(); + this._setLineDash(ctx, this.borderDashArray, null); + ctx.strokeStyle = this.borderColor; + + ctx.strokeRect( + -width / 2, + -height / 2, + width, + height + ); + + ctx.restore(); + return this; + }, + + /** + * Draws corners of an object's bounding box. + * Requires public properties: width, height + * Requires public options: cornerSize, padding + * @param {CanvasRenderingContext2D} ctx Context to draw on + * @return {fabric.Object} thisArg + * @chainable + */ + drawControls: function(ctx) { + if (!this.hasControls) { + return this; + } + + var wh = this._calculateCurrentDimensions(), + width = wh.x, + height = wh.y, + scaleOffset = this.cornerSize, + left = -(width + scaleOffset) / 2, + top = -(height + scaleOffset) / 2, + methodName = this.transparentCorners ? 'stroke' : 'fill'; + + ctx.save(); + ctx.strokeStyle = ctx.fillStyle = this.cornerColor; + if (!this.transparentCorners) { + ctx.strokeStyle = this.cornerStrokeColor; + } + this._setLineDash(ctx, this.cornerDashArray, null); + + // top-left + this._drawControl('tl', ctx, methodName, + left, + top); + + // top-right + this._drawControl('tr', ctx, methodName, + left + width, + top); + + // bottom-left + this._drawControl('bl', ctx, methodName, + left, + top + height); + + // bottom-right + this._drawControl('br', ctx, methodName, + left + width, + top + height); + + if (!this.get('lockUniScaling')) { + + // middle-top + this._drawControl('mt', ctx, methodName, + left + width / 2, + top); + + // middle-bottom + this._drawControl('mb', ctx, methodName, + left + width / 2, + top + height); + + // middle-right + this._drawControl('mr', ctx, methodName, + left + width, + top + height / 2); + + // middle-left + this._drawControl('ml', ctx, methodName, + left, + top + height / 2); + } + + // middle-top-rotate + if (this.hasRotatingPoint) { + this._drawControl('mtr', ctx, methodName, + left + width / 2, + top - this.rotatingPointOffset); + } + + ctx.restore(); + + return this; + }, + + /** + * @private + */ + _drawControl: function(control, ctx, methodName, left, top) { + if (!this.isControlVisible(control)) { + return; + } + var size = this.cornerSize, stroke = !this.transparentCorners && this.cornerStrokeColor; + switch (this.cornerStyle) { + case 'circle': + ctx.beginPath(); + ctx.arc(left + size / 2, top + size / 2, size / 2, 0, 2 * Math.PI, false); + ctx[methodName](); + if (stroke) { + ctx.stroke(); + } + break; + default: + isVML() || this.transparentCorners || ctx.clearRect(left, top, size, size); + ctx[methodName + 'Rect'](left, top, size, size); + if (stroke) { + ctx.strokeRect(left, top, size, size); + } + } + }, + + /** + * Returns true if the specified control is visible, false otherwise. + * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'. + * @returns {Boolean} true if the specified control is visible, false otherwise + */ + isControlVisible: function(controlName) { + return this._getControlsVisibility()[controlName]; + }, + + /** + * Sets the visibility of the specified control. + * @param {String} controlName The name of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'. + * @param {Boolean} visible true to set the specified control visible, false otherwise + * @return {fabric.Object} thisArg + * @chainable + */ + setControlVisible: function(controlName, visible) { + this._getControlsVisibility()[controlName] = visible; + return this; + }, + + /** + * Sets the visibility state of object controls. + * @param {Object} [options] Options object + * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it + * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it + * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it + * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it + * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it + * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it + * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it + * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it + * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it + * @return {fabric.Object} thisArg + * @chainable + */ + setControlsVisibility: function(options) { + options || (options = { }); + + for (var p in options) { + this.setControlVisible(p, options[p]); + } + return this; + }, + + /** + * Returns the instance of the control visibility set for this object. + * @private + * @returns {Object} + */ + _getControlsVisibility: function() { + if (!this._controlsVisibility) { + this._controlsVisibility = { + tl: true, + tr: true, + br: true, + bl: true, + ml: true, + mt: true, + mr: true, + mb: true, + mtr: true + }; + } + return this._controlsVisibility; + } + }); +})(); + + +fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { + + /** + * Animation duration (in ms) for fx* methods + * @type Number + * @default + */ + FX_DURATION: 500, + + /** + * Centers object horizontally with animation. + * @param {fabric.Object} object Object to center + * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties + * @param {Function} [callbacks.onComplete] Invoked on completion + * @param {Function} [callbacks.onChange] Invoked on every step of animation + * @return {fabric.Canvas} thisArg + * @chainable + */ + fxCenterObjectH: function (object, callbacks) { + callbacks = callbacks || { }; + + var empty = function() { }, + onComplete = callbacks.onComplete || empty, + onChange = callbacks.onChange || empty, + _this = this; + + fabric.util.animate({ + startValue: object.get('left'), + endValue: this.getCenter().left, + duration: this.FX_DURATION, + onChange: function(value) { + object.set('left', value); + _this.renderAll(); + onChange(); + }, + onComplete: function() { + object.setCoords(); + onComplete(); + } + }); + + return this; + }, + + /** + * Centers object vertically with animation. + * @param {fabric.Object} object Object to center + * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties + * @param {Function} [callbacks.onComplete] Invoked on completion + * @param {Function} [callbacks.onChange] Invoked on every step of animation + * @return {fabric.Canvas} thisArg + * @chainable + */ + fxCenterObjectV: function (object, callbacks) { + callbacks = callbacks || { }; + + var empty = function() { }, + onComplete = callbacks.onComplete || empty, + onChange = callbacks.onChange || empty, + _this = this; + + fabric.util.animate({ + startValue: object.get('top'), + endValue: this.getCenter().top, + duration: this.FX_DURATION, + onChange: function(value) { + object.set('top', value); + _this.renderAll(); + onChange(); + }, + onComplete: function() { + object.setCoords(); + onComplete(); + } + }); + + return this; + }, + + /** + * Same as `fabric.Canvas#remove` but animated + * @param {fabric.Object} object Object to remove + * @param {Object} [callbacks] Callbacks object with optional "onComplete" and/or "onChange" properties + * @param {Function} [callbacks.onComplete] Invoked on completion + * @param {Function} [callbacks.onChange] Invoked on every step of animation + * @return {fabric.Canvas} thisArg + * @chainable + */ + fxRemove: function (object, callbacks) { + callbacks = callbacks || { }; + + var empty = function() { }, + onComplete = callbacks.onComplete || empty, + onChange = callbacks.onChange || empty, + _this = this; + + fabric.util.animate({ + startValue: object.get('opacity'), + endValue: 0, + duration: this.FX_DURATION, + onStart: function() { + object.set('active', false); + }, + onChange: function(value) { + object.set('opacity', value); + _this.renderAll(); + onChange(); + }, + onComplete: function () { + _this.remove(object); + onComplete(); + } + }); + + return this; + } +}); + +fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + /** + * Animates object's properties + * @param {String|Object} property Property to animate (if string) or properties to animate (if object) + * @param {Number|Object} value Value to animate property to (if string was given first) or options object + * @return {fabric.Object} thisArg + * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation} + * @chainable + * + * As object — multiple properties + * + * object.animate({ left: ..., top: ... }); + * object.animate({ left: ..., top: ... }, { duration: ... }); + * + * As string — one property + * + * object.animate('left', ...); + * object.animate('left', { duration: ... }); + * + */ + animate: function() { + if (arguments[0] && typeof arguments[0] === 'object') { + var propsToAnimate = [], prop, skipCallbacks; + for (prop in arguments[0]) { + propsToAnimate.push(prop); + } + for (var i = 0, len = propsToAnimate.length; i < len; i++) { + prop = propsToAnimate[i]; + skipCallbacks = i !== len - 1; + this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks); + } + } + else { + this._animate.apply(this, arguments); + } + return this; + }, + + /** + * @private + * @param {String} property Property to animate + * @param {String} to Value to animate to + * @param {Object} [options] Options object + * @param {Boolean} [skipCallbacks] When true, callbacks like onchange and oncomplete are not invoked + */ + _animate: function(property, to, options, skipCallbacks) { + var _this = this, propPair; + + to = to.toString(); + + if (!options) { + options = { }; + } + else { + options = fabric.util.object.clone(options); + } + + if (~property.indexOf('.')) { + propPair = property.split('.'); + } + + var currentValue = propPair + ? this.get(propPair[0])[propPair[1]] + : this.get(property); + + if (!('from' in options)) { + options.from = currentValue; + } + + if (~to.indexOf('=')) { + to = currentValue + parseFloat(to.replace('=', '')); + } + else { + to = parseFloat(to); + } + + fabric.util.animate({ + startValue: options.from, + endValue: to, + byValue: options.by, + easing: options.easing, + duration: options.duration, + abort: options.abort && function() { + return options.abort.call(_this); + }, + onChange: function(value, valueProgress, timeProgress) { + if (propPair) { + _this[propPair[0]][propPair[1]] = value; + } + else { + _this.set(property, value); + } + if (skipCallbacks) { + return; + } + options.onChange && options.onChange(value, valueProgress, timeProgress); + }, + onComplete: function(value, valueProgress, timeProgress) { + if (skipCallbacks) { + return; + } + + _this.setCoords(); + options.onComplete && options.onComplete(value, valueProgress, timeProgress); + } + }); + } +}); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + clone = fabric.util.object.clone, + coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 }, + supportsLineDash = fabric.StaticCanvas.supports('setLineDash'); + + if (fabric.Line) { + fabric.warn('fabric.Line is already defined'); + return; + } + + /** + * Line class + * @class fabric.Line + * @extends fabric.Object + * @see {@link fabric.Line#initialize} for constructor definition + */ + fabric.Line = fabric.util.createClass(fabric.Object, /** @lends fabric.Line.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'line', + + /** + * x value or first line edge + * @type Number + * @default + */ + x1: 0, + + /** + * y value or first line edge + * @type Number + * @default + */ + y1: 0, + + /** + * x value or second line edge + * @type Number + * @default + */ + x2: 0, + + /** + * y value or second line edge + * @type Number + * @default + */ + y2: 0, + + cacheProperties: fabric.Object.prototype.cacheProperties.concat('x1', 'x2', 'y1', 'y2'), + + /** + * Constructor + * @param {Array} [points] Array of points + * @param {Object} [options] Options object + * @return {fabric.Line} thisArg + */ + initialize: function(points, options) { + if (!points) { + points = [0, 0, 0, 0]; + } + + this.callSuper('initialize', options); + + this.set('x1', points[0]); + this.set('y1', points[1]); + this.set('x2', points[2]); + this.set('y2', points[3]); + + this._setWidthHeight(options); + }, + + /** + * @private + * @param {Object} [options] Options + */ + _setWidthHeight: function(options) { + options || (options = { }); + + this.width = Math.abs(this.x2 - this.x1); + this.height = Math.abs(this.y2 - this.y1); + + this.left = 'left' in options + ? options.left + : this._getLeftToOriginX(); + + this.top = 'top' in options + ? options.top + : this._getTopToOriginY(); + }, + + /** + * @private + * @param {String} key + * @param {*} value + */ + _set: function(key, value) { + this.callSuper('_set', key, value); + if (typeof coordProps[key] !== 'undefined') { + this._setWidthHeight(); + } + return this; + }, + + /** + * @private + * @return {Number} leftToOriginX Distance from left edge of canvas to originX of Line. + */ + _getLeftToOriginX: makeEdgeToOriginGetter( + { // property names + origin: 'originX', + axis1: 'x1', + axis2: 'x2', + dimension: 'width' + }, + { // possible values of origin + nearest: 'left', + center: 'center', + farthest: 'right' + } + ), + + /** + * @private + * @return {Number} topToOriginY Distance from top edge of canvas to originY of Line. + */ + _getTopToOriginY: makeEdgeToOriginGetter( + { // property names + origin: 'originY', + axis1: 'y1', + axis2: 'y2', + dimension: 'height' + }, + { // possible values of origin + nearest: 'top', + center: 'center', + farthest: 'bottom' + } + ), + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + _render: function(ctx, noTransform) { + ctx.beginPath(); + + if (noTransform) { + // Line coords are distances from left-top of canvas to origin of line. + // To render line in a path-group, we need to translate them to + // distances from center of path-group to center of line. + var cp = this.getCenterPoint(), + offset = this.strokeWidth / 2; + ctx.translate( + cp.x - (this.strokeLineCap === 'butt' && this.height === 0 ? 0 : offset), + cp.y - (this.strokeLineCap === 'butt' && this.width === 0 ? 0 : offset) + ); + } + + if (!this.strokeDashArray || this.strokeDashArray && supportsLineDash) { + // move from center (of virtual box) to its left/top corner + // we can't assume x1, y1 is top left and x2, y2 is bottom right + var p = this.calcLinePoints(); + ctx.moveTo(p.x1, p.y1); + ctx.lineTo(p.x2, p.y2); + } + + ctx.lineWidth = this.strokeWidth; + + // TODO: test this + // make sure setting "fill" changes color of a line + // (by copying fillStyle to strokeStyle, since line is stroked, not filled) + var origStrokeStyle = ctx.strokeStyle; + ctx.strokeStyle = this.stroke || ctx.fillStyle; + this.stroke && this._renderStroke(ctx); + ctx.strokeStyle = origStrokeStyle; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderDashedStroke: function(ctx) { + var p = this.calcLinePoints(); + + ctx.beginPath(); + fabric.util.drawDashedLine(ctx, p.x1, p.y1, p.x2, p.y2, this.strokeDashArray); + ctx.closePath(); + }, + + /** + * Returns object representation of an instance + * @methd toObject + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + return extend(this.callSuper('toObject', propertiesToInclude), this.calcLinePoints()); + }, + + /* + * Calculate object dimensions from its properties + * @private + */ + _getNonTransformedDimensions: function() { + var dim = this.callSuper('_getNonTransformedDimensions'); + if (this.strokeLineCap === 'butt') { + if (this.width === 0) { + dim.y -= this.strokeWidth; + } + if (this.height === 0) { + dim.x -= this.strokeWidth; + } + } + return dim; + }, + + /** + * Recalculates line points given width and height + * @private + */ + calcLinePoints: function() { + var xMult = this.x1 <= this.x2 ? -1 : 1, + yMult = this.y1 <= this.y2 ? -1 : 1, + x1 = (xMult * this.width * 0.5), + y1 = (yMult * this.height * 0.5), + x2 = (xMult * this.width * -0.5), + y2 = (yMult * this.height * -0.5); + + return { + x1: x1, + x2: x2, + y1: y1, + y2: y2 + }; + }, + + /* _TO_SVG_START_ */ + /** + * Returns SVG representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var markup = this._createBaseSVGMarkup(), + p = { x1: this.x1, x2: this.x2, y1: this.y1, y2: this.y2 }; + + if (!(this.group && this.group.type === 'path-group')) { + p = this.calcLinePoints(); + } + markup.push( + '\n' + ); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + }); + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by {@link fabric.Line.fromElement}) + * @static + * @memberOf fabric.Line + * @see http://www.w3.org/TR/SVG/shapes.html#LineElement + */ + fabric.Line.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' ')); + + /** + * Returns fabric.Line instance from an SVG element + * @static + * @memberOf fabric.Line + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Line} instance of fabric.Line + */ + fabric.Line.fromElement = function(element, options) { + options = options || { }; + var parsedAttributes = fabric.parseAttributes(element, fabric.Line.ATTRIBUTE_NAMES), + points = [ + parsedAttributes.x1 || 0, + parsedAttributes.y1 || 0, + parsedAttributes.x2 || 0, + parsedAttributes.y2 || 0 + ]; + options.originX = 'left'; + options.originY = 'top'; + return new fabric.Line(points, extend(parsedAttributes, options)); + }; + /* _FROM_SVG_END_ */ + + /** + * Returns fabric.Line instance from an object representation + * @static + * @memberOf fabric.Line + * @param {Object} object Object to create an instance from + * @param {function} [callback] invoked with new instance as first argument + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.Line} instance of fabric.Line + */ + fabric.Line.fromObject = function(object, callback, forceAsync) { + function _callback(instance) { + delete instance.points; + callback && callback(instance); + }; + var options = clone(object, true); + options.points = [object.x1, object.y1, object.x2, object.y2]; + var line = fabric.Object._fromObject('Line', options, _callback, forceAsync, 'points'); + if (line) { + delete line.points; + } + return line; + }; + + /** + * Produces a function that calculates distance from canvas edge to Line origin. + */ + 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; + + 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)); + } + }; + + } + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + pi = Math.PI, + extend = fabric.util.object.extend; + + if (fabric.Circle) { + fabric.warn('fabric.Circle is already defined.'); + return; + } + + /** + * Circle class + * @class fabric.Circle + * @extends fabric.Object + * @see {@link fabric.Circle#initialize} for constructor definition + */ + fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'circle', + + /** + * Radius of this circle + * @type Number + * @default + */ + radius: 0, + + /** + * Start angle of the circle, moving clockwise + * @type Number + * @default 0 + */ + startAngle: 0, + + /** + * End angle of the circle + * @type Number + * @default 2Pi + */ + endAngle: pi * 2, + + cacheProperties: fabric.Object.prototype.cacheProperties.concat('radius'), + + /** + * Constructor + * @param {Object} [options] Options object + * @return {fabric.Circle} thisArg + */ + initialize: function(options) { + this.callSuper('initialize', options); + this.set('radius', options && options.radius || 0); + }, + + /** + * @private + * @param {String} key + * @param {*} value + * @return {fabric.Circle} thisArg + */ + _set: function(key, value) { + this.callSuper('_set', key, value); + + if (key === 'radius') { + this.setRadius(value); + } + + return this; + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + return this.callSuper('toObject', ['radius', 'startAngle', 'endAngle'].concat(propertiesToInclude)); + }, + + /* _TO_SVG_START_ */ + /** + * Returns svg representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var markup = this._createBaseSVGMarkup(), x = 0, y = 0, + angle = (this.endAngle - this.startAngle) % ( 2 * pi); + + if (angle === 0) { + if (this.group && this.group.type === 'path-group') { + x = this.left + this.radius; + y = this.top + this.radius; + } + markup.push( + '\n' + ); + } + else { + var startX = Math.cos(this.startAngle) * this.radius, + startY = Math.sin(this.startAngle) * this.radius, + endX = Math.cos(this.endAngle) * this.radius, + endY = Math.sin(this.endAngle) * this.radius, + largeFlag = angle > pi ? '1' : '0'; + + markup.push( + '\n' + ); + } + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + + /** + * @private + * @param {CanvasRenderingContext2D} ctx context to render on + * @param {Boolean} [noTransform] When true, context is not transformed + */ + _render: function(ctx, noTransform) { + ctx.beginPath(); + ctx.arc(noTransform ? this.left + this.radius : 0, + noTransform ? this.top + this.radius : 0, + this.radius, + this.startAngle, + this.endAngle, false); + this._renderFill(ctx); + this._renderStroke(ctx); + }, + + /** + * Returns horizontal radius of an object (according to how an object is scaled) + * @return {Number} + */ + getRadiusX: function() { + return this.get('radius') * this.get('scaleX'); + }, + + /** + * Returns vertical radius of an object (according to how an object is scaled) + * @return {Number} + */ + getRadiusY: function() { + return this.get('radius') * this.get('scaleY'); + }, + + /** + * Sets radius of an object (and updates width accordingly) + * @return {fabric.Circle} thisArg + */ + setRadius: function(value) { + this.radius = value; + return this.set('width', value * 2).set('height', value * 2); + }, + }); + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement}) + * @static + * @memberOf fabric.Circle + * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement + */ + fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' ')); + + /** + * Returns {@link fabric.Circle} instance from an SVG element + * @static + * @memberOf fabric.Circle + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @throws {Error} If value of `r` attribute is missing or invalid + * @return {fabric.Circle} Instance of fabric.Circle + */ + fabric.Circle.fromElement = function(element, options) { + options || (options = { }); + + var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES); + + if (!isValidRadius(parsedAttributes)) { + throw new Error('value of `r` attribute is required and can not be negative'); + } + + parsedAttributes.left = parsedAttributes.left || 0; + parsedAttributes.top = parsedAttributes.top || 0; + + var obj = new fabric.Circle(extend(parsedAttributes, options)); + + obj.left -= obj.radius; + obj.top -= obj.radius; + return obj; + }; + + /** + * @private + */ + function isValidRadius(attributes) { + return (('radius' in attributes) && (attributes.radius >= 0)); + } + /* _FROM_SVG_END_ */ + + /** + * Returns {@link fabric.Circle} instance from an object representation + * @static + * @memberOf fabric.Circle + * @param {Object} object Object to create an instance from + * @param {function} [callback] invoked with new instance as first argument + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {Object} Instance of fabric.Circle + */ + fabric.Circle.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Circle', object, callback, forceAsync); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }); + + if (fabric.Triangle) { + fabric.warn('fabric.Triangle is already defined'); + return; + } + + /** + * Triangle class + * @class fabric.Triangle + * @extends fabric.Object + * @return {fabric.Triangle} thisArg + * @see {@link fabric.Triangle#initialize} for constructor definition + */ + fabric.Triangle = fabric.util.createClass(fabric.Object, /** @lends fabric.Triangle.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'triangle', + + /** + * Constructor + * @param {Object} [options] Options object + * @return {Object} thisArg + */ + initialize: function(options) { + this.callSuper('initialize', options); + this.set('width', options && options.width || 100) + .set('height', options && options.height || 100); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _render: function(ctx) { + var widthBy2 = this.width / 2, + heightBy2 = this.height / 2; + + ctx.beginPath(); + ctx.moveTo(-widthBy2, heightBy2); + ctx.lineTo(0, -heightBy2); + ctx.lineTo(widthBy2, heightBy2); + ctx.closePath(); + + this._renderFill(ctx); + this._renderStroke(ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderDashedStroke: function(ctx) { + var widthBy2 = this.width / 2, + heightBy2 = this.height / 2; + + ctx.beginPath(); + fabric.util.drawDashedLine(ctx, -widthBy2, heightBy2, 0, -heightBy2, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, 0, -heightBy2, widthBy2, heightBy2, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, widthBy2, heightBy2, -widthBy2, heightBy2, this.strokeDashArray); + ctx.closePath(); + }, + + /* _TO_SVG_START_ */ + /** + * Returns SVG representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var markup = this._createBaseSVGMarkup(), + widthBy2 = this.width / 2, + heightBy2 = this.height / 2, + points = [ + -widthBy2 + ' ' + heightBy2, + '0 ' + -heightBy2, + widthBy2 + ' ' + heightBy2 + ] + .join(','); + + markup.push( + '' + ); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + }); + + /** + * Returns {@link fabric.Triangle} instance from an object representation + * @static + * @memberOf fabric.Triangle + * @param {Object} object Object to create an instance from + * @param {function} [callback] invoked with new instance as first argument + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.Triangle} + */ + fabric.Triangle.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Triangle', object, callback, forceAsync); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + piBy2 = Math.PI * 2, + extend = fabric.util.object.extend; + + if (fabric.Ellipse) { + fabric.warn('fabric.Ellipse is already defined.'); + return; + } + + /** + * Ellipse class + * @class fabric.Ellipse + * @extends fabric.Object + * @return {fabric.Ellipse} thisArg + * @see {@link fabric.Ellipse#initialize} for constructor definition + */ + fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @lends fabric.Ellipse.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'ellipse', + + /** + * Horizontal radius + * @type Number + * @default + */ + rx: 0, + + /** + * Vertical radius + * @type Number + * @default + */ + ry: 0, + + cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'), + + /** + * Constructor + * @param {Object} [options] Options object + * @return {fabric.Ellipse} thisArg + */ + initialize: function(options) { + this.callSuper('initialize', options); + this.set('rx', options && options.rx || 0); + this.set('ry', options && options.ry || 0); + }, + + /** + * @private + * @param {String} key + * @param {*} value + * @return {fabric.Ellipse} thisArg + */ + _set: function(key, value) { + this.callSuper('_set', key, value); + switch (key) { + + case 'rx': + this.rx = value; + this.set('width', value * 2); + break; + + case 'ry': + this.ry = value; + this.set('height', value * 2); + break; + + } + return this; + }, + + /** + * Returns horizontal radius of an object (according to how an object is scaled) + * @return {Number} + */ + getRx: function() { + return this.get('rx') * this.get('scaleX'); + }, + + /** + * Returns Vertical radius of an object (according to how an object is scaled) + * @return {Number} + */ + getRy: function() { + return this.get('ry') * this.get('scaleY'); + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude)); + }, + + /* _TO_SVG_START_ */ + /** + * Returns svg representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var markup = this._createBaseSVGMarkup(), x = 0, y = 0; + if (this.group && this.group.type === 'path-group') { + x = this.left + this.rx; + y = this.top + this.ry; + } + markup.push( + '\n' + ); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + + /** + * @private + * @param {CanvasRenderingContext2D} ctx context to render on + * @param {Boolean} [noTransform] When true, context is not transformed + */ + _render: function(ctx, noTransform) { + ctx.beginPath(); + ctx.save(); + ctx.transform(1, 0, 0, this.ry / this.rx, 0, 0); + ctx.arc( + noTransform ? this.left + this.rx : 0, + noTransform ? (this.top + this.ry) * this.rx / this.ry : 0, + this.rx, + 0, + piBy2, + false); + ctx.restore(); + this._renderFill(ctx); + this._renderStroke(ctx); + }, + }); + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by {@link fabric.Ellipse.fromElement}) + * @static + * @memberOf fabric.Ellipse + * @see http://www.w3.org/TR/SVG/shapes.html#EllipseElement + */ + fabric.Ellipse.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy rx ry'.split(' ')); + + /** + * Returns {@link fabric.Ellipse} instance from an SVG element + * @static + * @memberOf fabric.Ellipse + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Ellipse} + */ + fabric.Ellipse.fromElement = function(element, options) { + options || (options = { }); + + var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES); + + parsedAttributes.left = parsedAttributes.left || 0; + parsedAttributes.top = parsedAttributes.top || 0; + + var ellipse = new fabric.Ellipse(extend(parsedAttributes, options)); + + ellipse.top -= ellipse.ry; + ellipse.left -= ellipse.rx; + return ellipse; + }; + /* _FROM_SVG_END_ */ + + /** + * Returns {@link fabric.Ellipse} instance from an object representation + * @static + * @memberOf fabric.Ellipse + * @param {Object} object Object to create an instance from + * @param {function} [callback] invoked with new instance as first argument + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.Ellipse} + */ + fabric.Ellipse.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Ellipse', object, callback, forceAsync); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend; + + if (fabric.Rect) { + fabric.warn('fabric.Rect is already defined'); + return; + } + + /** + * Rectangle class + * @class fabric.Rect + * @extends fabric.Object + * @return {fabric.Rect} thisArg + * @see {@link fabric.Rect#initialize} for constructor definition + */ + fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ { + + /** + * 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: fabric.Object.prototype.stateProperties.concat('rx', 'ry'), + + /** + * Type of an object + * @type String + * @default + */ + type: 'rect', + + /** + * Horizontal border radius + * @type Number + * @default + */ + rx: 0, + + /** + * Vertical border radius + * @type Number + * @default + */ + ry: 0, + + cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'), + + /** + * Constructor + * @param {Object} [options] Options object + * @return {Object} thisArg + */ + initialize: function(options) { + this.callSuper('initialize', options); + this._initRxRy(); + }, + + /** + * Initializes rx/ry attributes + * @private + */ + _initRxRy: function() { + if (this.rx && !this.ry) { + this.ry = this.rx; + } + else if (this.ry && !this.rx) { + this.rx = this.ry; + } + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + _render: function(ctx, noTransform) { + + // optimize 1x1 case (used in spray brush) + if (this.width === 1 && this.height === 1) { + ctx.fillRect(-0.5, -0.5, 1, 1); + return; + } + + var rx = this.rx ? Math.min(this.rx, this.width / 2) : 0, + ry = this.ry ? Math.min(this.ry, this.height / 2) : 0, + w = this.width, + h = this.height, + x = noTransform ? this.left : -this.width / 2, + y = noTransform ? this.top : -this.height / 2, + isRounded = rx !== 0 || ry !== 0, + /* "magic number" for bezier approximations of arcs (http://itc.ktu.lt/itc354/Riskus354.pdf) */ + k = 1 - 0.5522847498; + ctx.beginPath(); + + ctx.moveTo(x + rx, y); + + ctx.lineTo(x + w - rx, y); + isRounded && ctx.bezierCurveTo(x + w - k * rx, y, x + w, y + k * ry, x + w, y + ry); + + ctx.lineTo(x + w, y + h - ry); + isRounded && ctx.bezierCurveTo(x + w, y + h - k * ry, x + w - k * rx, y + h, x + w - rx, y + h); + + ctx.lineTo(x + rx, y + h); + isRounded && ctx.bezierCurveTo(x + k * rx, y + h, x, y + h - k * ry, x, y + h - ry); + + ctx.lineTo(x, y + ry); + isRounded && ctx.bezierCurveTo(x, y + k * ry, x + k * rx, y, x + rx, y); + + ctx.closePath(); + + this._renderFill(ctx); + this._renderStroke(ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderDashedStroke: function(ctx) { + var x = -this.width / 2, + y = -this.height / 2, + w = this.width, + h = this.height; + + ctx.beginPath(); + fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray); + ctx.closePath(); + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude)); + }, + + /* _TO_SVG_START_ */ + /** + * Returns svg representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var markup = this._createBaseSVGMarkup(), x = this.left, y = this.top; + if (!(this.group && this.group.type === 'path-group')) { + x = -this.width / 2; + y = -this.height / 2; + } + markup.push( + '\n'); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + }); + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`) + * @static + * @memberOf fabric.Rect + * @see: http://www.w3.org/TR/SVG/shapes.html#RectElement + */ + fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' ')); + + /** + * Returns {@link fabric.Rect} instance from an SVG element + * @static + * @memberOf fabric.Rect + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Rect} Instance of fabric.Rect + */ + fabric.Rect.fromElement = function(element, options) { + if (!element) { + return null; + } + options = options || { }; + + var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES); + + parsedAttributes.left = parsedAttributes.left || 0; + parsedAttributes.top = parsedAttributes.top || 0; + var rect = new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes)); + rect.visible = rect.visible && rect.width > 0 && rect.height > 0; + return rect; + }; + /* _FROM_SVG_END_ */ + + /** + * Returns {@link fabric.Rect} instance from an object representation + * @static + * @memberOf fabric.Rect + * @param {Object} object Object to create an instance from + * @param {Function} [callback] Callback to invoke when an fabric.Rect instance is created + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {Object} instance of fabric.Rect + */ + fabric.Rect.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Rect', object, callback, forceAsync); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + min = fabric.util.array.min, + max = fabric.util.array.max, + toFixed = fabric.util.toFixed, + NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS; + + if (fabric.Polyline) { + fabric.warn('fabric.Polyline is already defined'); + return; + } + + /** + * Polyline class + * @class fabric.Polyline + * @extends fabric.Object + * @see {@link fabric.Polyline#initialize} for constructor definition + */ + fabric.Polyline = fabric.util.createClass(fabric.Object, /** @lends fabric.Polyline.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'polyline', + + /** + * Points array + * @type Array + * @default + */ + points: null, + + /** + * Minimum X from points values, necessary to offset points + * @type Number + * @default + */ + minX: 0, + + /** + * Minimum Y from points values, necessary to offset points + * @type Number + * @default + */ + minY: 0, + + cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'), + + /** + * Constructor + * @param {Array} points Array of points (where each point is an object with x and y) + * @param {Object} [options] Options object + * @return {fabric.Polyline} thisArg + * @example + * var poly = new fabric.Polyline([ + * { x: 10, y: 10 }, + * { x: 50, y: 30 }, + * { x: 40, y: 70 }, + * { x: 60, y: 50 }, + * { x: 100, y: 150 }, + * { x: 40, y: 100 } + * ], { + * stroke: 'red', + * left: 100, + * top: 100 + * }); + */ + initialize: function(points, options) { + options = options || {}; + this.points = points || []; + this.callSuper('initialize', options); + this._calcDimensions(); + if (!('top' in options)) { + this.top = this.minY; + } + if (!('left' in options)) { + this.left = this.minX; + } + this.pathOffset = { + x: this.minX + this.width / 2, + y: this.minY + this.height / 2 + }; + }, + + /** + * @private + */ + _calcDimensions: function() { + + 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; + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} Object representation of an instance + */ + toObject: function(propertiesToInclude) { + return extend(this.callSuper('toObject', propertiesToInclude), { + points: this.points.concat() + }); + }, + + /* _TO_SVG_START_ */ + /** + * Returns svg representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var points = [], + diffX = 0, + diffY = 0, + markup = this._createBaseSVGMarkup(); + + if (!(this.group && this.group.type === 'path-group')) { + diffX = this.pathOffset.x; + diffY = this.pathOffset.y; + } + + for (var i = 0, len = this.points.length; i < len; i++) { + points.push( + toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',', + toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' ' + ); + } + markup.push( + '<', this.type, ' ', this.getSvgId(), + 'points="', points.join(''), + '" style="', this.getSvgStyles(), + '" transform="', this.getSvgTransform(), + ' ', this.getSvgTransformMatrix(), + '"/>\n' + ); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + commonRender: function(ctx, noTransform) { + var point, len = this.points.length, + x = noTransform ? 0 : this.pathOffset.x, + y = noTransform ? 0 : this.pathOffset.y; + + if (!len || isNaN(this.points[len - 1].y)) { + // do not draw if no points or odd points + // NaN comes from parseFloat of a empty string in parser + return false; + } + ctx.beginPath(); + ctx.moveTo(this.points[0].x - x, this.points[0].y - y); + for (var i = 0; i < len; i++) { + point = this.points[i]; + ctx.lineTo(point.x - x, point.y - y); + } + return true; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + _render: function(ctx, noTransform) { + if (!this.commonRender(ctx, noTransform)) { + return; + } + this._renderFill(ctx); + this._renderStroke(ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderDashedStroke: function(ctx) { + var p1, p2; + + ctx.beginPath(); + for (var i = 0, len = this.points.length; i < len; i++) { + p1 = this.points[i]; + p2 = this.points[i + 1] || p1; + fabric.util.drawDashedLine(ctx, p1.x, p1.y, p2.x, p2.y, this.strokeDashArray); + } + }, + + /** + * Returns complexity of an instance + * @return {Number} complexity of this instance + */ + complexity: function() { + return this.get('points').length; + } + }); + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by {@link fabric.Polyline.fromElement}) + * @static + * @memberOf fabric.Polyline + * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement + */ + fabric.Polyline.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(); + + /** + * Returns fabric.Polyline instance from an SVG element + * @static + * @memberOf fabric.Polyline + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Polyline} Instance of fabric.Polyline + */ + fabric.Polyline.fromElement = function(element, options) { + if (!element) { + return null; + } + options || (options = { }); + + 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)); + }; + /* _FROM_SVG_END_ */ + + /** + * Returns fabric.Polyline instance from an object representation + * @static + * @memberOf fabric.Polyline + * @param {Object} object Object to create an instance from + * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.Polyline} Instance of fabric.Polyline + */ + fabric.Polyline.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Polyline', object, callback, forceAsync, 'points'); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend; + + if (fabric.Polygon) { + fabric.warn('fabric.Polygon is already defined'); + return; + } + + /** + * Polygon class + * @class fabric.Polygon + * @extends fabric.Polyline + * @see {@link fabric.Polygon#initialize} for constructor definition + */ + fabric.Polygon = fabric.util.createClass(fabric.Polyline, /** @lends fabric.Polygon.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'polygon', + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + _render: function(ctx, noTransform) { + if (!this.commonRender(ctx, noTransform)) { + return; + } + ctx.closePath(); + this._renderFill(ctx); + this._renderStroke(ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderDashedStroke: function(ctx) { + this.callSuper('_renderDashedStroke', ctx); + ctx.closePath(); + }, + }); + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`) + * @static + * @memberOf fabric.Polygon + * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement + */ + fabric.Polygon.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(); + + /** + * Returns {@link fabric.Polygon} instance from an SVG element + * @static + * @memberOf fabric.Polygon + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Polygon} Instance of fabric.Polygon + */ + fabric.Polygon.fromElement = function(element, options) { + if (!element) { + return null; + } + + options || (options = { }); + + var points = fabric.parsePointsAttribute(element.getAttribute('points')), + parsedAttributes = fabric.parseAttributes(element, fabric.Polygon.ATTRIBUTE_NAMES); + + return new fabric.Polygon(points, extend(parsedAttributes, options)); + }; + /* _FROM_SVG_END_ */ + + /** + * Returns fabric.Polygon instance from an object representation + * @static + * @memberOf fabric.Polygon + * @param {Object} object Object to create an instance from + * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.Polygon} Instance of fabric.Polygon + */ + fabric.Polygon.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Polygon', object, callback, forceAsync, 'points'); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + min = fabric.util.array.min, + max = fabric.util.array.max, + extend = fabric.util.object.extend, + _toString = Object.prototype.toString, + drawArc = fabric.util.drawArc, + commandLengths = { + m: 2, + l: 2, + h: 1, + v: 1, + c: 6, + s: 4, + q: 4, + t: 2, + a: 7 + }, + repeatedCommands = { + m: 'l', + M: 'L' + }; + + if (fabric.Path) { + fabric.warn('fabric.Path is already defined'); + return; + } + + /** + * Path class + * @class fabric.Path + * @extends fabric.Object + * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup} + * @see {@link fabric.Path#initialize} for constructor definition + */ + fabric.Path = fabric.util.createClass(fabric.Object, /** @lends fabric.Path.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'path', + + /** + * Array of path points + * @type Array + * @default + */ + path: null, + + /** + * Minimum X from points values, necessary to offset points + * @type Number + * @default + */ + minX: 0, + + /** + * Minimum Y from points values, necessary to offset points + * @type Number + * @default + */ + minY: 0, + + cacheProperties: fabric.Object.prototype.cacheProperties.concat('path', 'fillRule'), + + stateProperties: fabric.Object.prototype.stateProperties.concat('path'), + + /** + * Constructor + * @param {Array|String} path Path data (sequence of coordinates and corresponding "command" tokens) + * @param {Object} [options] Options object + * @return {fabric.Path} thisArg + */ + initialize: function(path, options) { + options = options || { }; + this.callSuper('initialize', options); + + if (!path) { + path = []; + } + + var fromArray = _toString.call(path) === '[object Array]'; + + this.path = fromArray + ? path + // one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values) + : path.match && path.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi); + + if (!this.path) { + return; + } + + if (!fromArray) { + this.path = this._parsePath(); + } + + this._setPositionDimensions(options); + }, + + /** + * @private + * @param {Object} options Options object + */ + _setPositionDimensions: function(options) { + var calcDim = this._parseDimensions(); + + this.minX = calcDim.left; + this.minY = calcDim.top; + this.width = calcDim.width; + this.height = calcDim.height; + + if (typeof options.left === 'undefined') { + this.left = calcDim.left + (this.originX === 'center' + ? this.width / 2 + : this.originX === 'right' + ? this.width + : 0); + } + + if (typeof options.top === 'undefined') { + this.top = calcDim.top + (this.originY === 'center' + ? this.height / 2 + : this.originY === 'bottom' + ? this.height + : 0); + } + + this.pathOffset = this.pathOffset || { + x: this.minX + this.width / 2, + y: this.minY + this.height / 2 + }; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx context to render path on + */ + _renderPathCommands: function(ctx) { + var current, // current instruction + previous = null, + subpathStartX = 0, + subpathStartY = 0, + x = 0, // current x + y = 0, // current y + controlX = 0, // current control point x + controlY = 0, // current control point y + tempX, + tempY, + l = -this.pathOffset.x, + t = -this.pathOffset.y; + + if (this.group && this.group.type === 'path-group') { + l = 0; + t = 0; + } + + ctx.beginPath(); + + for (var i = 0, len = this.path.length; i < len; ++i) { + + current = this.path[i]; + + switch (current[0]) { // first letter + + case 'l': // lineto, relative + x += current[1]; + y += current[2]; + ctx.lineTo(x + l, y + t); + break; + + case 'L': // lineto, absolute + x = current[1]; + y = current[2]; + ctx.lineTo(x + l, y + t); + break; + + case 'h': // horizontal lineto, relative + x += current[1]; + ctx.lineTo(x + l, y + t); + break; + + case 'H': // horizontal lineto, absolute + x = current[1]; + ctx.lineTo(x + l, y + t); + break; + + case 'v': // vertical lineto, relative + y += current[1]; + ctx.lineTo(x + l, y + t); + break; + + case 'V': // verical lineto, absolute + y = current[1]; + ctx.lineTo(x + l, y + t); + break; + + case 'm': // moveTo, relative + x += current[1]; + y += current[2]; + subpathStartX = x; + subpathStartY = y; + ctx.moveTo(x + l, y + t); + break; + + case 'M': // moveTo, absolute + x = current[1]; + y = current[2]; + subpathStartX = x; + subpathStartY = y; + ctx.moveTo(x + l, y + t); + break; + + case 'c': // bezierCurveTo, relative + tempX = x + current[5]; + tempY = y + current[6]; + controlX = x + current[3]; + controlY = y + current[4]; + ctx.bezierCurveTo( + x + current[1] + l, // x1 + y + current[2] + t, // y1 + controlX + l, // x2 + controlY + t, // y2 + tempX + l, + tempY + t + ); + x = tempX; + y = tempY; + break; + + case 'C': // bezierCurveTo, absolute + x = current[5]; + y = current[6]; + controlX = current[3]; + controlY = current[4]; + ctx.bezierCurveTo( + current[1] + l, + current[2] + t, + controlX + l, + controlY + t, + x + l, + y + t + ); + break; + + case 's': // shorthand cubic bezierCurveTo, relative + + // transform to absolute x,y + tempX = x + current[3]; + tempY = y + current[4]; + + if (previous[0].match(/[CcSs]/) === null) { + // If there is no previous command or if the previous command was not a C, c, S, or s, + // the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control points + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + + ctx.bezierCurveTo( + controlX + l, + controlY + t, + x + current[1] + l, + y + current[2] + t, + tempX + l, + tempY + t + ); + // set control point to 2nd one of this command + // "... the first control point is assumed to be + // the reflection of the second control point on + // the previous command relative to the current point." + controlX = x + current[1]; + controlY = y + current[2]; + + x = tempX; + y = tempY; + break; + + case 'S': // shorthand cubic bezierCurveTo, absolute + tempX = current[3]; + tempY = current[4]; + if (previous[0].match(/[CcSs]/) === null) { + // If there is no previous command or if the previous command was not a C, c, S, or s, + // the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control points + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + ctx.bezierCurveTo( + controlX + l, + controlY + t, + current[1] + l, + current[2] + t, + tempX + l, + tempY + t + ); + x = tempX; + y = tempY; + + // set control point to 2nd one of this command + // "... the first control point is assumed to be + // the reflection of the second control point on + // the previous command relative to the current point." + controlX = current[1]; + controlY = current[2]; + + break; + + case 'q': // quadraticCurveTo, relative + // transform to absolute x,y + tempX = x + current[3]; + tempY = y + current[4]; + + controlX = x + current[1]; + controlY = y + current[2]; + + ctx.quadraticCurveTo( + controlX + l, + controlY + t, + tempX + l, + tempY + t + ); + x = tempX; + y = tempY; + break; + + case 'Q': // quadraticCurveTo, absolute + tempX = current[3]; + tempY = current[4]; + + ctx.quadraticCurveTo( + current[1] + l, + current[2] + t, + tempX + l, + tempY + t + ); + x = tempX; + y = tempY; + controlX = current[1]; + controlY = current[2]; + break; + + case 't': // shorthand quadraticCurveTo, relative + + // transform to absolute x,y + tempX = x + current[1]; + tempY = y + current[2]; + + if (previous[0].match(/[QqTt]/) === null) { + // If there is no previous command or if the previous command was not a Q, q, T or t, + // assume the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control point + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + + ctx.quadraticCurveTo( + controlX + l, + controlY + t, + tempX + l, + tempY + t + ); + x = tempX; + y = tempY; + + break; + + case 'T': + tempX = current[1]; + tempY = current[2]; + + if (previous[0].match(/[QqTt]/) === null) { + // If there is no previous command or if the previous command was not a Q, q, T or t, + // assume the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control point + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + ctx.quadraticCurveTo( + controlX + l, + controlY + t, + tempX + l, + tempY + t + ); + x = tempX; + y = tempY; + break; + + case 'a': + // TODO: optimize this + drawArc(ctx, x + l, y + t, [ + current[1], + current[2], + current[3], + current[4], + current[5], + current[6] + x + l, + current[7] + y + t + ]); + x += current[6]; + y += current[7]; + break; + + case 'A': + // TODO: optimize this + drawArc(ctx, x + l, y + t, [ + current[1], + current[2], + current[3], + current[4], + current[5], + current[6] + l, + current[7] + t + ]); + x = current[6]; + y = current[7]; + break; + + case 'z': + case 'Z': + x = subpathStartX; + y = subpathStartY; + ctx.closePath(); + break; + } + previous = current; + } + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx context to render path on + */ + _render: function(ctx) { + this._renderPathCommands(ctx); + this._renderFill(ctx); + this._renderStroke(ctx); + }, + + /** + * Returns string representation of an instance + * @return {String} string representation of an instance + */ + toString: function() { + return '#'; + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + var o = extend(this.callSuper('toObject', ['sourcePath', 'pathOffset'].concat(propertiesToInclude)), { + path: this.path.map(function(item) { return item.slice(); }), + top: this.top, + left: this.left, + }); + return o; + }, + + /** + * Returns dataless object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toDatalessObject: function(propertiesToInclude) { + var o = this.toObject(propertiesToInclude); + if (this.sourcePath) { + o.path = this.sourcePath; + } + delete o.sourcePath; + return o; + }, + + /* _TO_SVG_START_ */ + /** + * Returns svg representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var chunks = [], + markup = this._createBaseSVGMarkup(), addTransform = ''; + + for (var i = 0, len = this.path.length; i < len; i++) { + chunks.push(this.path[i].join(' ')); + } + var path = chunks.join(' '); + if (!(this.group && this.group.type === 'path-group')) { + addTransform = ' translate(' + (-this.pathOffset.x) + ', ' + (-this.pathOffset.y) + ') '; + } + markup.push( + '\n' + ); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + + /** + * Returns number representation of an instance complexity + * @return {Number} complexity of this instance + */ + complexity: function() { + return this.path.length; + }, + + /** + * @private + */ + _parsePath: function() { + var result = [], + coords = [], + currentPath, + parsed, + re = /([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig, + match, + coordsStr; + + for (var i = 0, coordsParsed, len = this.path.length; i < len; i++) { + currentPath = this.path[i]; + + coordsStr = currentPath.slice(1).trim(); + coords.length = 0; + + while ((match = re.exec(coordsStr))) { + coords.push(match[0]); + } + + coordsParsed = [currentPath.charAt(0)]; + + for (var j = 0, jlen = coords.length; j < jlen; j++) { + parsed = parseFloat(coords[j]); + if (!isNaN(parsed)) { + coordsParsed.push(parsed); + } + } + + var command = coordsParsed[0], + commandLength = commandLengths[command.toLowerCase()], + repeatedCommand = repeatedCommands[command] || command; + + 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))); + command = repeatedCommand; + } + } + else { + result.push(coordsParsed); + } + } + + return result; + }, + + /** + * @private + */ + _parseDimensions: function() { + + var aX = [], + aY = [], + current, // current instruction + previous = null, + subpathStartX = 0, + subpathStartY = 0, + x = 0, // current x + y = 0, // current y + controlX = 0, // current control point x + controlY = 0, // current control point y + tempX, + tempY, + bounds; + + for (var i = 0, len = this.path.length; i < len; ++i) { + + current = this.path[i]; + + switch (current[0]) { // first letter + + case 'l': // lineto, relative + x += current[1]; + y += current[2]; + bounds = []; + break; + + case 'L': // lineto, absolute + x = current[1]; + y = current[2]; + bounds = []; + break; + + case 'h': // horizontal lineto, relative + x += current[1]; + bounds = []; + break; + + case 'H': // horizontal lineto, absolute + x = current[1]; + bounds = []; + break; + + case 'v': // vertical lineto, relative + y += current[1]; + bounds = []; + break; + + case 'V': // verical lineto, absolute + y = current[1]; + bounds = []; + break; + + case 'm': // moveTo, relative + x += current[1]; + y += current[2]; + subpathStartX = x; + subpathStartY = y; + bounds = []; + break; + + case 'M': // moveTo, absolute + x = current[1]; + y = current[2]; + subpathStartX = x; + subpathStartY = y; + bounds = []; + break; + + case 'c': // bezierCurveTo, relative + tempX = x + current[5]; + tempY = y + current[6]; + controlX = x + current[3]; + controlY = y + current[4]; + bounds = fabric.util.getBoundsOfCurve(x, y, + x + current[1], // x1 + y + current[2], // y1 + controlX, // x2 + controlY, // y2 + tempX, + tempY + ); + x = tempX; + y = tempY; + break; + + case 'C': // bezierCurveTo, absolute + controlX = current[3]; + controlY = current[4]; + bounds = fabric.util.getBoundsOfCurve(x, y, + current[1], + current[2], + controlX, + controlY, + current[5], + current[6] + ); + x = current[5]; + y = current[6]; + break; + + case 's': // shorthand cubic bezierCurveTo, relative + + // transform to absolute x,y + tempX = x + current[3]; + tempY = y + current[4]; + + if (previous[0].match(/[CcSs]/) === null) { + // If there is no previous command or if the previous command was not a C, c, S, or s, + // the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control points + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + + bounds = fabric.util.getBoundsOfCurve(x, y, + controlX, + controlY, + x + current[1], + y + current[2], + tempX, + tempY + ); + // set control point to 2nd one of this command + // "... the first control point is assumed to be + // the reflection of the second control point on + // the previous command relative to the current point." + controlX = x + current[1]; + controlY = y + current[2]; + x = tempX; + y = tempY; + break; + + case 'S': // shorthand cubic bezierCurveTo, absolute + tempX = current[3]; + tempY = current[4]; + if (previous[0].match(/[CcSs]/) === null) { + // If there is no previous command or if the previous command was not a C, c, S, or s, + // the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control points + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + bounds = fabric.util.getBoundsOfCurve(x, y, + controlX, + controlY, + current[1], + current[2], + tempX, + tempY + ); + x = tempX; + y = tempY; + // set control point to 2nd one of this command + // "... the first control point is assumed to be + // the reflection of the second control point on + // the previous command relative to the current point." + controlX = current[1]; + controlY = current[2]; + break; + + case 'q': // quadraticCurveTo, relative + // transform to absolute x,y + tempX = x + current[3]; + tempY = y + current[4]; + controlX = x + current[1]; + controlY = y + current[2]; + bounds = fabric.util.getBoundsOfCurve(x, y, + controlX, + controlY, + controlX, + controlY, + tempX, + tempY + ); + x = tempX; + y = tempY; + break; + + case 'Q': // quadraticCurveTo, absolute + controlX = current[1]; + controlY = current[2]; + bounds = fabric.util.getBoundsOfCurve(x, y, + controlX, + controlY, + controlX, + controlY, + current[3], + current[4] + ); + x = current[3]; + y = current[4]; + break; + + case 't': // shorthand quadraticCurveTo, relative + // transform to absolute x,y + tempX = x + current[1]; + tempY = y + current[2]; + if (previous[0].match(/[QqTt]/) === null) { + // If there is no previous command or if the previous command was not a Q, q, T or t, + // assume the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control point + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + + bounds = fabric.util.getBoundsOfCurve(x, y, + controlX, + controlY, + controlX, + controlY, + tempX, + tempY + ); + x = tempX; + y = tempY; + + break; + + case 'T': + tempX = current[1]; + tempY = current[2]; + + if (previous[0].match(/[QqTt]/) === null) { + // If there is no previous command or if the previous command was not a Q, q, T or t, + // assume the control point is coincident with the current point + controlX = x; + controlY = y; + } + else { + // calculate reflection of previous control point + controlX = 2 * x - controlX; + controlY = 2 * y - controlY; + } + bounds = fabric.util.getBoundsOfCurve(x, y, + controlX, + controlY, + controlX, + controlY, + tempX, + tempY + ); + x = tempX; + y = tempY; + break; + + case 'a': + // TODO: optimize this + bounds = fabric.util.getBoundsOfArc(x, y, + current[1], + current[2], + current[3], + current[4], + current[5], + current[6] + x, + current[7] + y + ); + x += current[6]; + y += current[7]; + break; + + case 'A': + // TODO: optimize this + bounds = fabric.util.getBoundsOfArc(x, y, + current[1], + current[2], + current[3], + current[4], + current[5], + current[6], + current[7] + ); + x = current[6]; + y = current[7]; + break; + + case 'z': + case 'Z': + x = subpathStartX; + y = subpathStartY; + break; + } + previous = current; + bounds.forEach(function (point) { + aX.push(point.x); + aY.push(point.y); + }); + aX.push(x); + aY.push(y); + } + + var minX = min(aX) || 0, + minY = min(aY) || 0, + maxX = max(aX) || 0, + maxY = max(aY) || 0, + deltaX = maxX - minX, + deltaY = maxY - minY, + + o = { + left: minX, + top: minY, + width: deltaX, + height: deltaY + }; + + return o; + } + }); + + /** + * Creates an instance of fabric.Path from an object + * @static + * @memberOf fabric.Path + * @param {Object} object + * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + */ + fabric.Path.fromObject = function(object, callback, forceAsync) { + // remove this pattern rom 2.0, accept just object. + var path; + if (typeof object.path === 'string') { + fabric.loadSVGFromURL(object.path, function (elements) { + var pathUrl = object.path; + path = elements[0]; + delete object.path; + + path.setOptions(object); + path.setSourcePath(pathUrl); + + callback && callback(path); + }); + } + else { + return fabric.Object._fromObject('Path', object, callback, forceAsync, 'path'); + } + }; + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by `fabric.Path.fromElement`) + * @static + * @memberOf fabric.Path + * @see http://www.w3.org/TR/SVG/paths.html#PathElement + */ + fabric.Path.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(['d']); + + /** + * Creates an instance of fabric.Path from an SVG element + * @static + * @memberOf fabric.Path + * @param {SVGElement} element to parse + * @param {Function} callback Callback to invoke when an fabric.Path instance is created + * @param {Object} [options] Options object + */ + fabric.Path.fromElement = function(element, callback, options) { + var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES); + callback && callback(new fabric.Path(parsedAttributes.d, extend(parsedAttributes, options))); + }; + /* _FROM_SVG_END_ */ + + /** + * Indicates that instances of this type are async + * @static + * @memberOf fabric.Path + * @type Boolean + * @default + */ + fabric.Path.async = true; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend; + + if (fabric.PathGroup) { + fabric.warn('fabric.PathGroup is already defined'); + return; + } + + /** + * Path group class + * @class fabric.PathGroup + * @extends fabric.Path + * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup} + * @see {@link fabric.PathGroup#initialize} for constructor definition + */ + fabric.PathGroup = fabric.util.createClass(fabric.Object, /** @lends fabric.PathGroup.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'path-group', + + /** + * Fill value + * @type String + * @default + */ + fill: '', + + /** + * Pathgroups are container, do not render anything on theyr own, ence no cache properties + * @type Boolean + * @default + */ + cacheProperties: [], + + /** + * Constructor + * @param {Array} paths + * @param {Object} [options] Options object + * @return {fabric.PathGroup} thisArg + */ + initialize: function(paths, options) { + + options = options || { }; + this.paths = paths || []; + + for (var i = this.paths.length; i--;) { + this.paths[i].group = this; + } + + if (options.toBeParsed) { + this.parseDimensionsFromPaths(options); + delete options.toBeParsed; + } + this.setOptions(options); + this.setCoords(); + }, + + /** + * Calculate width and height based on paths contained + */ + parseDimensionsFromPaths: function(options) { + var points, p, xC = [], yC = [], path, height, width, + m; + for (var j = this.paths.length; j--;) { + path = this.paths[j]; + height = path.height + path.strokeWidth; + width = path.width + path.strokeWidth; + points = [ + { x: path.left, y: path.top }, + { x: path.left + width, y: path.top }, + { x: path.left, y: path.top + height }, + { x: path.left + width, y: path.top + height } + ]; + m = this.paths[j].transformMatrix; + for (var i = 0; i < points.length; i++) { + p = points[i]; + if (m) { + p = fabric.util.transformPoint(p, m, false); + } + xC.push(p.x); + yC.push(p.y); + } + } + options.width = Math.max.apply(null, xC); + options.height = Math.max.apply(null, yC); + }, + + /** + * Execute the drawing operation for an object on a specified context + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} [noTransform] When true, context is not transformed + */ + drawObject: function(ctx) { + ctx.save(); + 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); + } + ctx.restore(); + }, + + /** + * Decide if the object should cache or not. + * objectCaching is a global flag, wins over everything + * needsItsOwnCache should be used when the object drawing method requires + * a cache step. None of the fabric classes requires it. + * Generally you do not cache objects in groups because the group outside is cached. + * @return {Boolean} + */ + shouldCache: function() { + var parentCache = this.objectCaching && (!this.group || this.needsItsOwnCache() || !this.group.isCaching()); + this.caching = parentCache; + if (parentCache) { + for (var i = 0, len = this.paths.length; i < len; i++) { + if (this.paths[i].willDrawShadow()) { + this.caching = false; + return false; + } + } + } + return parentCache; + }, + + /** + * Check if this object or a child object will cast a shadow + * @return {Boolean} + */ + willDrawShadow: function() { + if (this.shadow) { + return true; + } + for (var i = 0, len = this.paths.length; i < len; i++) { + if (this.paths[i].willDrawShadow()) { + return true; + } + } + return false; + }, + + /** + * Check if this group or its parent group are caching, recursively up + * @return {Boolean} + */ + isCaching: function() { + return this.caching || this.group && this.group.isCaching(); + }, + + /** + * Check if cache is dirty + */ + isCacheDirty: function() { + if (this.callSuper('isCacheDirty')) { + return true; + } + if (!this.statefullCache) { + return false; + } + for (var i = 0, len = this.paths.length; i < len; i++) { + if (this.paths[i].isCacheDirty(true)) { + if (this._cacheCanvas) { + var x = this.cacheWidth / this.zoomX, y = this.cacheHeight / this.zoomY; + this._cacheContext.clearRect(-x / 2, -y / 2, x, y); + } + return true; + } + } + return false; + }, + + /** + * Sets certain property to a certain value + * @param {String} prop + * @param {*} value + * @return {fabric.PathGroup} thisArg + */ + _set: function(prop, value) { + + if (prop === 'fill' && value && this.isSameColor()) { + var i = this.paths.length; + while (i--) { + this.paths[i]._set(prop, value); + } + } + + return this.callSuper('_set', prop, value); + }, + + /** + * Returns object representation of this path group + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + var pathsToObject = this.paths.map(function(path) { + var originalDefaults = path.includeDefaultValues; + path.includeDefaultValues = path.group.includeDefaultValues; + var obj = path.toObject(propertiesToInclude); + path.includeDefaultValues = originalDefaults; + return obj; + }); + var o = extend(this.callSuper('toObject', ['sourcePath'].concat(propertiesToInclude)), { + paths: pathsToObject + }); + return o; + }, + + /** + * Returns dataless object representation of this path group + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} dataless object representation of an instance + */ + toDatalessObject: function(propertiesToInclude) { + var o = this.toObject(propertiesToInclude); + if (this.sourcePath) { + o.paths = this.sourcePath; + } + return o; + }, + + /* _TO_SVG_START_ */ + /** + * Returns svg representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var objects = this.getObjects(), + p = this.getPointByOrigin('left', 'top'), + translatePart = 'translate(' + p.x + ' ' + p.y + ')', + markup = this._createBaseSVGMarkup(); + markup.push( + '\n' + ); + + for (var i = 0, len = objects.length; i < len; i++) { + markup.push('\t', objects[i].toSVG(reviver)); + } + markup.push('\n'); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + + /** + * Returns a string representation of this path group + * @return {String} string representation of an object + */ + toString: function() { + return '#'; + }, + + /** + * Returns true if all paths in this group are of same color + * @return {Boolean} true if all paths are of the same color (`fill`) + */ + isSameColor: function() { + var firstPathFill = this.getObjects()[0].get('fill') || ''; + if (typeof firstPathFill !== 'string') { + return false; + } + firstPathFill = firstPathFill.toLowerCase(); + return this.getObjects().every(function(path) { + var pathFill = path.get('fill') || ''; + return typeof pathFill === 'string' && (pathFill).toLowerCase() === firstPathFill; + }); + }, + + /** + * Returns number representation of object's complexity + * @return {Number} complexity + */ + complexity: function() { + return this.paths.reduce(function(total, path) { + return total + ((path && path.complexity) ? path.complexity() : 0); + }, 0); + }, + + /** + * Returns all paths in this path group + * @return {Array} array of path objects included in this path group + */ + getObjects: function() { + return this.paths; + } + }); + + /** + * Creates fabric.PathGroup instance from an object representation + * @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 + */ + fabric.PathGroup.fromObject = function(object, callback) { + var originalPaths = object.paths; + delete object.paths; + if (typeof originalPaths === 'string') { + fabric.loadSVGFromURL(originalPaths, function (elements) { + var pathUrl = originalPaths; + var pathGroup = fabric.util.groupSVGElements(elements, object, pathUrl); + object.paths = originalPaths; + callback(pathGroup); + }); + } + else { + fabric.util.enlivenObjects(originalPaths, function(enlivenedObjects) { + var pathGroup = new fabric.PathGroup(enlivenedObjects, object); + object.paths = originalPaths; + callback(pathGroup); + }); + } + }; + + /** + * Indicates that instances of this type are async + * @static + * @memberOf fabric.PathGroup + * @type Boolean + * @default + */ + fabric.PathGroup.async = true; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + min = fabric.util.array.min, + max = fabric.util.array.max; + + if (fabric.Group) { + return; + } + + // lock-related properties, for use in fabric.Group#get + // to enable locking behavior on group + // when one of its objects has lock-related properties set + var _lockProperties = { + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + lockUniScaling: true + }; + + /** + * Group class + * @class fabric.Group + * @extends fabric.Object + * @mixes fabric.Collection + * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#groups} + * @see {@link fabric.Group#initialize} for constructor definition + */ + fabric.Group = fabric.util.createClass(fabric.Object, fabric.Collection, /** @lends fabric.Group.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'group', + + /** + * Width of stroke + * @type Number + * @default + */ + strokeWidth: 0, + + /** + * Indicates if click events should also check for subtargets + * @type Boolean + * @default + */ + subTargetCheck: false, + + /** + * Groups are container, do not render anything on theyr own, ence no cache properties + * @type Boolean + * @default + */ + cacheProperties: [], + + /** + * Constructor + * @param {Object} objects Group objects + * @param {Object} [options] Options object + * @param {Boolean} [isAlreadyGrouped] if true, objects have been grouped already. + * @return {Object} thisArg + */ + initialize: function(objects, options, isAlreadyGrouped) { + options = options || { }; + + this._objects = []; + // if objects enclosed in a group have been grouped already, + // we cannot change properties of objects. + // Thus we need to set options to group without objects, + // because delegatedProperties propagate to objects. + isAlreadyGrouped && this.callSuper('initialize', options); + + this._objects = objects || []; + for (var i = this._objects.length; i--; ) { + this._objects[i].group = this; + } + + if (options.originX) { + this.originX = options.originX; + } + if (options.originY) { + this.originY = options.originY; + } + + if (isAlreadyGrouped) { + // do not change coordinate of objects enclosed in a group, + // because objects coordinate system have been group coodinate system already. + this._updateObjectsCoords(true); + this._updateObjectsACoords(); + } + else { + this._calcBounds(); + this._updateObjectsCoords(); + this.callSuper('initialize', options); + } + + this.setCoords(); + this.saveCoords(); + }, + + _updateObjectsACoords: function() { + var ignoreZoom = true, skipAbsolute = true; + for (var i = this._objects.length; i--; ){ + this._objects[i].setCoords(ignoreZoom, skipAbsolute); + } + }, + + /** + * @private + * @param {Boolean} [skipCoordsChange] if true, coordinates of objects enclosed in a group do not change + */ + _updateObjectsCoords: function(skipCoordsChange) { + var center = this.getCenterPoint(); + for (var i = this._objects.length; i--; ){ + this._updateObjectCoords(this._objects[i], center, skipCoordsChange); + } + }, + + /** + * @private + * @param {Object} object + * @param {fabric.Point} center, current center of group. + * @param {Boolean} [skipCoordsChange] if true, coordinates of object dose not change + */ + _updateObjectCoords: function(object, center, skipCoordsChange) { + // do not display corners of objects enclosed in a group + object.__origHasControls = object.hasControls; + object.hasControls = false; + + if (skipCoordsChange) { + return; + } + + var objectLeft = object.getLeft(), + objectTop = object.getTop(), + ignoreZoom = true, skipAbsolute = true; + + object.set({ + left: objectLeft - center.x, + top: objectTop - center.y + }); + object.setCoords(ignoreZoom, skipAbsolute); + }, + + /** + * Returns string represenation of a group + * @return {String} + */ + toString: function() { + return '#'; + }, + + /** + * Adds an object to a group; Then recalculates group's dimension, position. + * @param {Object} object + * @return {fabric.Group} thisArg + * @chainable + */ + addWithUpdate: function(object) { + this._restoreObjectsState(); + fabric.util.resetObjectTransform(this); + if (object) { + this._objects.push(object); + object.group = this; + object._set('canvas', this.canvas); + } + // since _restoreObjectsState set objects inactive + this.forEachObject(this._setObjectActive, this); + this._calcBounds(); + this._updateObjectsCoords(); + this.setCoords(); + this.dirty = true; + return this; + }, + + /** + * @private + */ + _setObjectActive: function(object) { + object.set('active', true); + object.group = this; + }, + + /** + * Removes an object from a group; Then recalculates group's dimension, position. + * @param {Object} object + * @return {fabric.Group} thisArg + * @chainable + */ + removeWithUpdate: function(object) { + this._restoreObjectsState(); + fabric.util.resetObjectTransform(this); + // since _restoreObjectsState set objects inactive + this.forEachObject(this._setObjectActive, this); + + this.remove(object); + this._calcBounds(); + this._updateObjectsCoords(); + this.setCoords(); + this.dirty = true; + return this; + }, + + /** + * @private + */ + _onObjectAdded: function(object) { + this.dirty = true; + object.group = this; + object._set('canvas', this.canvas); + }, + + /** + * @private + */ + _onObjectRemoved: function(object) { + this.dirty = true; + delete object.group; + object.set('active', false); + }, + + /** + * Properties that are delegated to group objects when reading/writing + * @param {Object} delegatedProperties + */ + delegatedProperties: { + fill: true, + stroke: true, + strokeWidth: true, + fontFamily: true, + fontWeight: true, + fontSize: true, + fontStyle: true, + lineHeight: true, + textDecoration: true, + textAlign: true, + backgroundColor: true + }, + + /** + * @private + */ + _set: function(key, value) { + var i = this._objects.length; + + if (this.delegatedProperties[key] || key === 'canvas') { + while (i--) { + this._objects[i].set(key, value); + } + } + else { + while (i--) { + this._objects[i].setOnGroup(key, value); + } + } + + this.callSuper('_set', key, value); + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + var objsToObject = this.getObjects().map(function(obj) { + var originalDefaults = obj.includeDefaultValues; + obj.includeDefaultValues = obj.group.includeDefaultValues; + var _obj = obj.toObject(propertiesToInclude); + obj.includeDefaultValues = originalDefaults; + return _obj; + }); + return extend(this.callSuper('toObject', propertiesToInclude), { + objects: objsToObject + }); + }, + + /** + * Returns object representation of an instance, in dataless mode. + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toDatalessObject: function(propertiesToInclude) { + var objsToObject = this.getObjects().map(function(obj) { + var originalDefaults = obj.includeDefaultValues; + obj.includeDefaultValues = obj.group.includeDefaultValues; + var _obj = obj.toDatalessObject(propertiesToInclude); + obj.includeDefaultValues = originalDefaults; + return _obj; + }); + return extend(this.callSuper('toDatalessObject', propertiesToInclude), { + objects: objsToObject + }); + }, + + /** + * Renders instance on a given context + * @param {CanvasRenderingContext2D} ctx context to render instance on + */ + render: function(ctx) { + this._transformDone = true; + this.callSuper('render', ctx); + this._transformDone = false; + }, + + /** + * Decide if the object should cache or not. + * objectCaching is a global flag, wins over everything + * needsItsOwnCache should be used when the object drawing method requires + * a cache step. None of the fabric classes requires it. + * Generally you do not cache objects in groups because the group outside is cached. + * @return {Boolean} + */ + shouldCache: function() { + var parentCache = this.objectCaching && (!this.group || this.needsItsOwnCache() || !this.group.isCaching()); + this.caching = parentCache; + if (parentCache) { + for (var i = 0, len = this._objects.length; i < len; i++) { + if (this._objects[i].willDrawShadow()) { + this.caching = false; + return false; + } + } + } + return parentCache; + }, + + /** + * Check if this object or a child object will cast a shadow + * @return {Boolean} + */ + willDrawShadow: function() { + if (this.callSuper('willDrawShadow')) { + return true; + } + for (var i = 0, len = this._objects.length; i < len; i++) { + if (this._objects[i].willDrawShadow()) { + return true; + } + } + return false; + }, + + /** + * Check if this group or its parent group are caching, recursively up + * @return {Boolean} + */ + isCaching: function() { + return this.caching || this.group && this.group.isCaching(); + }, + + /** + * Execute the drawing operation for an object on a specified context + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} [noTransform] When true, context is not transformed + */ + drawObject: function(ctx) { + for (var i = 0, len = this._objects.length; i < len; i++) { + this._renderObject(this._objects[i], ctx); + } + }, + + /** + * Check if cache is dirty + */ + isCacheDirty: function() { + if (this.callSuper('isCacheDirty')) { + return true; + } + if (!this.statefullCache) { + return false; + } + for (var i = 0, len = this._objects.length; i < len; i++) { + if (this._objects[i].isCacheDirty(true)) { + if (this._cacheCanvas) { + // if this group has not a cache canvas there is nothing to clean + var x = this.cacheWidth / this.zoomX, y = this.cacheHeight / this.zoomY; + this._cacheContext.clearRect(-x / 2, -y / 2, x, y); + } + return true; + } + } + return false; + }, + + /** + * Renders controls and borders for the object + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} [noTransform] When true, context is not transformed + */ + _renderControls: function(ctx, noTransform) { + ctx.save(); + ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1; + this.callSuper('_renderControls', ctx, noTransform); + for (var i = 0, len = this._objects.length; i < len; i++) { + this._objects[i]._renderControls(ctx); + } + ctx.restore(); + }, + + /** + * @private + */ + _renderObject: function(object, ctx) { + // do not render if object is not visible + if (!object.visible) { + return; + } + + var originalHasRotatingPoint = object.hasRotatingPoint; + object.hasRotatingPoint = false; + object.render(ctx); + object.hasRotatingPoint = originalHasRotatingPoint; + }, + + /** + * Retores original state of each of group objects (original state is that which was before group was created). + * @private + * @return {fabric.Group} thisArg + * @chainable + */ + _restoreObjectsState: function() { + this._objects.forEach(this._restoreObjectState, this); + return this; + }, + + /** + * Realises the transform from this group onto the supplied object + * i.e. it tells you what would happen if the supplied object was in + * the group, and then the group was destroyed. It mutates the supplied + * object. + * @param {fabric.Object} object + * @return {fabric.Object} transformedObject + */ + realizeTransform: function(object) { + var matrix = object.calcTransformMatrix(), + options = fabric.util.qrDecompose(matrix), + center = new fabric.Point(options.translateX, options.translateY); + object.flipX = false; + object.flipY = false; + object.set('scaleX', options.scaleX); + object.set('scaleY', options.scaleY); + object.skewX = options.skewX; + object.skewY = options.skewY; + object.angle = options.angle; + object.setPositionByOrigin(center, 'center', 'center'); + return object; + }, + + /** + * Restores original state of a specified object in group + * @private + * @param {fabric.Object} object + * @return {fabric.Group} thisArg + */ + _restoreObjectState: function(object) { + this.realizeTransform(object); + object.setCoords(); + object.hasControls = object.__origHasControls; + delete object.__origHasControls; + object.set('active', false); + delete object.group; + + return this; + }, + + /** + * Destroys a group (restoring state of its objects) + * @return {fabric.Group} thisArg + * @chainable + */ + destroy: function() { + // when group is destroyed objects needs to get a repaint to be eventually + // displayed on canvas. + this._objects.forEach(function(object) { + object.set('dirty', true); + }); + return this._restoreObjectsState(); + }, + + /** + * Saves coordinates of this instance (to be used together with `hasMoved`) + * @saveCoords + * @return {fabric.Group} thisArg + * @chainable + */ + saveCoords: function() { + this._originalLeft = this.get('left'); + this._originalTop = this.get('top'); + return this; + }, + + /** + * Checks whether this group was moved (since `saveCoords` was called last) + * @return {Boolean} true if an object was moved (since fabric.Group#saveCoords was called) + */ + hasMoved: function() { + return this._originalLeft !== this.get('left') || + this._originalTop !== this.get('top'); + }, + + /** + * Sets coordinates of all objects inside group + * @return {fabric.Group} thisArg + * @chainable + */ + setObjectsCoords: function() { + var ignoreZoom = true, skipAbsolute = true; + this.forEachObject(function(object) { + object.setCoords(ignoreZoom, skipAbsolute); + }); + return this; + }, + + /** + * @private + */ + _calcBounds: function(onlyWidthHeight) { + var aX = [], + aY = [], + o, prop, + props = ['tr', 'br', 'bl', 'tl'], + i = 0, iLen = this._objects.length, + j, jLen = props.length, + ignoreZoom = true; + + for ( ; i < iLen; ++i) { + o = this._objects[i]; + o.setCoords(ignoreZoom); + for (j = 0; j < jLen; j++) { + prop = props[j]; + aX.push(o.oCoords[prop].x); + aY.push(o.oCoords[prop].y); + } + } + + this.set(this._getBounds(aX, aY, onlyWidthHeight)); + }, + + /** + * @private + */ + _getBounds: function(aX, aY, onlyWidthHeight) { + var minXY = new fabric.Point(min(aX), min(aY)), + maxXY = new fabric.Point(max(aX), max(aY)), + obj = { + width: (maxXY.x - minXY.x) || 0, + height: (maxXY.y - minXY.y) || 0 + }; + + if (!onlyWidthHeight) { + obj.left = minXY.x || 0; + obj.top = minXY.y || 0; + if (this.originX === 'center') { + obj.left += obj.width / 2; + } + if (this.originX === 'right') { + obj.left += obj.width; + } + if (this.originY === 'center') { + obj.top += obj.height / 2; + } + if (this.originY === 'bottom') { + obj.top += obj.height; + } + } + return obj; + }, + + /* _TO_SVG_START_ */ + /** + * Returns svg representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + var markup = this._createBaseSVGMarkup(); + markup.push( + '\n' + ); + + for (var i = 0, len = this._objects.length; i < len; i++) { + markup.push('\t', this._objects[i].toSVG(reviver)); + } + + markup.push('\n'); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + + /** + * Returns requested property + * @param {String} prop Property to get + * @return {*} + */ + get: function(prop) { + if (prop in _lockProperties) { + if (this[prop]) { + return this[prop]; + } + else { + for (var i = 0, len = this._objects.length; i < len; i++) { + if (this._objects[i][prop]) { + return true; + } + } + return false; + } + } + else { + if (prop in this.delegatedProperties) { + return this._objects[0] && this._objects[0].get(prop); + } + return this[prop]; + } + } + }); + + /** + * Returns {@link fabric.Group} instance from an object representation + * @static + * @memberOf fabric.Group + * @param {Object} object Object to create a group from + * @param {Function} [callback] Callback to invoke when an group instance is created + */ + fabric.Group.fromObject = function(object, callback) { + fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) { + var options = fabric.util.object.clone(object, true); + delete options.objects; + callback && callback(new fabric.Group(enlivenedObjects, options, true)); + }); + }; + + /** + * Indicates that instances of this type are async + * @static + * @memberOf fabric.Group + * @type Boolean + * @default + */ + fabric.Group.async = true; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var extend = fabric.util.object.extend; + + if (!global.fabric) { + global.fabric = { }; + } + + if (global.fabric.Image) { + fabric.warn('fabric.Image is already defined.'); + return; + } + + /** + * Image class + * @class fabric.Image + * @extends fabric.Object + * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#images} + * @see {@link fabric.Image#initialize} for constructor definition + */ + fabric.Image = fabric.util.createClass(fabric.Object, /** @lends fabric.Image.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'image', + + /** + * crossOrigin value (one of "", "anonymous", "use-credentials") + * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes + * @type String + * @default + */ + crossOrigin: '', + + /** + * AlignX value, part of preserveAspectRatio (one of "none", "mid", "min", "max") + * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute + * This parameter defines how the picture is aligned to its viewport when image element width differs from image width. + * @type String + * @default + */ + alignX: 'none', + + /** + * AlignY value, part of preserveAspectRatio (one of "none", "mid", "min", "max") + * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute + * This parameter defines how the picture is aligned to its viewport when image element height differs from image height. + * @type String + * @default + */ + alignY: 'none', + + /** + * meetOrSlice value, part of preserveAspectRatio (one of "meet", "slice"). + * if meet the image is always fully visibile, if slice the viewport is always filled with image. + * @see http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute + * @type String + * @default + */ + meetOrSlice: 'meet', + + /** + * Width of a stroke. + * For image quality a stroke multiple of 2 gives better results. + * @type Number + * @default + */ + strokeWidth: 0, + + /** + * private + * contains last value of scaleX to detect + * if the Image got resized after the last Render + * @type Number + */ + _lastScaleX: 1, + + /** + * private + * contains last value of scaleY to detect + * if the Image got resized after the last Render + * @type Number + */ + _lastScaleY: 1, + + /** + * minimum scale factor under which any resizeFilter is triggered to resize the image + * 0 will disable the automatic resize. 1 will trigger automatically always. + * number bigger than 1 can be used in case we want to scale with some filter above + * the natural image dimensions + * @type Number + */ + 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: fabric.Object.prototype.stateProperties.concat( + 'alignX', + 'alignY', + 'meetOrSlice'), + + /** + * When `true`, object is cached on an additional canvas. + * default to false for images + * since 1.7.0 + * @type Boolean + * @default + */ + objectCaching: false, + + /** + * Constructor + * @param {HTMLImageElement | String} element Image element + * @param {Object} [options] Options object + * @param {function} [callback] callback function to call after eventual filters applied. + * @return {fabric.Image} thisArg + */ + initialize: function(element, options, callback) { + options || (options = { }); + this.filters = []; + this.resizeFilters = []; + this.callSuper('initialize', options); + this._initElement(element, options, callback); + }, + + /** + * Returns image element which this instance if based on + * @return {HTMLImageElement} Image element + */ + getElement: function() { + return this._element; + }, + + /** + * Sets image element for this instance to a specified one. + * If filters defined they are applied to new image. + * You might need to call `canvas.renderAll` and `object.setCoords` after replacing, to render new image and update controls area. + * @param {HTMLImageElement} element + * @param {Function} [callback] Callback is invoked when all filters have been applied and new image is generated + * @param {Object} [options] Options object + * @return {fabric.Image} thisArg + * @chainable + */ + setElement: function(element, callback, options) { + + var _callback, _this; + + this._element = element; + this._originalElement = element; + this._initConfig(options); + + if (this.resizeFilters.length === 0) { + _callback = callback; + } + else { + _this = this; + _callback = function() { + _this.applyFilters(callback, _this.resizeFilters, _this._filteredEl || _this._originalElement, true); + }; + } + + if (this.filters.length !== 0) { + this.applyFilters(_callback); + } + else if (_callback) { + _callback(this); + } + + return this; + }, + + /** + * Sets crossOrigin value (on an instance and corresponding image element) + * @return {fabric.Image} thisArg + * @chainable + */ + setCrossOrigin: function(value) { + this.crossOrigin = value; + this._element.crossOrigin = value; + + return this; + }, + + /** + * Returns original size of an image + * @return {Object} Object with "width" and "height" properties + */ + getOriginalSize: function() { + var element = this.getElement(); + return { + width: element.width, + height: element.height + }; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _stroke: function(ctx) { + if (!this.stroke || this.strokeWidth === 0) { + return; + } + var w = this.width / 2, h = this.height / 2; + ctx.beginPath(); + ctx.moveTo(-w, -h); + ctx.lineTo(w, -h); + ctx.lineTo(w, h); + ctx.lineTo(-w, h); + ctx.lineTo(-w, -h); + ctx.closePath(); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderDashedStroke: function(ctx) { + var x = -this.width / 2, + y = -this.height / 2, + w = this.width, + h = this.height; + + ctx.save(); + this._setStrokeStyles(ctx); + + ctx.beginPath(); + fabric.util.drawDashedLine(ctx, x, y, x + w, y, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, x + w, y, x + w, y + h, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, x + w, y + h, x, y + h, this.strokeDashArray); + fabric.util.drawDashedLine(ctx, x, y + h, x, y, this.strokeDashArray); + ctx.closePath(); + ctx.restore(); + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} Object representation of an instance + */ + toObject: function(propertiesToInclude) { + var filters = [], resizeFilters = [], + scaleX = 1, scaleY = 1; + + this.filters.forEach(function(filterObj) { + if (filterObj) { + if (filterObj.type === 'Resize') { + scaleX *= filterObj.scaleX; + scaleY *= filterObj.scaleY; + } + filters.push(filterObj.toObject()); + } + }); + + this.resizeFilters.forEach(function(filterObj) { + filterObj && resizeFilters.push(filterObj.toObject()); + }); + var object = extend( + this.callSuper( + 'toObject', + ['crossOrigin', 'alignX', 'alignY', 'meetOrSlice'].concat(propertiesToInclude) + ), { + src: this.getSrc(), + filters: filters, + resizeFilters: resizeFilters, + }); + + object.width /= scaleX; + object.height /= scaleY; + + return object; + }, + + /* _TO_SVG_START_ */ + /** + * Returns SVG representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + 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; + } + if (this.alignX !== 'none' && this.alignY !== 'none') { + preserveAspectRatio = 'x' + this.alignX + 'Y' + this.alignY + ' ' + this.meetOrSlice; + } + markup.push( + '\n', + '\n' + ); + + if (this.stroke || this.strokeDashArray) { + var origFill = this.fill; + this.fill = null; + markup.push( + '\n' + ); + this.fill = origFill; + } + + markup.push('\n'); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + /* _TO_SVG_END_ */ + + /** + * Returns source of an image + * @param {Boolean} filtered indicates if the src is needed for svg + * @return {String} Source of an image + */ + getSrc: function(filtered) { + var element = filtered ? this._element : this._originalElement; + if (element) { + return fabric.isLikelyNode ? element._src : element.src; + } + else { + return this.src || ''; + } + }, + + /** + * Sets source of an image + * @param {String} src Source string (URL) + * @param {Function} [callback] Callback is invoked when image has been loaded (and all filters have been applied) + * @param {Object} [options] Options object + * @return {fabric.Image} thisArg + * @chainable + */ + setSrc: function(src, callback, options) { + fabric.util.loadImage(src, function(img) { + return this.setElement(img, callback, options); + }, this, options && options.crossOrigin); + }, + + /** + * Returns string representation of an instance + * @return {String} String representation of an instance + */ + toString: function() { + return '#'; + }, + + /** + * Applies filters assigned to this image (from "filters" array) + * @method applyFilters + * @param {Function} callback Callback is invoked when all filters have been applied and new image is generated + * @param {Array} filters to be applied + * @param {fabric.Image} imgElement image to filter ( default to this._element ) + * @param {Boolean} forResizing + * @return {CanvasElement} canvasEl to be drawn immediately + * @chainable + */ + applyFilters: function(callback, filters, imgElement, forResizing) { + + filters = filters || this.filters; + imgElement = imgElement || this._originalElement; + + if (!imgElement) { + return; + } + + var replacement = fabric.util.createImage(), + retinaScaling = this.canvas ? this.canvas.getRetinaScaling() : fabric.devicePixelRatio, + minimumScale = this.minimumScaleTrigger / retinaScaling, + _this = this, scaleX, scaleY; + + if (filters.length === 0) { + this._element = imgElement; + callback && callback(this); + return imgElement; + } + + var canvasEl = fabric.util.createCanvasElement(); + canvasEl.width = imgElement.width; + canvasEl.height = imgElement.height; + canvasEl.getContext('2d').drawImage(imgElement, 0, 0, imgElement.width, imgElement.height); + + filters.forEach(function(filter) { + if (!filter) { + return; + } + if (forResizing) { + scaleX = _this.scaleX < minimumScale ? _this.scaleX : 1; + scaleY = _this.scaleY < minimumScale ? _this.scaleY : 1; + if (scaleX * retinaScaling < 1) { + scaleX *= retinaScaling; + } + if (scaleY * retinaScaling < 1) { + scaleY *= retinaScaling; + } + } + else { + scaleX = filter.scaleX; + scaleY = filter.scaleY; + } + filter.applyTo(canvasEl, scaleX, scaleY); + if (!forResizing && filter.type === 'Resize') { + _this.width *= filter.scaleX; + _this.height *= filter.scaleY; + } + }); + + /** @ignore */ + replacement.width = canvasEl.width; + replacement.height = canvasEl.height; + if (fabric.isLikelyNode) { + replacement.src = canvasEl.toBuffer(undefined, fabric.Image.pngCompression); + // onload doesn't fire in some node versions, so we invoke callback manually + _this._element = replacement; + !forResizing && (_this._filteredEl = replacement); + callback && callback(_this); + } + else { + replacement.onload = function() { + _this._element = replacement; + !forResizing && (_this._filteredEl = replacement); + callback && callback(_this); + replacement.onload = canvasEl = null; + }; + replacement.src = canvasEl.toDataURL('image/png'); + } + return canvasEl; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + _render: function(ctx, noTransform) { + var x, y, imageMargins = this._findMargins(), elementToDraw; + + x = (noTransform ? this.left : -this.width / 2); + y = (noTransform ? this.top : -this.height / 2); + + if (this.meetOrSlice === 'slice') { + ctx.beginPath(); + ctx.rect(x, y, this.width, this.height); + ctx.clip(); + } + + if (this.isMoving === false && this.resizeFilters.length && this._needsResize()) { + this._lastScaleX = this.scaleX; + this._lastScaleY = this.scaleY; + elementToDraw = this.applyFilters(null, this.resizeFilters, this._filteredEl || this._originalElement, true); + } + else { + elementToDraw = this._element; + } + elementToDraw && ctx.drawImage(elementToDraw, + x + imageMargins.marginX, + y + imageMargins.marginY, + imageMargins.width, + imageMargins.height + ); + + this._stroke(ctx); + this._renderStroke(ctx); + }, + + /** + * @private, needed to check if image needs resize + */ + _needsResize: function() { + return (this.scaleX !== this._lastScaleX || this.scaleY !== this._lastScaleY); + }, + + /** + * @private + */ + _findMargins: function() { + var width = this.width, height = this.height, scales, + scale, marginX = 0, marginY = 0; + + if (this.alignX !== 'none' || this.alignY !== 'none') { + scales = [this.width / this._element.width, this.height / this._element.height]; + scale = this.meetOrSlice === 'meet' + ? Math.min.apply(null, scales) : Math.max.apply(null, scales); + width = this._element.width * scale; + height = this._element.height * scale; + if (this.alignX === 'Mid') { + marginX = (this.width - width) / 2; + } + if (this.alignX === 'Max') { + marginX = this.width - width; + } + if (this.alignY === 'Mid') { + marginY = (this.height - height) / 2; + } + if (this.alignY === 'Max') { + marginY = this.height - height; + } + } + return { + width: width, + height: height, + marginX: marginX, + marginY: marginY + }; + }, + + /** + * @private + */ + _resetWidthHeight: function() { + var element = this.getElement(); + + this.set('width', element.width); + this.set('height', element.height); + }, + + /** + * The Image class's initialization method. This method is automatically + * called by the constructor. + * @private + * @param {HTMLImageElement|String} element The element representing the image + * @param {Object} [options] Options object + */ + _initElement: function(element, options, callback) { + this.setElement(fabric.util.getById(element), callback, options); + fabric.util.addClass(this.getElement(), fabric.Image.CSS_CANVAS); + }, + + /** + * @private + * @param {Object} [options] Options object + */ + _initConfig: function(options) { + options || (options = { }); + this.setOptions(options); + this._setWidthHeight(options); + if (this._element && this.crossOrigin) { + this._element.crossOrigin = this.crossOrigin; + } + }, + + /** + * @private + * @param {Array} filters to be initialized + * @param {Function} callback Callback to invoke when all fabric.Image.filters instances are created + */ + _initFilters: function(filters, callback) { + if (filters && filters.length) { + fabric.util.enlivenObjects(filters, function(enlivenedObjects) { + callback && callback(enlivenedObjects); + }, 'fabric.Image.filters'); + } + else { + callback && callback(); + } + }, + + /** + * @private + * @param {Object} [options] Object with width/height properties + */ + _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); + }, + }); + + /** + * Default CSS class name for canvas + * @static + * @type String + * @default + */ + fabric.Image.CSS_CANVAS = 'canvas-img'; + + /** + * Alias for getSrc + * @static + */ + fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc; + + /** + * 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 + */ + fabric.Image.fromObject = function(object, callback) { + fabric.util.loadImage(object.src, function(img, error) { + if (error) { + callback && callback(null, error); + return; + } + fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) { + object.filters = filters || []; + fabric.Image.prototype._initFilters.call(object, object.resizeFilters, function(resizeFilters) { + object.resizeFilters = resizeFilters || []; + return new fabric.Image(img, object, callback); + }); + }); + }, null, object.crossOrigin); + }; + + /** + * Creates an instance of fabric.Image from an URL string + * @static + * @param {String} url URL to create an image from + * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument) + * @param {Object} [imgOptions] Options object + */ + fabric.Image.fromURL = function(url, callback, imgOptions) { + fabric.util.loadImage(url, function(img) { + callback && callback(new fabric.Image(img, imgOptions)); + }, null, imgOptions && imgOptions.crossOrigin); + }; + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by {@link fabric.Image.fromElement}) + * @static + * @see {@link http://www.w3.org/TR/SVG/struct.html#ImageElement} + */ + fabric.Image.ATTRIBUTE_NAMES = + fabric.SHARED_ATTRIBUTES.concat('x y width height preserveAspectRatio xlink:href crossOrigin'.split(' ')); + + /** + * Returns {@link fabric.Image} instance from an SVG element + * @static + * @param {SVGElement} element Element to parse + * @param {Function} callback Callback to execute when fabric.Image object is created + * @param {Object} [options] Options object + * @return {fabric.Image} Instance of fabric.Image + */ + fabric.Image.fromElement = function(element, callback, options) { + var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES), + preserveAR; + + if (parsedAttributes.preserveAspectRatio) { + preserveAR = fabric.util.parsePreserveAspectRatioAttribute(parsedAttributes.preserveAspectRatio); + extend(parsedAttributes, preserveAR); + } + + fabric.Image.fromURL(parsedAttributes['xlink:href'], callback, + extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes)); + }; + /* _FROM_SVG_END_ */ + + /** + * Indicates that instances of this type are async + * @static + * @type Boolean + * @default + */ + fabric.Image.async = true; + + /** + * Indicates compression level used when generating PNG under Node (in applyFilters). Any of 0-9 + * @static + * @type Number + * @default + */ + fabric.Image.pngCompression = 1; + +})(typeof exports !== 'undefined' ? exports : this); + + +fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ { + + /** + * @private + * @return {Number} angle value + */ + _getAngleValueForStraighten: function() { + var angle = this.getAngle() % 360; + if (angle > 0) { + return Math.round((angle - 1) / 90) * 90; + } + return Math.round(angle / 90) * 90; + }, + + /** + * Straightens an object (rotating it from current angle to one of 0, 90, 180, 270, etc. depending on which is closer) + * @return {fabric.Object} thisArg + * @chainable + */ + straighten: function() { + this.setAngle(this._getAngleValueForStraighten()); + return this; + }, + + /** + * Same as {@link fabric.Object.prototype.straighten} but with animation + * @param {Object} callbacks Object with callback functions + * @param {Function} [callbacks.onComplete] Invoked on completion + * @param {Function} [callbacks.onChange] Invoked on every step of animation + * @return {fabric.Object} thisArg + * @chainable + */ + fxStraighten: function(callbacks) { + callbacks = callbacks || { }; + + var empty = function() { }, + onComplete = callbacks.onComplete || empty, + onChange = callbacks.onChange || empty, + _this = this; + + fabric.util.animate({ + startValue: this.get('angle'), + endValue: this._getAngleValueForStraighten(), + duration: this.FX_DURATION, + onChange: function(value) { + _this.setAngle(value); + onChange(); + }, + onComplete: function() { + _this.setCoords(); + onComplete(); + }, + onStart: function() { + _this.set('active', false); + } + }); + + return this; + } +}); + +fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ { + + /** + * Straightens object, then rerenders canvas + * @param {fabric.Object} object Object to straighten + * @return {fabric.Canvas} thisArg + * @chainable + */ + straightenObject: function (object) { + object.straighten(); + this.renderAll(); + return this; + }, + + /** + * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated + * @param {fabric.Object} object Object to straighten + * @return {fabric.Canvas} thisArg + * @chainable + */ + fxStraightenObject: function (object) { + object.fxStraighten({ + onChange: this.renderAll.bind(this) + }); + return this; + } +}); + + +/** + * @namespace fabric.Image.filters + * @memberOf fabric.Image + * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#image_filters} + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + */ +fabric.Image.filters = fabric.Image.filters || { }; + +/** + * Root filter class from which all filter classes inherit from + * @class fabric.Image.filters.BaseFilter + * @memberOf fabric.Image.filters + */ +fabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Image.filters.BaseFilter.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'BaseFilter', + + /** + * Constructor + * @param {Object} [options] Options object + */ + initialize: function(options) { + if (options) { + this.setOptions(options); + } + }, + + /** + * Sets filter's properties from options + * @param {Object} [options] Options object + */ + setOptions: function(options) { + for (var prop in options) { + this[prop] = options[prop]; + } + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return { type: this.type }; + }, + + /** + * Returns a JSON representation of an instance + * @return {Object} JSON + */ + toJSON: function() { + // delegate, not alias + return this.toObject(); + } +}); + +fabric.Image.filters.BaseFilter.fromObject = function(object, callback) { + var filter = new fabric.Image.filters[object.type](object); + callback && callback(filter); + return filter; +}; + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Brightness filter class + * @class fabric.Image.filters.Brightness + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Brightness#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Brightness({ + * brightness: 200 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Brightness = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Brightness', + + /** + * Constructor + * @memberOf fabric.Image.filters.Brightness.prototype + * @param {Object} [options] Options object + * @param {Number} [options.brightness=0] Value to brighten the image up (-255..255) + */ + initialize: function(options) { + options = options || { }; + this.brightness = options.brightness || 0; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + brightness = this.brightness; + + for (var i = 0, len = data.length; i < len; i += 4) { + data[i] += brightness; + data[i + 1] += brightness; + data[i + 2] += brightness; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + brightness: this.brightness + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Brightness} Instance of fabric.Image.filters.Brightness + */ + fabric.Image.filters.Brightness.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Adapted from html5rocks article + * @class fabric.Image.filters.Convolute + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Convolute#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example Sharpen filter + * var filter = new fabric.Image.filters.Convolute({ + * matrix: [ 0, -1, 0, + * -1, 5, -1, + * 0, -1, 0 ] + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + * @example Blur filter + * var filter = new fabric.Image.filters.Convolute({ + * matrix: [ 1/9, 1/9, 1/9, + * 1/9, 1/9, 1/9, + * 1/9, 1/9, 1/9 ] + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + * @example Emboss filter + * var filter = new fabric.Image.filters.Convolute({ + * matrix: [ 1, 1, 1, + * 1, 0.7, -1, + * -1, -1, -1 ] + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + * @example Emboss filter with opaqueness + * var filter = new fabric.Image.filters.Convolute({ + * opaque: true, + * matrix: [ 1, 1, 1, + * 1, 0.7, -1, + * -1, -1, -1 ] + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Convolute = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Convolute', + + /** + * Constructor + * @memberOf fabric.Image.filters.Convolute.prototype + * @param {Object} [options] Options object + * @param {Boolean} [options.opaque=false] Opaque value (true/false) + * @param {Array} [options.matrix] Filter matrix + */ + initialize: function(options) { + options = options || { }; + + this.opaque = options.opaque; + this.matrix = options.matrix || [ + 0, 0, 0, + 0, 1, 0, + 0, 0, 0 + ]; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + + var weights = this.matrix, + context = canvasEl.getContext('2d'), + pixels = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + + side = Math.round(Math.sqrt(weights.length)), + halfSide = Math.floor(side / 2), + src = pixels.data, + sw = pixels.width, + sh = pixels.height, + output = context.createImageData(sw, sh), + dst = output.data, + // go through the destination image pixels + alphaFac = this.opaque ? 1 : 0, + r, g, b, a, dstOff, + scx, scy, srcOff, wt; + + for (var y = 0; y < sh; y++) { + for (var x = 0; x < sw; x++) { + dstOff = (y * sw + x) * 4; + // calculate the weighed sum of the source image pixels that + // fall under the convolution matrix + r = 0; g = 0; b = 0; a = 0; + + for (var cy = 0; cy < side; cy++) { + for (var cx = 0; cx < side; cx++) { + scy = y + cy - halfSide; + scx = x + cx - halfSide; + + // eslint-disable-next-line max-depth + if (scy < 0 || scy > sh || scx < 0 || scx > sw) { + continue; + } + + srcOff = (scy * sw + scx) * 4; + wt = weights[cy * side + cx]; + + r += src[srcOff] * wt; + g += src[srcOff + 1] * wt; + b += src[srcOff + 2] * wt; + a += src[srcOff + 3] * wt; + } + } + dst[dstOff] = r; + dst[dstOff + 1] = g; + dst[dstOff + 2] = b; + dst[dstOff + 3] = a + alphaFac * (255 - a); + } + } + + context.putImageData(output, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + opaque: this.opaque, + matrix: this.matrix + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Convolute} Instance of fabric.Image.filters.Convolute + */ + fabric.Image.filters.Convolute.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * GradientTransparency filter class + * @class fabric.Image.filters.GradientTransparency + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.GradientTransparency#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.GradientTransparency({ + * threshold: 200 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + // eslint-disable-next-line max-len + filters.GradientTransparency = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.GradientTransparency.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'GradientTransparency', + + /** + * Constructor + * @memberOf fabric.Image.filters.GradientTransparency.prototype + * @param {Object} [options] Options object + * @param {Number} [options.threshold=100] Threshold value + */ + initialize: function(options) { + options = options || { }; + this.threshold = options.threshold || 100; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + threshold = this.threshold, + total = data.length; + + for (var i = 0, len = data.length; i < len; i += 4) { + data[i + 3] = threshold + 255 * (total - i) / total; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + threshold: this.threshold + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.GradientTransparency} Instance of fabric.Image.filters.GradientTransparency + */ + fabric.Image.filters.GradientTransparency.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Grayscale image filter class + * @class fabric.Image.filters.Grayscale + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Grayscale(); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Grayscale = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Grayscale', + + /** + * Applies filter to canvas element + * @memberOf fabric.Image.filters.Grayscale.prototype + * @param {Object} canvasEl Canvas element to apply filter to + */ + 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; + + while (index < len) { + average = (data[index] + data[index + 1] + data[index + 2]) / 3; + data[index] = average; + data[index + 1] = average; + data[index + 2] = average; + index += 4; + } + + context.putImageData(imageData, 0, 0); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale + */ + fabric.Image.filters.Grayscale.fromObject = function(object, callback) { + object = object || { }; + object.type = 'Grayscale'; + return fabric.Image.filters.BaseFilter.fromObject(object, callback); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Invert filter class + * @class fabric.Image.filters.Invert + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Invert(); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Invert = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Invert', + + /** + * Applies filter to canvas element + * @memberOf fabric.Image.filters.Invert.prototype + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + iLen = data.length, i; + + 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]; + } + + context.putImageData(imageData, 0, 0); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Invert} Instance of fabric.Image.filters.Invert + */ + fabric.Image.filters.Invert.fromObject = function(object, callback) { + object = object || { }; + object.type = 'Invert'; + return fabric.Image.filters.BaseFilter.fromObject(object, callback); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Mask filter class + * See http://resources.aleph-1.com/mask/ + * @class fabric.Image.filters.Mask + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Mask#initialize} for constructor definition + */ + filters.Mask = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Mask.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Mask', + + /** + * Constructor + * @memberOf fabric.Image.filters.Mask.prototype + * @param {Object} [options] Options object + * @param {fabric.Image} [options.mask] Mask image object + * @param {Number} [options.channel=0] Rgb channel (0, 1, 2 or 3) + */ + initialize: function(options) { + options = options || { }; + + this.mask = options.mask; + this.channel = [0, 1, 2, 3].indexOf(options.channel) > -1 ? options.channel : 0; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + if (!this.mask) { + return; + } + + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + maskEl = this.mask.getElement(), + maskCanvasEl = fabric.util.createCanvasElement(), + channel = this.channel, + i, + iLen = imageData.width * imageData.height * 4; + + maskCanvasEl.width = canvasEl.width; + maskCanvasEl.height = canvasEl.height; + + maskCanvasEl.getContext('2d').drawImage(maskEl, 0, 0, canvasEl.width, canvasEl.height); + + var maskImageData = maskCanvasEl.getContext('2d').getImageData(0, 0, canvasEl.width, canvasEl.height), + maskData = maskImageData.data; + + for (i = 0; i < iLen; i += 4) { + data[i + 3] = maskData[i + channel]; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + mask: this.mask.toObject(), + channel: this.channel + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] Callback to invoke when a mask filter instance is created + */ + fabric.Image.filters.Mask.fromObject = function(object, callback) { + fabric.util.loadImage(object.mask.src, function(img) { + object.mask = new fabric.Image(img, object.mask); + return fabric.Image.filters.BaseFilter.fromObject(object, callback); + }); + }; + + /** + * Indicates that instances of this type are async + * @static + * @type Boolean + * @default + */ + fabric.Image.filters.Mask.async = true; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Noise filter class + * @class fabric.Image.filters.Noise + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Noise#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Noise({ + * noise: 700 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Noise = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Noise', + + /** + * Constructor + * @memberOf fabric.Image.filters.Noise.prototype + * @param {Object} [options] Options object + * @param {Number} [options.noise=0] Noise value + */ + initialize: function(options) { + options = options || { }; + this.noise = options.noise || 0; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + noise = this.noise, rand; + + for (var i = 0, len = data.length; i < len; i += 4) { + + rand = (0.5 - Math.random()) * noise; + + data[i] += rand; + data[i + 1] += rand; + data[i + 2] += rand; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + noise: this.noise + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Noise} Instance of fabric.Image.filters.Noise + */ + fabric.Image.filters.Noise.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Pixelate filter class + * @class fabric.Image.filters.Pixelate + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Pixelate#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Pixelate({ + * blocksize: 8 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Pixelate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Pixelate', + + /** + * Constructor + * @memberOf fabric.Image.filters.Pixelate.prototype + * @param {Object} [options] Options object + * @param {Number} [options.blocksize=4] Blocksize for pixelate + */ + initialize: function(options) { + options = options || { }; + this.blocksize = options.blocksize || 4; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + iLen = imageData.height, + jLen = imageData.width, + index, i, j, r, g, b, a; + + for (i = 0; i < iLen; i += this.blocksize) { + for (j = 0; j < jLen; j += this.blocksize) { + + index = (i * 4) * jLen + (j * 4); + + r = data[index]; + g = data[index + 1]; + b = data[index + 2]; + a = data[index + 3]; + + /* + blocksize: 4 + + [1,x,x,x,1] + [x,x,x,x,1] + [x,x,x,x,1] + [x,x,x,x,1] + [1,1,1,1,1] + */ + + for (var _i = i, _ilen = i + this.blocksize; _i < _ilen; _i++) { + for (var _j = j, _jlen = j + this.blocksize; _j < _jlen; _j++) { + index = (_i * 4) * jLen + (_j * 4); + data[index] = r; + data[index + 1] = g; + data[index + 2] = b; + data[index + 3] = a; + } + } + } + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + blocksize: this.blocksize + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Pixelate} Instance of fabric.Image.filters.Pixelate + */ + fabric.Image.filters.Pixelate.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Remove white filter class + * @class fabric.Image.filters.RemoveWhite + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.RemoveWhite#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.RemoveWhite({ + * threshold: 40, + * distance: 140 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.RemoveWhite = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.RemoveWhite.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'RemoveWhite', + + /** + * Constructor + * @memberOf fabric.Image.filters.RemoveWhite.prototype + * @param {Object} [options] Options object + * @param {Number} [options.threshold=30] Threshold value + * @param {Number} [options.distance=20] Distance value + */ + initialize: function(options) { + options = options || { }; + this.threshold = options.threshold || 30; + this.distance = options.distance || 20; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + threshold = this.threshold, + distance = this.distance, + limit = 255 - threshold, + abs = Math.abs, + r, g, b; + + for (var i = 0, len = data.length; i < len; i += 4) { + r = data[i]; + g = data[i + 1]; + b = data[i + 2]; + + if (r > limit && + g > limit && + b > limit && + abs(r - g) < distance && + abs(r - b) < distance && + abs(g - b) < distance + ) { + data[i + 3] = 0; + } + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + threshold: this.threshold, + distance: this.distance + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.RemoveWhite} Instance of fabric.Image.filters.RemoveWhite + */ + fabric.Image.filters.RemoveWhite.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Sepia filter class + * @class fabric.Image.filters.Sepia + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Sepia(); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Sepia = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Sepia', + + /** + * Applies filter to canvas element + * @memberOf fabric.Image.filters.Sepia.prototype + * @param {Object} canvasEl Canvas element to apply filter to + */ + 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; + + 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; + data[i + 2] = avg + 255; + } + + context.putImageData(imageData, 0, 0); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Sepia} Instance of fabric.Image.filters.Sepia + */ + fabric.Image.filters.Sepia.fromObject = function(object, callback) { + object = object || { }; + object.type = 'Sepia'; + return new fabric.Image.filters.BaseFilter.fromObject(object, callback); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Sepia2 filter class + * @class fabric.Image.filters.Sepia2 + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Sepia2(); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Sepia2 = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Sepia2.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Sepia2', + + /** + * Applies filter to canvas element + * @memberOf fabric.Image.filters.Sepia.prototype + * @param {Object} canvasEl Canvas element to apply filter to + */ + 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; + + for (i = 0; i < iLen; i += 4) { + r = data[i]; + g = data[i + 1]; + b = data[i + 2]; + + data[i] = (r * 0.393 + g * 0.769 + b * 0.189 ) / 1.351; + data[i + 1] = (r * 0.349 + g * 0.686 + b * 0.168 ) / 1.203; + data[i + 2] = (r * 0.272 + g * 0.534 + b * 0.131 ) / 2.140; + } + + context.putImageData(imageData, 0, 0); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Sepia2} Instance of fabric.Image.filters.Sepia2 + */ + fabric.Image.filters.Sepia2.fromObject = function(object, callback) { + object = object || { }; + object.type = 'Sepia2'; + return new fabric.Image.filters.BaseFilter.fromObject(object, callback); + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Tint filter class + * Adapted from https://github.com/mezzoblue/PaintbrushJS + * @class fabric.Image.filters.Tint + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Tint#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example Tint filter with hex color and opacity + * var filter = new fabric.Image.filters.Tint({ + * color: '#3513B0', + * opacity: 0.5 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + * @example Tint filter with rgba color + * var filter = new fabric.Image.filters.Tint({ + * color: 'rgba(53, 21, 176, 0.5)' + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Tint = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Tint.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Tint', + + /** + * Constructor + * @memberOf fabric.Image.filters.Tint.prototype + * @param {Object} [options] Options object + * @param {String} [options.color=#000000] Color to tint the image with + * @param {Number} [options.opacity] Opacity value that controls the tint effect's transparency (0..1) + */ + initialize: function(options) { + options = options || { }; + + this.color = options.color || '#000000'; + this.opacity = typeof options.opacity !== 'undefined' + ? options.opacity + : new fabric.Color(this.color).getAlpha(); + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + iLen = data.length, i, + tintR, tintG, tintB, + r, g, b, alpha1, + source; + + source = new fabric.Color(this.color).getSource(); + + tintR = source[0] * this.opacity; + tintG = source[1] * this.opacity; + tintB = source[2] * this.opacity; + + alpha1 = 1 - this.opacity; + + for (i = 0; i < iLen; i += 4) { + r = data[i]; + g = data[i + 1]; + b = data[i + 2]; + + // alpha compositing + data[i] = tintR + r * alpha1; + data[i + 1] = tintG + g * alpha1; + data[i + 2] = tintB + b * alpha1; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + color: this.color, + opacity: this.opacity + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Tint} Instance of fabric.Image.filters.Tint + */ + fabric.Image.filters.Tint.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Multiply filter class + * Adapted from http://www.laurenscorijn.com/articles/colormath-basics + * @class fabric.Image.filters.Multiply + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @example Multiply filter with hex color + * var filter = new fabric.Image.filters.Multiply({ + * color: '#F0F' + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + * @example Multiply filter with rgb color + * var filter = new fabric.Image.filters.Multiply({ + * color: 'rgb(53, 21, 176)' + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Multiply = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Multiply.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Multiply', + + /** + * Constructor + * @memberOf fabric.Image.filters.Multiply.prototype + * @param {Object} [options] Options object + * @param {String} [options.color=#000000] Color to multiply the image pixels with + */ + initialize: function(options) { + options = options || { }; + + this.color = options.color || '#000000'; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + iLen = data.length, i, + source; + + source = new fabric.Color(this.color).getSource(); + + for (i = 0; i < iLen; i += 4) { + data[i] *= source[0] / 255; + data[i + 1] *= source[1] / 255; + data[i + 2] *= source[2] / 255; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + color: this.color + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Multiply} Instance of fabric.Image.filters.Multiply + */ + fabric.Image.filters.Multiply.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + 'use strict'; + + var fabric = global.fabric, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Color Blend filter class + * @class fabric.Image.filter.Blend + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @example + * var filter = new fabric.Image.filters.Blend({ + * color: '#000', + * mode: 'multiply' + * }); + * + * var filter = new fabric.Image.filters.Blend({ + * image: fabricImageObject, + * mode: 'multiply', + * alpha: 0.5 + * }); + + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + + filters.Blend = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blend.prototype */ { + type: 'Blend', + + initialize: function(options) { + options = options || {}; + this.color = options.color || '#000'; + this.image = options.image || false; + this.mode = options.mode || 'multiply'; + this.alpha = options.alpha || 1; + }, + + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + tr, tg, tb, + r, g, b, + _r, _g, _b, + source, + isImage = false; + + if (this.image) { + // Blend images + isImage = true; + + var _el = fabric.util.createCanvasElement(); + _el.width = this.image.width; + _el.height = this.image.height; + + var tmpCanvas = new fabric.StaticCanvas(_el); + tmpCanvas.add(this.image); + var context2 = tmpCanvas.getContext('2d'); + source = context2.getImageData(0, 0, tmpCanvas.width, tmpCanvas.height).data; + } + else { + // Blend color + source = new fabric.Color(this.color).getSource(); + + tr = source[0] * this.alpha; + tg = source[1] * this.alpha; + tb = source[2] * this.alpha; + } + + for (var i = 0, len = data.length; i < len; i += 4) { + + r = data[i]; + g = data[i + 1]; + b = data[i + 2]; + + if (isImage) { + tr = source[i] * this.alpha; + tg = source[i + 1] * this.alpha; + tb = source[i + 2] * this.alpha; + } + + switch (this.mode) { + case 'multiply': + data[i] = r * tr / 255; + data[i + 1] = g * tg / 255; + data[i + 2] = b * tb / 255; + break; + case 'screen': + data[i] = 1 - (1 - r) * (1 - tr); + data[i + 1] = 1 - (1 - g) * (1 - tg); + data[i + 2] = 1 - (1 - b) * (1 - tb); + break; + case 'add': + data[i] = Math.min(255, r + tr); + data[i + 1] = Math.min(255, g + tg); + data[i + 2] = Math.min(255, b + tb); + break; + case 'diff': + case 'difference': + data[i] = Math.abs(r - tr); + data[i + 1] = Math.abs(g - tg); + data[i + 2] = Math.abs(b - tb); + break; + case 'subtract': + _r = r - tr; + _g = g - tg; + _b = b - tb; + + data[i] = (_r < 0) ? 0 : _r; + data[i + 1] = (_g < 0) ? 0 : _g; + data[i + 2] = (_b < 0) ? 0 : _b; + break; + case 'darken': + data[i] = Math.min(r, tr); + data[i + 1] = Math.min(g, tg); + data[i + 2] = Math.min(b, tb); + break; + case 'lighten': + data[i] = Math.max(r, tr); + data[i + 1] = Math.max(g, tg); + data[i + 2] = Math.max(b, tb); + break; + } + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return { + color: this.color, + image: this.image, + mode: this.mode, + alpha: this.alpha + }; + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Blend} Instance of fabric.Image.filters.Blend + */ + fabric.Image.filters.Blend.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(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, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Resize image filter class + * @class fabric.Image.filters.Resize + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Resize(); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Resize = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Resize.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Resize', + + /** + * Resize type + * @param {String} resizeType + * @default + */ + resizeType: 'hermite', + + /** + * Scale factor for resizing, x axis + * @param {Number} scaleX + * @default + */ + scaleX: 0, + + /** + * Scale factor for resizing, y axis + * @param {Number} scaleY + * @default + */ + scaleY: 0, + + /** + * LanczosLobes parameter for lanczos filter + * @param {Number} lanczosLobes + * @default + */ + lanczosLobes: 3, + + /** + * Applies filter to canvas element + * @memberOf fabric.Image.filters.Resize.prototype + * @param {Object} canvasEl Canvas element to apply filter to + * @param {Number} scaleX + * @param {Number} scaleY + */ + applyTo: function(canvasEl, scaleX, scaleY) { + if (scaleX === 1 && scaleY === 1) { + return; + } + + this.rcpScaleX = 1 / scaleX; + this.rcpScaleY = 1 / scaleY; + + var oW = canvasEl.width, oH = canvasEl.height, + dW = round(oW * scaleX), dH = round(oH * scaleY), + imageData; + + if (this.resizeType === 'sliceHack') { + imageData = this.sliceByTwo(canvasEl, oW, oH, dW, dH); + } + if (this.resizeType === 'hermite') { + imageData = this.hermiteFastResize(canvasEl, oW, oH, dW, dH); + } + if (this.resizeType === 'bilinear') { + imageData = this.bilinearFiltering(canvasEl, oW, oH, dW, dH); + } + if (this.resizeType === 'lanczos') { + imageData = this.lanczosResize(canvasEl, oW, oH, dW, dH); + } + canvasEl.width = dW; + canvasEl.height = dH; + canvasEl.getContext('2d').putImageData(imageData, 0, 0); + }, + + /** + * Filter sliceByTwo + * @param {Object} canvasEl Canvas element to apply filter to + * @param {Number} oW Original Width + * @param {Number} oH Original Height + * @param {Number} dW Destination Width + * @param {Number} dH Destination Height + * @returns {ImageData} + */ + sliceByTwo: function(canvasEl, oW, oH, dW, dH) { + var context = canvasEl.getContext('2d'), imageData, + multW = 0.5, multH = 0.5, signW = 1, signH = 1, + doneW = false, doneH = false, stepW = oW, stepH = oH, + tmpCanvas = fabric.util.createCanvasElement(), + tmpCtx = tmpCanvas.getContext('2d'); + dW = floor(dW); + dH = floor(dH); + tmpCanvas.width = max(dW, oW); + tmpCanvas.height = max(dH, oH); + + if (dW > oW) { + multW = 2; + signW = -1; + } + if (dH > oH) { + multH = 2; + signH = -1; + } + imageData = context.getImageData(0, 0, oW, oH); + canvasEl.width = max(dW, oW); + canvasEl.height = max(dH, oH); + context.putImageData(imageData, 0, 0); + + while (!doneW || !doneH) { + oW = stepW; + oH = stepH; + if (dW * signW < floor(stepW * multW * signW)) { + stepW = floor(stepW * multW); + } + else { + stepW = dW; + doneW = true; + } + if (dH * signH < floor(stepH * multH * signH)) { + stepH = floor(stepH * multH); + } + else { + stepH = dH; + doneH = true; + } + imageData = context.getImageData(0, 0, oW, oH); + tmpCtx.putImageData(imageData, 0, 0); + context.clearRect(0, 0, stepW, stepH); + context.drawImage(tmpCanvas, 0, 0, oW, oH, 0, 0, stepW, stepH); + } + return context.getImageData(0, 0, dW, dH); + }, + + /** + * Filter lanczosResize + * @param {Object} canvasEl Canvas element to apply filter to + * @param {Number} oW Original Width + * @param {Number} oH Original Height + * @param {Number} dW Destination Width + * @param {Number} dH Destination Height + * @returns {ImageData} + */ + lanczosResize: function(canvasEl, oW, oH, dW, dH) { + + function lanczosCreate(lobes) { + return function(x) { + if (x > lobes) { + return 0; + } + x *= Math.PI; + if (abs(x) < 1e-16) { + return 1; + } + var xx = x / lobes; + return sin(x) * sin(xx) / x / xx; + }; + } + + function process(u) { + var v, i, weight, idx, a, red, green, + blue, alpha, fX, fY; + center.x = (u + 0.5) * ratioX; + icenter.x = floor(center.x); + 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; + for (i = icenter.x - range2X; i <= icenter.x + range2X; i++) { + if (i < 0 || i >= oW) { + continue; + } + fX = floor(1000 * abs(i - center.x)); + if (!cacheLanc[fX]) { + cacheLanc[fX] = { }; + } + for (var j = icenter.y - range2Y; j <= icenter.y + range2Y; j++) { + if (j < 0 || j >= oH) { + continue; + } + fY = floor(1000 * abs(j - center.y)); + if (!cacheLanc[fX][fY]) { + cacheLanc[fX][fY] = lanczos(sqrt(pow(fX * rcpRatioX, 2) + pow(fY * rcpRatioY, 2)) / 1000); + } + weight = cacheLanc[fX][fY]; + if (weight > 0) { + idx = (j * oW + i) * 4; + a += weight; + red += weight * srcData[idx]; + green += weight * srcData[idx + 1]; + blue += weight * srcData[idx + 2]; + alpha += weight * srcData[idx + 3]; + } + } + } + idx = (v * dW + u) * 4; + destData[idx] = red / a; + destData[idx + 1] = green / a; + destData[idx + 2] = blue / a; + destData[idx + 3] = alpha / a; + } + + if (++u < dW) { + return process(u); + } + else { + return destImg; + } + } + + var context = canvasEl.getContext('2d'), + srcImg = context.getImageData(0, 0, oW, oH), + destImg = context.getImageData(0, 0, dW, dH), + srcData = srcImg.data, destData = destImg.data, + lanczos = lanczosCreate(this.lanczosLobes), + ratioX = this.rcpScaleX, ratioY = this.rcpScaleY, + rcpRatioX = 2 / this.rcpScaleX, rcpRatioY = 2 / this.rcpScaleY, + range2X = ceil(ratioX * this.lanczosLobes / 2), + range2Y = ceil(ratioY * this.lanczosLobes / 2), + cacheLanc = { }, center = { }, icenter = { }; + + return process(0); + }, + + /** + * bilinearFiltering + * @param {Object} canvasEl Canvas element to apply filter to + * @param {Number} oW Original Width + * @param {Number} oH Original Height + * @param {Number} dW Destination Width + * @param {Number} dH Destination Height + * @returns {ImageData} + */ + bilinearFiltering: function(canvasEl, oW, oH, dW, dH) { + var a, b, c, d, x, y, i, j, xDiff, yDiff, chnl, + color, offset = 0, origPix, ratioX = this.rcpScaleX, + ratioY = this.rcpScaleY, context = canvasEl.getContext('2d'), + w4 = 4 * (oW - 1), img = context.getImageData(0, 0, oW, oH), + pixels = img.data, destImage = context.getImageData(0, 0, dW, dH), + destPixels = destImage.data; + for (i = 0; i < dH; i++) { + for (j = 0; j < dW; j++) { + x = floor(ratioX * j); + y = floor(ratioY * i); + xDiff = ratioX * j - x; + yDiff = ratioY * i - y; + origPix = 4 * (y * oW + x); + + for (chnl = 0; chnl < 4; chnl++) { + a = pixels[origPix + chnl]; + b = pixels[origPix + 4 + chnl]; + c = pixels[origPix + w4 + chnl]; + d = pixels[origPix + w4 + 4 + chnl]; + color = a * (1 - xDiff) * (1 - yDiff) + b * xDiff * (1 - yDiff) + + c * yDiff * (1 - xDiff) + d * xDiff * yDiff; + destPixels[offset++] = color; + } + } + } + return destImage; + }, + + /** + * hermiteFastResize + * @param {Object} canvasEl Canvas element to apply filter to + * @param {Number} oW Original Width + * @param {Number} oH Original Height + * @param {Number} dW Destination Width + * @param {Number} dH Destination Height + * @returns {ImageData} + */ + hermiteFastResize: function(canvasEl, oW, oH, dW, dH) { + var ratioW = this.rcpScaleX, ratioH = this.rcpScaleY, + ratioWHalf = ceil(ratioW / 2), + ratioHHalf = ceil(ratioH / 2), + context = canvasEl.getContext('2d'), + img = context.getImageData(0, 0, oW, oH), data = img.data, + img2 = context.getImageData(0, 0, dW, dH), data2 = img2.data; + for (var j = 0; j < dH; j++) { + for (var i = 0; i < dW; i++) { + var x2 = (i + j * dW) * 4, weight = 0, weights = 0, weightsAlpha = 0, + gxR = 0, gxG = 0, gxB = 0, gxA = 0, centerY = (j + 0.5) * ratioH; + for (var yy = floor(j * ratioH); yy < (j + 1) * ratioH; yy++) { + var dy = abs(centerY - (yy + 0.5)) / ratioHHalf, + centerX = (i + 0.5) * ratioW, w0 = dy * dy; + for (var xx = floor(i * ratioW); xx < (i + 1) * ratioW; xx++) { + var dx = abs(centerX - (xx + 0.5)) / ratioWHalf, + w = sqrt(w0 + dx * dx); + /* eslint-disable max-depth */ + if (w > 1 && w < -1) { + continue; + } + //hermite filter + weight = 2 * w * w * w - 3 * w * w + 1; + if (weight > 0) { + dx = 4 * (xx + yy * oW); + //alpha + gxA += weight * data[dx + 3]; + weightsAlpha += weight; + //colors + if (data[dx + 3] < 255) { + weight = weight * data[dx + 3] / 250; + } + gxR += weight * data[dx]; + gxG += weight * data[dx + 1]; + gxB += weight * data[dx + 2]; + weights += weight; + } + /* eslint-enable max-depth */ + } + } + data2[x2] = gxR / weights; + data2[x2 + 1] = gxG / weights; + data2[x2 + 2] = gxB / weights; + data2[x2 + 3] = gxA / weightsAlpha; + } + } + return img2; + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return { + type: this.type, + scaleX: this.scaleX, + scaleY: this.scaleY, + resizeType: this.resizeType, + lanczosLobes: this.lanczosLobes + }; + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Resize} Instance of fabric.Image.filters.Resize + */ + fabric.Image.filters.Resize.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Color Matrix filter class + * @class fabric.Image.filters.ColorMatrix + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.ColorMatrix#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @see {@Link http://www.webwasp.co.uk/tutorials/219/Color_Matrix_Filter.php} + * @see {@Link http://phoboslab.org/log/2013/11/fast-image-filters-with-webgl} + * @example Kodachrome filter + * var filter = new fabric.Image.filters.ColorMatrix({ + * matrix: [ + 1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502, + -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203, + -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946, + 0, 0, 0, 1, 0 + ] + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.ColorMatrix = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.ColorMatrix.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'ColorMatrix', + + /** + * Constructor + * @memberOf fabric.Image.filters.ColorMatrix.prototype + * @param {Object} [options] Options object + * @param {Array} [options.matrix] Color Matrix to modify the image data with + */ + 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 + ]; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + 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; + + for ( i = 0; i < iLen; i += 4 ) { + r = data[ i ]; + g = data[ i + 1 ]; + b = data[ i + 2 ]; + a = data[ i + 3 ]; + + data[ i ] = r * m[ 0 ] + g * m[ 1 ] + b * m[ 2 ] + a * m[ 3 ] + m[ 4 ]; + data[ i + 1 ] = r * m[ 5 ] + g * m[ 6 ] + b * m[ 7 ] + a * m[ 8 ] + m[ 9 ]; + data[ i + 2 ] = r * m[ 10 ] + g * m[ 11 ] + b * m[ 12 ] + a * m[ 13 ] + m[ 14 ]; + data[ i + 3 ] = r * m[ 15 ] + g * m[ 16 ] + b * m[ 17 ] + a * m[ 18 ] + m[ 19 ]; + } + + context.putImageData( imageData, 0, 0 ); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + type: this.type, + matrix: this.matrix + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] function to invoke after filter creation + * @return {fabric.Image.filters.ColorMatrix} Instance of fabric.Image.filters.ColorMatrix + */ + fabric.Image.filters.ColorMatrix.fromObject = fabric.Image.filters.BaseFilter.fromObject; +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Contrast filter class + * @class fabric.Image.filters.Contrast + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Contrast#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Contrast({ + * contrast: 40 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Contrast = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Contrast.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Contrast', + + /** + * Constructor + * @memberOf fabric.Image.filters.Contrast.prototype + * @param {Object} [options] Options object + * @param {Number} [options.contrast=0] Value to contrast the image up (-255...255) + */ + initialize: function(options) { + options = options || { }; + this.contrast = options.contrast || 0; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + contrastF = 259 * (this.contrast + 255) / (255 * (259 - this.contrast)); + + for (var i = 0, len = data.length; i < len; i += 4) { + data[i] = contrastF * (data[i] - 128) + 128; + data[i + 1] = contrastF * (data[i + 1] - 128) + 128; + data[i + 2] = contrastF * (data[i + 2] - 128) + 128; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + contrast: this.contrast + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Contrast} Instance of fabric.Image.filters.Contrast + */ + fabric.Image.filters.Contrast.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + extend = fabric.util.object.extend, + filters = fabric.Image.filters, + createClass = fabric.util.createClass; + + /** + * Saturate filter class + * @class fabric.Image.filters.Saturate + * @memberOf fabric.Image.filters + * @extends fabric.Image.filters.BaseFilter + * @see {@link fabric.Image.filters.Saturate#initialize} for constructor definition + * @see {@link http://fabricjs.com/image-filters|ImageFilters demo} + * @example + * var filter = new fabric.Image.filters.Saturate({ + * saturate: 100 + * }); + * object.filters.push(filter); + * object.applyFilters(canvas.renderAll.bind(canvas)); + */ + filters.Saturate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Saturate.prototype */ { + + /** + * Filter type + * @param {String} type + * @default + */ + type: 'Saturate', + + /** + * Constructor + * @memberOf fabric.Image.filters.Saturate.prototype + * @param {Object} [options] Options object + * @param {Number} [options.saturate=0] Value to saturate the image (-100...100) + */ + initialize: function(options) { + options = options || { }; + this.saturate = options.saturate || 0; + }, + + /** + * Applies filter to canvas element + * @param {Object} canvasEl Canvas element to apply filter to + */ + applyTo: function(canvasEl) { + var context = canvasEl.getContext('2d'), + imageData = context.getImageData(0, 0, canvasEl.width, canvasEl.height), + data = imageData.data, + max, adjust = -this.saturate * 0.01; + + for (var i = 0, len = data.length; i < len; i += 4) { + max = Math.max(data[i], data[i + 1], data[i + 2]); + data[i] += max !== data[i] ? (max - data[i]) * adjust : 0; + data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * adjust : 0; + data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * adjust : 0; + } + + context.putImageData(imageData, 0, 0); + }, + + /** + * Returns object representation of an instance + * @return {Object} Object representation of an instance + */ + toObject: function() { + return extend(this.callSuper('toObject'), { + saturate: this.saturate + }); + } + }); + + /** + * Returns filter instance from an object representation + * @static + * @param {Object} object Object to create an instance from + * @param {Function} [callback] to be invoked after filter creation + * @return {fabric.Image.filters.Saturate} Instance of fabric.Image.filters.Saturate + */ + fabric.Image.filters.Saturate.fromObject = fabric.Image.filters.BaseFilter.fromObject; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = { }), + 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; + } + + /** + * Text class + * @class fabric.Text + * @extends fabric.Object + * @return {fabric.Text} thisArg + * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text} + * @see {@link fabric.Text#initialize} for constructor definition + */ + fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ { + + /** + * Properties which when set cause object to change dimensions + * @type Object + * @private + */ + _dimensionAffectingProps: [ + 'fontSize', + 'fontWeight', + 'fontFamily', + 'fontStyle', + 'lineHeight', + 'text', + 'charSpacing', + 'textAlign' + ], + + /** + * @private + */ + _reNewline: /\r?\n/, + + /** + * Use this regular expression to filter for whitespace that is not a new line. + * Mostly used when text is 'justify' aligned. + * @private + */ + _reSpacesAndTabs: /[ \t\r]+/g, + + /** + * Retrieves object's fontSize + * @method getFontSize + * @memberOf fabric.Text.prototype + * @return {String} Font size (in pixels) + */ + + /** + * Sets object's fontSize + * Does not update the object .width and .height, + * call ._initDimensions() to update the values. + * @method setFontSize + * @memberOf fabric.Text.prototype + * @param {Number} fontSize Font size (in pixels) + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's fontWeight + * @method getFontWeight + * @memberOf fabric.Text.prototype + * @return {(String|Number)} Font weight + */ + + /** + * Sets object's fontWeight + * Does not update the object .width and .height, + * call ._initDimensions() to update the values. + * @method setFontWeight + * @memberOf fabric.Text.prototype + * @param {(Number|String)} fontWeight Font weight + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's fontFamily + * @method getFontFamily + * @memberOf fabric.Text.prototype + * @return {String} Font family + */ + + /** + * Sets object's fontFamily + * Does not update the object .width and .height, + * call ._initDimensions() to update the values. + * @method setFontFamily + * @memberOf fabric.Text.prototype + * @param {String} fontFamily Font family + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's text + * @method getText + * @memberOf fabric.Text.prototype + * @return {String} text + */ + + /** + * Sets object's text + * Does not update the object .width and .height, + * call ._initDimensions() to update the values. + * @method setText + * @memberOf fabric.Text.prototype + * @param {String} text Text + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's textDecoration + * @method getTextDecoration + * @memberOf fabric.Text.prototype + * @return {String} Text decoration + */ + + /** + * Sets object's textDecoration + * @method setTextDecoration + * @memberOf fabric.Text.prototype + * @param {String} textDecoration Text decoration + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's fontStyle + * @method getFontStyle + * @memberOf fabric.Text.prototype + * @return {String} Font style + */ + + /** + * Sets object's fontStyle + * Does not update the object .width and .height, + * call ._initDimensions() to update the values. + * @method setFontStyle + * @memberOf fabric.Text.prototype + * @param {String} fontStyle Font style + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's lineHeight + * @method getLineHeight + * @memberOf fabric.Text.prototype + * @return {Number} Line height + */ + + /** + * Sets object's lineHeight + * @method setLineHeight + * @memberOf fabric.Text.prototype + * @param {Number} lineHeight Line height + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's textAlign + * @method getTextAlign + * @memberOf fabric.Text.prototype + * @return {String} Text alignment + */ + + /** + * Sets object's textAlign + * @method setTextAlign + * @memberOf fabric.Text.prototype + * @param {String} textAlign Text alignment + * @return {fabric.Text} + * @chainable + */ + + /** + * Retrieves object's textBackgroundColor + * @method getTextBackgroundColor + * @memberOf fabric.Text.prototype + * @return {String} Text background color + */ + + /** + * Sets object's textBackgroundColor + * @method setTextBackgroundColor + * @memberOf fabric.Text.prototype + * @param {String} textBackgroundColor Text background color + * @return {fabric.Text} + * @chainable + */ + + /** + * Type of an object + * @type String + * @default + */ + type: 'text', + + /** + * Font size (in pixels) + * @type Number + * @default + */ + fontSize: 40, + + /** + * Font weight (e.g. bold, normal, 400, 600, 800) + * @type {(Number|String)} + * @default + */ + fontWeight: 'normal', + + /** + * Font family + * @type String + * @default + */ + fontFamily: 'Times New Roman', + + /** + * Text decoration Possible values: "", "underline", "overline" or "line-through". + * @type String + * @default + */ + textDecoration: '', + + /** + * Text alignment. Possible values: "left", "center", "right" or "justify". + * @type String + * @default + */ + textAlign: 'left', + + /** + * Font style . Possible values: "", "normal", "italic" or "oblique". + * @type String + * @default + */ + fontStyle: '', + + /** + * Line height + * @type Number + * @default + */ + lineHeight: 1.16, + + /** + * Background color of text lines + * @type String + * @default + */ + textBackgroundColor: '', + + /** + * 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: fabric.Object.prototype.stateProperties.concat( + 'fontFamily', + 'fontWeight', + 'fontSize', + 'text', + 'textDecoration', + 'textAlign', + 'fontStyle', + 'lineHeight', + 'textBackgroundColor', + 'charSpacing'), + + /** + * List of properties to consider when checking if cache needs refresh + * @type Array + */ + cacheProperties: fabric.Object.prototype.cacheProperties.concat( + 'fontFamily', + 'fontWeight', + 'fontSize', + 'text', + 'textDecoration', + 'textAlign', + 'fontStyle', + 'lineHeight', + 'textBackgroundColor', + 'charSpacing', + 'styles'), + + /** + * When defined, an object is rendered via stroke and this property specifies its color. + * Backwards incompatibility note: This property was named "strokeStyle" until v1.1.6 + * @type String + * @default + */ + stroke: null, + + /** + * Shadow object representing shadow of this shape. + * Backwards incompatibility note: This property was named "textShadow" (String) until v1.2.11 + * @type fabric.Shadow + * @default + */ + shadow: null, + + /** + * @private + */ + _fontSizeFraction: 0.25, + + /** + * Text Line proportion to font Size (in pixels) + * @type Number + * @default + */ + _fontSizeMult: 1.13, + + /** + * additional space between characters + * expressed in thousands of em unit + * @type Number + * @default + */ + charSpacing: 0, + + /** + * Constructor + * @param {String} text Text string + * @param {Object} [options] Options object + * @return {fabric.Text} thisArg + */ + initialize: function(text, options) { + options = options || { }; + this.text = text; + this.__skipDimension = true; + this.callSuper('initialize', options); + this.__skipDimension = false; + this._initDimensions(); + this.setCoords(); + this.setupState({ propertySet: '_dimensionAffectingProps' }); + }, + + /** + * Initialize text dimensions. Render all text on given context + * or on a offscreen canvas to get the text width with measureText. + * Updates this.width and this.height with the proper values. + * Does not return dimensions. + * @param {CanvasRenderingContext2D} [ctx] Context to render on + * @private + */ + _initDimensions: function(ctx) { + if (this.__skipDimension) { + return; + } + if (!ctx) { + ctx = fabric.util.createCanvasElement().getContext('2d'); + this._setTextStyles(ctx); + } + this._textLines = this._splitTextIntoLines(); + this._clearCache(); + this.width = this._getTextWidth(ctx) || this.cursorWidth || MIN_TEXT_WIDTH; + this.height = this._getTextHeight(ctx); + this.setCoords(); + }, + + /** + * Returns string representation of an instance + * @return {String} String representation of text object + */ + toString: function() { + return '#'; + }, + + /** + * Return the dimension and the zoom level needed to create a cache canvas + * big enough to host the object to be cached. + * @private + * @param {Object} dim.x width of object to be cached + * @param {Object} dim.y height of object to be cached + * @return {Object}.width width of canvas + * @return {Object}.height height of canvas + * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache + * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache + */ + _getCacheCanvasDimensions: function() { + var dims = this.callSuper('_getCacheCanvasDimensions'); + var fontSize = this.fontSize; + dims.width += fontSize * dims.zoomX; + dims.height += fontSize * dims.zoomY; + return dims; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _render: function(ctx) { + this._setTextStyles(ctx); + if (this.group && this.group.type === 'path-group') { + ctx.translate(this.left, this.top); + } + this._renderTextLinesBackground(ctx); + this._renderText(ctx); + this._renderTextDecoration(ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderText: function(ctx) { + this._renderTextFill(ctx); + this._renderTextStroke(ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _setTextStyles: function(ctx) { + ctx.textBaseline = 'alphabetic'; + ctx.font = this._getFontDeclaration(); + }, + + /** + * @private + * @return {Number} Height of fabric.Text object + */ + _getTextHeight: function() { + return this._getHeightOfSingleLine() + (this._textLines.length - 1) * this._getHeightOfLine(); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @return {Number} Maximum width of fabric.Text object + */ + _getTextWidth: function(ctx) { + var maxWidth = this._getLineWidth(ctx, 0); + + for (var i = 1, len = this._textLines.length; i < len; i++) { + var currentLineWidth = this._getLineWidth(ctx, i); + if (currentLineWidth > maxWidth) { + maxWidth = currentLineWidth; + } + } + return maxWidth; + }, + + /** + * @private + * @param {String} method Method name ("fillText" or "strokeText") + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} chars Chars to render + * @param {Number} left Left position of text + * @param {Number} top Top position of text + */ + _renderChars: function(method, ctx, chars, left, top) { + // remove Text word from method var + var shortM = method.slice(0, -4), _char, width; + if (this[shortM].toLive) { + var offsetX = -this.width / 2 + this[shortM].offsetX || 0, + offsetY = -this.height / 2 + this[shortM].offsetY || 0; + ctx.save(); + ctx.translate(offsetX, offsetY); + left -= offsetX; + top -= offsetY; + } + if (this.charSpacing !== 0) { + var additionalSpace = this._getWidthOfCharSpacing(); + chars = chars.split(''); + for (var i = 0, len = chars.length; i < len; i++) { + _char = chars[i]; + width = ctx.measureText(_char).width + additionalSpace; + ctx[method](_char, left, top); + left += width > 0 ? width : 0; + } + } + else { + ctx[method](chars, left, top); + } + this[shortM].toLive && ctx.restore(); + }, + + /** + * @private + * @param {String} method Method name ("fillText" or "strokeText") + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} line Text to render + * @param {Number} left Left position of text + * @param {Number} top Top position of text + * @param {Number} lineIndex Index of a line in a text + */ + _renderTextLine: function(method, ctx, line, left, top, lineIndex) { + // lift the line by quarter of fontSize + top -= this.fontSize * this._fontSizeFraction; + + // short-circuit + var lineWidth = this._getLineWidth(ctx, lineIndex); + if (this.textAlign !== 'justify' || this.width < lineWidth) { + this._renderChars(method, ctx, line, left, top, lineIndex); + return; + } + + // stretch the line + var words = line.split(/\s+/), + charOffset = 0, + wordsWidth = this._getWidthOfWords(ctx, words.join(' '), lineIndex, 0), + widthDiff = this.width - wordsWidth, + numSpaces = words.length - 1, + spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0, + leftOffset = 0, word; + + for (var i = 0, len = words.length; i < len; i++) { + while (line[charOffset] === ' ' && charOffset < line.length) { + charOffset++; + } + word = words[i]; + this._renderChars(method, ctx, word, left + leftOffset, top, lineIndex, charOffset); + leftOffset += this._getWidthOfWords(ctx, word, lineIndex, charOffset) + spaceWidth; + charOffset += word.length; + } + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} word + */ + _getWidthOfWords: function (ctx, word) { + var width = ctx.measureText(word).width, charCount, additionalSpace; + if (this.charSpacing !== 0) { + charCount = word.split('').length; + additionalSpace = charCount * this._getWidthOfCharSpacing(); + width += additionalSpace; + } + return width > 0 ? width : 0; + }, + + /** + * @private + * @return {Number} Left offset + */ + _getLeftOffset: function() { + return -this.width / 2; + }, + + /** + * @private + * @return {Number} Top offset + */ + _getTopOffset: function() { + return -this.height / 2; + }, + + /** + * Returns true because text has no style + */ + isEmptyStyles: function() { + return true; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} method Method name ("fillText" or "strokeText") + */ + _renderTextCommon: function(ctx, method) { + + var lineHeights = 0, left = this._getLeftOffset(), top = this._getTopOffset(); + + for (var i = 0, len = this._textLines.length; i < len; i++) { + var heightOfLine = this._getHeightOfLine(ctx, i), + maxHeight = heightOfLine / this.lineHeight, + lineWidth = this._getLineWidth(ctx, i), + leftOffset = this._getLineLeftOffset(lineWidth); + this._renderTextLine( + method, + ctx, + this._textLines[i], + left + leftOffset, + top + lineHeights + maxHeight, + i + ); + lineHeights += heightOfLine; + } + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderTextFill: function(ctx) { + if (!this.fill && this.isEmptyStyles()) { + return; + } + + this._renderTextCommon(ctx, 'fillText'); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderTextStroke: function(ctx) { + if ((!this.stroke || this.strokeWidth === 0) && this.isEmptyStyles()) { + return; + } + + if (this.shadow && !this.shadow.affectStroke) { + this._removeShadow(ctx); + } + + ctx.save(); + this._setLineDash(ctx, this.strokeDashArray); + ctx.beginPath(); + this._renderTextCommon(ctx, 'strokeText'); + ctx.closePath(); + ctx.restore(); + }, + + /** + * @private + * @return {Number} height of line + */ + _getHeightOfLine: function() { + return this._getHeightOfSingleLine() * this.lineHeight; + }, + + /** + * @private + * @return {Number} height of line without lineHeight + */ + _getHeightOfSingleLine: function() { + return this.fontSize * this._fontSizeMult; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderTextLinesBackground: function(ctx) { + if (!this.textBackgroundColor) { + return; + } + var lineTopOffset = 0, heightOfLine, + lineWidth, lineLeftOffset, originalFill = ctx.fillStyle; + + ctx.fillStyle = this.textBackgroundColor; + for (var i = 0, len = this._textLines.length; i < len; i++) { + heightOfLine = this._getHeightOfLine(ctx, i); + lineWidth = this._getLineWidth(ctx, i); + if (lineWidth > 0) { + lineLeftOffset = this._getLineLeftOffset(lineWidth); + ctx.fillRect( + this._getLeftOffset() + lineLeftOffset, + this._getTopOffset() + lineTopOffset, + lineWidth, + heightOfLine / this.lineHeight + ); + } + lineTopOffset += heightOfLine; + } + ctx.fillStyle = originalFill; + // if there is text background color no + // other shadows should be casted + this._removeShadow(ctx); + }, + + /** + * @private + * @param {Number} lineWidth Width of text line + * @return {Number} Line left offset + */ + _getLineLeftOffset: function(lineWidth) { + if (this.textAlign === 'center') { + return (this.width - lineWidth) / 2; + } + if (this.textAlign === 'right') { + return this.width - lineWidth; + } + return 0; + }, + + /** + * @private + */ + _clearCache: function() { + this.__lineWidths = []; + this.__lineHeights = []; + }, + + /** + * @private + */ + _shouldClearDimensionCache: function() { + var shouldClear = this._forceClearCache; + shouldClear || (shouldClear = this.hasStateChanged('_dimensionAffectingProps')); + if (shouldClear) { + this.saveState({ propertySet: '_dimensionAffectingProps' }); + this.dirty = true; + } + return shouldClear; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Number} lineIndex line number + * @return {Number} Line width + */ + _getLineWidth: function(ctx, lineIndex) { + if (this.__lineWidths[lineIndex]) { + return this.__lineWidths[lineIndex] === -1 ? this.width : this.__lineWidths[lineIndex]; + } + + var width, wordCount, line = this._textLines[lineIndex]; + + if (line === '') { + width = 0; + } + else { + width = this._measureLine(ctx, lineIndex); + } + this.__lineWidths[lineIndex] = width; + + if (width && this.textAlign === 'justify') { + wordCount = line.split(/\s+/); + if (wordCount.length > 1) { + this.__lineWidths[lineIndex] = -1; + } + } + return width; + }, + + _getWidthOfCharSpacing: function() { + if (this.charSpacing !== 0) { + return this.fontSize * this.charSpacing / 1000; + } + return 0; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Number} lineIndex line number + * @return {Number} Line width + */ + _measureLine: function(ctx, lineIndex) { + var line = this._textLines[lineIndex], + width = ctx.measureText(line).width, + additionalSpace = 0, charCount, finalWidth; + if (this.charSpacing !== 0) { + charCount = line.split('').length; + additionalSpace = (charCount - 1) * this._getWidthOfCharSpacing(); + } + finalWidth = width + additionalSpace; + return finalWidth > 0 ? finalWidth : 0; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderTextDecoration: function(ctx) { + if (!this.textDecoration) { + return; + } + var halfOfVerticalBox = this.height / 2, + _this = this, offsets = []; + + /** @ignore */ + 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); + 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); + } + lineHeight += heightOfLine; + } + } + + if (this.textDecoration.indexOf('underline') > -1) { + offsets.push(0.85); // 1 - 3/16 + } + if (this.textDecoration.indexOf('line-through') > -1) { + offsets.push(0.43); + } + if (this.textDecoration.indexOf('overline') > -1) { + offsets.push(-0.12); + } + if (offsets.length > 0) { + renderLinesAtOffset(offsets); + } + }, + + /** + * return font declaration string for canvas context + * @returns {String} font declaration formatted for canvas context. + */ + _getFontDeclaration: function() { + return [ + // node-canvas needs "weight style", while browsers need "style weight" + (fabric.isLikelyNode ? this.fontWeight : this.fontStyle), + (fabric.isLikelyNode ? this.fontStyle : this.fontWeight), + this.fontSize + 'px', + (fabric.isLikelyNode ? ('"' + this.fontFamily + '"') : this.fontFamily) + ].join(' '); + }, + + /** + * Renders text instance on a specified context + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + render: function(ctx, noTransform) { + // do not render if object is not visible + if (!this.visible) { + return; + } + if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) { + return; + } + if (this._shouldClearDimensionCache()) { + this._setTextStyles(ctx); + this._initDimensions(ctx); + } + this.callSuper('render', ctx, noTransform); + }, + + /** + * Returns the text as an array of lines. + * @returns {Array} Lines in the text + */ + _splitTextIntoLines: function() { + return this.text.split(this._reNewline); + }, + + /** + * Returns object representation of an instance + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} Object representation of an instance + */ + toObject: function(propertiesToInclude) { + var additionalProperties = [ + 'text', + 'fontSize', + 'fontWeight', + 'fontFamily', + 'fontStyle', + 'lineHeight', + 'textDecoration', + 'textAlign', + 'textBackgroundColor', + 'charSpacing' + ].concat(propertiesToInclude); + return this.callSuper('toObject', additionalProperties); + }, + + /* _TO_SVG_START_ */ + /** + * Returns SVG representation of an instance + * @param {Function} [reviver] Method for further parsing of svg representation. + * @return {String} svg representation of an instance + */ + toSVG: function(reviver) { + if (!this.ctx) { + this.ctx = fabric.util.createCanvasElement().getContext('2d'); + } + var markup = this._createBaseSVGMarkup(), + offsets = this._getSVGLeftTopOffsets(this.ctx), + textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft); + this._wrapSVGTextAndBg(markup, textAndBg); + + return reviver ? reviver(markup.join('')) : markup.join(''); + }, + + /** + * @private + */ + _getSVGLeftTopOffsets: function(ctx) { + var lineTop = this._getHeightOfLine(ctx, 0), + textLeft = -this.width / 2, + textTop = 0; + + return { + textLeft: textLeft + (this.group && this.group.type === 'path-group' ? this.left : 0), + textTop: textTop + (this.group && this.group.type === 'path-group' ? -this.top : 0), + lineTop: lineTop + }; + }, + + /** + * @private + */ + _wrapSVGTextAndBg: function(markup, textAndBg) { + var noShadow = true, filter = this.getSvgFilter(), + style = filter === '' ? '' : ' style="' + filter + '"'; + + markup.push( + '\t\n', + textAndBg.textBgRects.join(''), + '\t\t\n', + textAndBg.textSpans.join(''), + '\t\t\n', + '\t\n' + ); + }, + + getSvgStyles: function(skipShadow) { + var svgStyle = fabric.Object.prototype.getSvgStyles.call(this, skipShadow); + return svgStyle + ' white-space: pre;'; + }, + + /** + * @private + * @param {Number} textTopOffset Text top offset + * @param {Number} textLeftOffset Text left offset + * @return {Object} + */ + _getSVGTextAndBg: function(textTopOffset, textLeftOffset) { + var textSpans = [], + textBgRects = [], + height = 0; + // bounding-box background + this._setSVGBg(textBgRects); + + // text and text-background + for (var i = 0, len = this._textLines.length; i < len; i++) { + if (this.textBackgroundColor) { + this._setSVGTextLineBg(textBgRects, i, textLeftOffset, textTopOffset, height); + } + this._setSVGTextLineText(i, textSpans, height, textLeftOffset, textTopOffset, textBgRects); + height += this._getHeightOfLine(this.ctx, i); + } + + return { + textSpans: textSpans, + textBgRects: textBgRects + }; + }, + + _setSVGTextLineText: function(i, textSpans, height, textLeftOffset, textTopOffset) { + var yPos = this.fontSize * (this._fontSizeMult - this._fontSizeFraction) + - textTopOffset + height - this.height / 2; + if (this.textAlign === 'justify') { + // i call from here to do not intefere with IText + this._setSVGTextLineJustifed(i, textSpans, yPos, textLeftOffset); + return; + } + textSpans.push( + '\t\t\t elements since setting opacity + // on containing one doesn't work in Illustrator + this._getFillAttributes(this.fill), '>', + fabric.util.string.escapeXml(this._textLines[i]), + '\n' + ); + }, + + _setSVGTextLineJustifed: function(i, textSpans, yPos, textLeftOffset) { + var ctx = fabric.util.createCanvasElement().getContext('2d'); + + this._setTextStyles(ctx); + + var line = this._textLines[i], + words = line.split(/\s+/), + wordsWidth = this._getWidthOfWords(ctx, words.join('')), + widthDiff = this.width - wordsWidth, + numSpaces = words.length - 1, + spaceWidth = numSpaces > 0 ? widthDiff / numSpaces : 0, + word, attributes = this._getFillAttributes(this.fill), + len; + + textLeftOffset += this._getLineLeftOffset(this._getLineWidth(ctx, i)); + + for (i = 0, len = words.length; i < len; i++) { + word = words[i]; + textSpans.push( + '\t\t\t elements since setting opacity + // on containing one doesn't work in Illustrator + attributes, '>', + fabric.util.string.escapeXml(word), + '\n' + ); + textLeftOffset += this._getWidthOfWords(ctx, word) + spaceWidth; + } + }, + + _setSVGTextLineBg: function(textBgRects, i, textLeftOffset, textTopOffset, height) { + textBgRects.push( + '\t\t\n'); + }, + + _setSVGBg: function(textBgRects) { + if (this.backgroundColor) { + textBgRects.push( + '\t\t\n'); + } + }, + + /** + * Adobe Illustrator (at least CS5) is unable to render rgba()-based fill values + * we work around it by "moving" alpha channel into opacity attribute and setting fill's alpha to 1 + * + * @private + * @param {*} value + * @return {String} + */ + _getFillAttributes: function(value) { + var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : ''; + if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) { + return 'fill="' + value + '"'; + } + return 'opacity="' + fillColor.getAlpha() + '" fill="' + fillColor.setAlpha(1).toRgb() + '"'; + }, + /* _TO_SVG_END_ */ + + /** + * Sets specified property to a specified value + * @param {String} key + * @param {*} value + * @return {fabric.Text} thisArg + * @chainable + */ + _set: function(key, value) { + this.callSuper('_set', key, value); + + if (this._dimensionAffectingProps.indexOf(key) > -1) { + this._initDimensions(); + this.setCoords(); + } + }, + + /** + * Returns complexity of an instance + * @return {Number} complexity + */ + complexity: function() { + return 1; + } + }); + + /* _FROM_SVG_START_ */ + /** + * List of attribute names to account for when parsing SVG element (used by {@link fabric.Text.fromElement}) + * @static + * @memberOf fabric.Text + * @see: http://www.w3.org/TR/SVG/text.html#TextElement + */ + 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(' ')); + + /** + * Default SVG font size + * @static + * @memberOf fabric.Text + */ + fabric.Text.DEFAULT_SVG_FONT_SIZE = 16; + + /** + * Returns fabric.Text instance from an SVG element (not yet implemented) + * @static + * @memberOf fabric.Text + * @param {SVGElement} element Element to parse + * @param {Object} [options] Options object + * @return {fabric.Text} Instance of fabric.Text + */ + fabric.Text.fromElement = function(element, options) { + if (!element) { + return null; + } + + var parsedAttributes = fabric.parseAttributes(element, fabric.Text.ATTRIBUTE_NAMES); + options = fabric.util.object.extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes); + + options.top = options.top || 0; + options.left = options.left || 0; + if ('dx' in parsedAttributes) { + options.left += parsedAttributes.dx; + } + if ('dy' in parsedAttributes) { + options.top += parsedAttributes.dy; + } + if (!('fontSize' in options)) { + options.fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE; + } + + if (!options.originX) { + options.originX = 'left'; + } + + var textContent = ''; + + // The XML is not properly parsed in IE9 so a workaround to get + // textContent is through firstChild.data. Another workaround would be + // to convert XML loaded from a file to be converted using DOMParser (same way loadSVGFromString() does) + if (!('textContent' in element)) { + if ('firstChild' in element && element.firstChild !== null) { + if ('data' in element.firstChild && element.firstChild.data !== null) { + textContent = element.firstChild.data; + } + } + } + else { + textContent = element.textContent; + } + + textContent = textContent.replace(/^\s+|\s+$|\n+/g, '').replace(/\s+/g, ' '); + + var text = new fabric.Text(textContent, options), + textHeightScaleFactor = text.getHeight() / text.height, + lineHeightDiff = (text.height + text.strokeWidth) * text.lineHeight - text.height, + scaledDiff = lineHeightDiff * textHeightScaleFactor, + textHeight = text.getHeight() + scaledDiff, + offX = 0; + /* + Adjust positioning: + x/y attributes in SVG correspond to the bottom-left corner of text bounding box + top/left properties in Fabric correspond to center point of text bounding box + */ + if (text.originX === 'left') { + offX = text.getWidth() / 2; + } + if (text.originX === 'right') { + offX = -text.getWidth() / 2; + } + text.set({ + left: text.getLeft() + offX, + top: text.getTop() - textHeight / 2 + text.fontSize * (0.18 + text._fontSizeFraction) / text.lineHeight /* 0.3 is the old lineHeight */ + }); + + return text; + }; + /* _FROM_SVG_END_ */ + + /** + * Returns fabric.Text instance from an object representation + * @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 + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.Text} Instance of fabric.Text + */ + fabric.Text.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Text', object, callback, forceAsync, 'text'); + }; + + fabric.util.createAccessors(fabric.Text); + +})(typeof exports !== 'undefined' ? exports : this); + + +(function() { + + var clone = fabric.util.object.clone; + + /** + * IText class (introduced in v1.4) Events are also fired with "text:" + * prefix when observing canvas. + * @class fabric.IText + * @extends fabric.Text + * @mixes fabric.Observable + * + * @fires changed + * @fires selection:changed + * @fires editing:entered + * @fires editing:exited + * + * @return {fabric.IText} thisArg + * @see {@link fabric.IText#initialize} for constructor definition + * + *

Supported key combinations:

+ *
+   *   Move cursor:                    left, right, up, down
+   *   Select character:               shift + left, shift + right
+   *   Select text vertically:         shift + up, shift + down
+   *   Move cursor by word:            alt + left, alt + right
+   *   Select words:                   shift + alt + left, shift + alt + right
+   *   Move cursor to line start/end:  cmd + left, cmd + right or home, end
+   *   Select till start/end of line:  cmd + shift + left, cmd + shift + right or shift + home, shift + end
+   *   Jump to start/end of text:      cmd + up, cmd + down
+   *   Select till start/end of text:  cmd + shift + up, cmd + shift + down or shift + pgUp, shift + pgDown
+   *   Delete character:               backspace
+   *   Delete word:                    alt + backspace
+   *   Delete line:                    cmd + backspace
+   *   Forward delete:                 delete
+   *   Copy text:                      ctrl/cmd + c
+   *   Paste text:                     ctrl/cmd + v
+   *   Cut text:                       ctrl/cmd + x
+   *   Select entire text:             ctrl/cmd + a
+   *   Quit editing                    tab or esc
+   * 
+ * + *

Supported mouse/touch combination

+ *
+   *   Position cursor:                click/touch
+   *   Create selection:               click/touch & drag
+   *   Create selection:               click & shift + click
+   *   Select word:                    double click
+   *   Select line:                    triple click
+   * 
+ */ + fabric.IText = fabric.util.createClass(fabric.Text, fabric.Observable, /** @lends fabric.IText.prototype */ { + + /** + * Type of an object + * @type String + * @default + */ + type: 'i-text', + + /** + * Index where text selection starts (or where cursor is when there is no selection) + * @type Number + * @default + */ + selectionStart: 0, + + /** + * Index where text selection ends + * @type Number + * @default + */ + selectionEnd: 0, + + /** + * Color of text selection + * @type String + * @default + */ + selectionColor: 'rgba(17,119,255,0.3)', + + /** + * Indicates whether text is in editing mode + * @type Boolean + * @default + */ + isEditing: false, + + /** + * Indicates whether a text can be edited + * @type Boolean + * @default + */ + editable: true, + + /** + * Border color of text object while it's in editing mode + * @type String + * @default + */ + editingBorderColor: 'rgba(102,153,255,0.25)', + + /** + * Width of cursor (in px) + * @type Number + * @default + */ + cursorWidth: 2, + + /** + * Color of default cursor (when not overwritten by character style) + * @type String + * @default + */ + cursorColor: '#333', + + /** + * Delay between cursor blink (in ms) + * @type Number + * @default + */ + cursorDelay: 1000, + + /** + * Duration of cursor fadein (in ms) + * @type Number + * @default + */ + cursorDuration: 600, + + /** + * Object containing character styles + * (where top-level properties corresponds to line number and 2nd-level properties -- to char number in a line) + * @type Object + * @default + */ + styles: null, + + /** + * Indicates whether internal text char widths can be cached + * @type Boolean + * @default + */ + caching: true, + + /** + * @private + */ + _reSpace: /\s|\n/, + + /** + * @private + */ + _currentCursorOpacity: 0, + + /** + * @private + */ + _selectionDirection: null, + + /** + * @private + */ + _abortCursorAnimation: false, + + /** + * @private + */ + __widthOfSpace: [], + + /** + * Constructor + * @param {String} text Text string + * @param {Object} [options] Options object + * @return {fabric.IText} thisArg + */ + initialize: function(text, options) { + this.styles = options ? (options.styles || { }) : { }; + this.callSuper('initialize', text, options); + this.initBehavior(); + }, + + /** + * @private + */ + _clearCache: function() { + this.callSuper('_clearCache'); + this.__widthOfSpace = []; + }, + + /** + * Returns true if object has no styling + */ + isEmptyStyles: function() { + if (!this.styles) { + return true; + } + var obj = this.styles; + + for (var p1 in obj) { + for (var p2 in obj[p1]) { + // eslint-disable-next-line no-unused-vars + for (var p3 in obj[p1][p2]) { + return false; + } + } + } + return true; + }, + + /** + * Sets selection start (left boundary of a selection) + * @param {Number} index Index to set selection start to + */ + setSelectionStart: function(index) { + index = Math.max(index, 0); + this._updateAndFire('selectionStart', index); + }, + + /** + * Sets selection end (right boundary of a selection) + * @param {Number} index Index to set selection end to + */ + setSelectionEnd: function(index) { + index = Math.min(index, this.text.length); + this._updateAndFire('selectionEnd', index); + }, + + /** + * @private + * @param {String} property 'selectionStart' or 'selectionEnd' + * @param {Number} index new position of property + */ + _updateAndFire: function(property, index) { + if (this[property] !== index) { + this._fireSelectionChanged(); + this[property] = index; + } + this._updateTextarea(); + }, + + /** + * Fires the even of selection changed + * @private + */ + _fireSelectionChanged: function() { + this.fire('selection:changed'); + this.canvas && this.canvas.fire('text:selection:changed', { target: this }); + }, + + /** + * Gets style of a current selection/cursor (at the start position) + * @param {Number} [startIndex] Start index to get styles at + * @param {Number} [endIndex] End index to get styles at + * @return {Object} styles Style object at a specified (or current) index + */ + getSelectionStyles: function(startIndex, endIndex) { + + if (arguments.length === 2) { + var styles = []; + for (var i = startIndex; i < endIndex; i++) { + styles.push(this.getSelectionStyles(i)); + } + return styles; + } + + var loc = this.get2DCursorLocation(startIndex), + style = this._getStyleDeclaration(loc.lineIndex, loc.charIndex); + + return style || {}; + }, + + /** + * Sets style of a current selection + * @param {Object} [styles] Styles object + * @return {fabric.IText} thisArg + * @chainable + */ + setSelectionStyles: function(styles) { + if (this.selectionStart === this.selectionEnd) { + this._extendStyles(this.selectionStart, styles); + } + else { + for (var i = this.selectionStart; i < this.selectionEnd; i++) { + this._extendStyles(i, styles); + } + } + /* not included in _extendStyles to avoid clearing cache more than once */ + this._forceClearCache = true; + return this; + }, + + /** + * @private + */ + _extendStyles: function(index, styles) { + var loc = this.get2DCursorLocation(index); + + if (!this._getLineStyle(loc.lineIndex)) { + this._setLineStyle(loc.lineIndex, {}); + } + + if (!this._getStyleDeclaration(loc.lineIndex, loc.charIndex)) { + this._setStyleDeclaration(loc.lineIndex, loc.charIndex, {}); + } + + fabric.util.object.extend(this._getStyleDeclaration(loc.lineIndex, loc.charIndex), styles); + }, + + /** + * Initialize text dimensions. Render all text on given context + * or on a offscreen canvas to get the text width with measureText. + * Updates this.width and this.height with the proper values. + * Does not return dimensions. + * @param {CanvasRenderingContext2D} [ctx] Context to render on + * @private + */ + _initDimensions: function(ctx) { + if (!ctx) { + this.clearContextTop(); + } + this.callSuper('_initDimensions', ctx); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Boolean} noTransform + */ + render: function(ctx, noTransform) { + this.clearContextTop(); + this.callSuper('render', ctx, noTransform); + // clear the cursorOffsetCache, so we ensure to calculate once per renderCursor + // the correct position but not at every cursor animation. + this.cursorOffsetCache = { }; + this.renderCursorOrSelection(); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _render: function(ctx) { + this.callSuper('_render', ctx); + this.ctx = ctx; + }, + + /** + * Prepare and clean the contextTop + */ + clearContextTop: function() { + if (!this.active || !this.isEditing) { + return; + } + if (this.canvas && this.canvas.contextTop) { + var ctx = this.canvas.contextTop; + ctx.save(); + ctx.transform.apply(ctx, this.canvas.viewportTransform); + this.transform(ctx); + this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix); + this._clearTextArea(ctx); + ctx.restore(); + } + }, + + /** + * Renders cursor or selection (depending on what exists) + */ + renderCursorOrSelection: function() { + if (!this.active || !this.isEditing) { + return; + } + var chars = this.text.split(''), + boundaries, ctx; + if (this.canvas && this.canvas.contextTop) { + ctx = this.canvas.contextTop; + ctx.save(); + ctx.transform.apply(ctx, this.canvas.viewportTransform); + this.transform(ctx); + this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix); + this._clearTextArea(ctx); + } + else { + ctx = this.ctx; + ctx.save(); + } + if (this.selectionStart === this.selectionEnd) { + boundaries = this._getCursorBoundaries(chars, 'cursor'); + this.renderCursor(boundaries, ctx); + } + else { + boundaries = this._getCursorBoundaries(chars, 'selection'); + this.renderSelection(chars, boundaries, ctx); + } + ctx.restore(); + }, + + _clearTextArea: function(ctx) { + // we add 4 pixel, to be sure to do not leave any pixel out + var width = this.width + 4, height = this.height + 4; + ctx.clearRect(-width / 2, -height / 2, width, height); + }, + /** + * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start) + * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used. + */ + get2DCursorLocation: function(selectionStart) { + if (typeof selectionStart === 'undefined') { + selectionStart = this.selectionStart; + } + var len = this._textLines.length; + for (var i = 0; i < len; i++) { + if (selectionStart <= this._textLines[i].length) { + return { + lineIndex: i, + charIndex: selectionStart + }; + } + selectionStart -= this._textLines[i].length + 1; + } + return { + lineIndex: i - 1, + charIndex: this._textLines[i - 1].length < selectionStart ? this._textLines[i - 1].length : selectionStart + }; + }, + + /** + * Returns complete style of char at the current cursor + * @param {Number} lineIndex Line index + * @param {Number} charIndex Char index + * @return {Object} Character style + */ + getCurrentCharStyle: function(lineIndex, charIndex) { + var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1); + + return { + fontSize: style && style.fontSize || this.fontSize, + fill: style && style.fill || this.fill, + textBackgroundColor: style && style.textBackgroundColor || this.textBackgroundColor, + textDecoration: style && style.textDecoration || this.textDecoration, + fontFamily: style && style.fontFamily || this.fontFamily, + fontWeight: style && style.fontWeight || this.fontWeight, + fontStyle: style && style.fontStyle || this.fontStyle, + stroke: style && style.stroke || this.stroke, + strokeWidth: style && style.strokeWidth || this.strokeWidth + }; + }, + + /** + * Returns fontSize of char at the current cursor + * @param {Number} lineIndex Line index + * @param {Number} charIndex Char index + * @return {Number} Character font size + */ + getCurrentCharFontSize: function(lineIndex, charIndex) { + var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1); + return style && style.fontSize ? style.fontSize : this.fontSize; + }, + + /** + * Returns color (fill) of char at the current cursor + * @param {Number} lineIndex Line index + * @param {Number} charIndex Char index + * @return {String} Character color (fill) + */ + getCurrentCharColor: function(lineIndex, charIndex) { + var style = this._getStyleDeclaration(lineIndex, charIndex === 0 ? 0 : charIndex - 1); + return style && style.fill ? style.fill : this.cursorColor; + }, + + /** + * Returns cursor boundaries (left, top, leftOffset, topOffset) + * @private + * @param {Array} chars Array of characters + * @param {String} typeOfBoundaries + */ + _getCursorBoundaries: function(chars, typeOfBoundaries) { + + // left/top are left/top of entire text box + // leftOffset/topOffset are offset from that left/top point of a text box + + var left = Math.round(this._getLeftOffset()), + top = this._getTopOffset(), + + offsets = this._getCursorBoundariesOffsets( + chars, typeOfBoundaries); + + return { + left: left, + top: top, + leftOffset: offsets.left + offsets.lineLeft, + topOffset: offsets.top + }; + }, + + /** + * @private + */ + _getCursorBoundariesOffsets: function(chars, typeOfBoundaries) { + if (this.cursorOffsetCache && 'top' in this.cursorOffsetCache) { + return this.cursorOffsetCache; + } + var lineLeftOffset = 0, + lineIndex = 0, + charIndex = 0, + topOffset = 0, + leftOffset = 0, + boundaries; + + for (var i = 0; i < this.selectionStart; i++) { + if (chars[i] === '\n') { + leftOffset = 0; + topOffset += this._getHeightOfLine(this.ctx, lineIndex); + + lineIndex++; + charIndex = 0; + } + else { + leftOffset += this._getWidthOfChar(this.ctx, chars[i], lineIndex, charIndex); + charIndex++; + } + + lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, lineIndex)); + } + if (typeOfBoundaries === 'cursor') { + topOffset += (1 - this._fontSizeFraction) * this._getHeightOfLine(this.ctx, lineIndex) / this.lineHeight + - this.getCurrentCharFontSize(lineIndex, charIndex) * (1 - this._fontSizeFraction); + } + if (this.charSpacing !== 0 && charIndex === this._textLines[lineIndex].length) { + leftOffset -= this._getWidthOfCharSpacing(); + } + boundaries = { + top: topOffset, + left: leftOffset > 0 ? leftOffset : 0, + lineLeft: lineLeftOffset + }; + this.cursorOffsetCache = boundaries; + return this.cursorOffsetCache; + }, + + /** + * Renders cursor + * @param {Object} boundaries + * @param {CanvasRenderingContext2D} ctx transformed context to draw on + */ + renderCursor: function(boundaries, ctx) { + + var cursorLocation = this.get2DCursorLocation(), + lineIndex = cursorLocation.lineIndex, + charIndex = cursorLocation.charIndex, + charHeight = this.getCurrentCharFontSize(lineIndex, charIndex), + leftOffset = boundaries.leftOffset, + multiplier = this.scaleX * this.canvas.getZoom(), + cursorWidth = this.cursorWidth / multiplier; + + ctx.fillStyle = this.getCurrentCharColor(lineIndex, charIndex); + ctx.globalAlpha = this.__isMousedown ? 1 : this._currentCursorOpacity; + + ctx.fillRect( + boundaries.left + leftOffset - cursorWidth / 2, + boundaries.top + boundaries.topOffset, + cursorWidth, + charHeight); + }, + + /** + * Renders text selection + * @param {Array} chars Array of characters + * @param {Object} boundaries Object with left/top/leftOffset/topOffset + * @param {CanvasRenderingContext2D} ctx transformed context to draw on + */ + renderSelection: function(chars, boundaries, ctx) { + + ctx.fillStyle = this.selectionColor; + + var start = this.get2DCursorLocation(this.selectionStart), + end = this.get2DCursorLocation(this.selectionEnd), + startLine = start.lineIndex, + endLine = end.lineIndex; + for (var i = startLine; i <= endLine; i++) { + var lineOffset = this._getLineLeftOffset(this._getLineWidth(ctx, i)) || 0, + lineHeight = this._getHeightOfLine(this.ctx, i), + realLineHeight = 0, boxWidth = 0, line = this._textLines[i]; + + if (i === startLine) { + for (var j = 0, len = line.length; j < len; j++) { + if (j >= start.charIndex && (i !== endLine || j < end.charIndex)) { + boxWidth += this._getWidthOfChar(ctx, line[j], i, j); + } + if (j < start.charIndex) { + lineOffset += this._getWidthOfChar(ctx, line[j], i, j); + } + } + if (j === line.length) { + boxWidth -= this._getWidthOfCharSpacing(); + } + } + else if (i > startLine && i < endLine) { + boxWidth += this._getLineWidth(ctx, i) || 5; + } + else if (i === endLine) { + for (var j2 = 0, j2len = end.charIndex; j2 < j2len; j2++) { + boxWidth += this._getWidthOfChar(ctx, line[j2], i, j2); + } + if (end.charIndex === line.length) { + boxWidth -= this._getWidthOfCharSpacing(); + } + } + realLineHeight = lineHeight; + if (this.lineHeight < 1 || (i === endLine && this.lineHeight > 1)) { + lineHeight /= this.lineHeight; + } + ctx.fillRect( + boundaries.left + lineOffset, + boundaries.top + boundaries.topOffset, + boxWidth > 0 ? boxWidth : 0, + lineHeight); + + boundaries.topOffset += realLineHeight; + } + }, + + /** + * @private + * @param {String} method + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} line Content of the line + * @param {Number} left + * @param {Number} top + * @param {Number} lineIndex + * @param {Number} charOffset + */ + _renderChars: function(method, ctx, line, left, top, lineIndex, charOffset) { + + if (this.isEmptyStyles()) { + return this._renderCharsFast(method, ctx, line, left, top); + } + + charOffset = charOffset || 0; + + // set proper line offset + var lineHeight = this._getHeightOfLine(ctx, lineIndex), + prevStyle, + thisStyle, + charsToRender = ''; + + ctx.save(); + top -= lineHeight / this.lineHeight * this._fontSizeFraction; + for (var i = charOffset, len = line.length + charOffset; i <= len; i++) { + prevStyle = prevStyle || this.getCurrentCharStyle(lineIndex, i); + thisStyle = this.getCurrentCharStyle(lineIndex, i + 1); + + if (this._hasStyleChanged(prevStyle, thisStyle) || i === len) { + this._renderChar(method, ctx, lineIndex, i - 1, charsToRender, left, top, lineHeight); + charsToRender = ''; + prevStyle = thisStyle; + } + charsToRender += line[i - charOffset]; + } + ctx.restore(); + }, + + /** + * @private + * @param {String} method + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} line Content of the line + * @param {Number} left Left coordinate + * @param {Number} top Top coordinate + */ + _renderCharsFast: function(method, ctx, line, left, top) { + + if (method === 'fillText' && this.fill) { + this.callSuper('_renderChars', method, ctx, line, left, top); + } + if (method === 'strokeText' && ((this.stroke && this.strokeWidth > 0) || this.skipFillStrokeCheck)) { + this.callSuper('_renderChars', method, ctx, line, left, top); + } + }, + + /** + * @private + * @param {String} method + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Number} lineIndex + * @param {Number} i + * @param {String} _char + * @param {Number} left Left coordinate + * @param {Number} top Top coordinate + * @param {Number} lineHeight Height of the line + */ + _renderChar: function(method, ctx, lineIndex, i, _char, left, top, lineHeight) { + var charWidth, charHeight, shouldFill, shouldStroke, + decl = this._getStyleDeclaration(lineIndex, i), + offset, textDecoration, chars, additionalSpace, _charWidth; + + if (decl) { + charHeight = this._getHeightOfChar(ctx, _char, lineIndex, i); + shouldStroke = decl.stroke; + shouldFill = decl.fill; + textDecoration = decl.textDecoration; + } + else { + charHeight = this.fontSize; + } + + shouldStroke = (shouldStroke || this.stroke) && method === 'strokeText'; + shouldFill = (shouldFill || this.fill) && method === 'fillText'; + + decl && ctx.save(); + + charWidth = this._applyCharStylesGetWidth(ctx, _char, lineIndex, i, decl || null); + textDecoration = textDecoration || this.textDecoration; + + if (decl && decl.textBackgroundColor) { + this._removeShadow(ctx); + } + if (this.charSpacing !== 0) { + additionalSpace = this._getWidthOfCharSpacing(); + chars = _char.split(''); + charWidth = 0; + for (var j = 0, len = chars.length, jChar; j < len; j++) { + jChar = chars[j]; + shouldFill && ctx.fillText(jChar, left + charWidth, top); + shouldStroke && ctx.strokeText(jChar, left + charWidth, top); + _charWidth = ctx.measureText(jChar).width + additionalSpace; + charWidth += _charWidth > 0 ? _charWidth : 0; + } + } + else { + shouldFill && ctx.fillText(_char, left, top); + shouldStroke && ctx.strokeText(_char, left, top); + } + + if (textDecoration || textDecoration !== '') { + offset = this._fontSizeFraction * lineHeight / this.lineHeight; + this._renderCharDecoration(ctx, textDecoration, left, top, offset, charWidth, charHeight); + } + + decl && ctx.restore(); + ctx.translate(charWidth, 0); + }, + + /** + * @private + * @param {Object} prevStyle + * @param {Object} thisStyle + */ + _hasStyleChanged: function(prevStyle, thisStyle) { + return (prevStyle.fill !== thisStyle.fill || + prevStyle.fontSize !== thisStyle.fontSize || + prevStyle.textBackgroundColor !== thisStyle.textBackgroundColor || + prevStyle.textDecoration !== thisStyle.textDecoration || + prevStyle.fontFamily !== thisStyle.fontFamily || + prevStyle.fontWeight !== thisStyle.fontWeight || + prevStyle.fontStyle !== thisStyle.fontStyle || + prevStyle.stroke !== thisStyle.stroke || + prevStyle.strokeWidth !== thisStyle.strokeWidth + ); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderCharDecoration: function(ctx, textDecoration, left, top, offset, charWidth, charHeight) { + + if (!textDecoration) { + return; + } + + var decorationWeight = charHeight / 15, + positions = { + underline: top + charHeight / 10, + 'line-through': top - charHeight * (this._fontSizeFraction + this._fontSizeMult - 1) + decorationWeight, + overline: top - (this._fontSizeMult - this._fontSizeFraction) * charHeight + }, + decorations = ['underline', 'line-through', 'overline'], i, decoration; + + for (i = 0; i < decorations.length; i++) { + decoration = decorations[i]; + if (textDecoration.indexOf(decoration) > -1) { + ctx.fillRect(left, positions[decoration], charWidth , decorationWeight); + } + } + }, + + /** + * @private + * @param {String} method + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} line + * @param {Number} left + * @param {Number} top + * @param {Number} lineIndex + */ + _renderTextLine: function(method, ctx, line, left, top, lineIndex) { + // to "cancel" this.fontSize subtraction in fabric.Text#_renderTextLine + // the adding 0.03 is just to align text with itext by overlap test + if (!this.isEmptyStyles()) { + top += this.fontSize * (this._fontSizeFraction + 0.03); + } + this.callSuper('_renderTextLine', method, ctx, line, left, top, lineIndex); + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderTextDecoration: function(ctx) { + if (this.isEmptyStyles()) { + return this.callSuper('_renderTextDecoration', ctx); + } + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _renderTextLinesBackground: function(ctx) { + this.callSuper('_renderTextLinesBackground', ctx); + + var lineTopOffset = 0, heightOfLine, + lineWidth, lineLeftOffset, + leftOffset = this._getLeftOffset(), + topOffset = this._getTopOffset(), + colorCache = '', + line, _char, style, leftCache, + topCache, widthCache, heightCache; + ctx.save(); + for (var i = 0, len = this._textLines.length; i < len; i++) { + heightOfLine = this._getHeightOfLine(ctx, i); + line = this._textLines[i]; + + if (line === '' || !this.styles || !this._getLineStyle(i)) { + lineTopOffset += heightOfLine; + continue; + } + + lineWidth = this._getLineWidth(ctx, i); + lineLeftOffset = this._getLineLeftOffset(lineWidth); + leftCache = topCache = widthCache = heightCache = 0; + for (var j = 0, jlen = line.length; j < jlen; j++) { + style = this._getStyleDeclaration(i, j) || {}; + + if (colorCache !== style.textBackgroundColor) { + if (heightCache && widthCache) { + ctx.fillStyle = colorCache; + ctx.fillRect(leftCache, topCache, widthCache, heightCache); + } + leftCache = topCache = widthCache = heightCache = 0; + colorCache = style.textBackgroundColor || ''; + } + + if (!style.textBackgroundColor) { + colorCache = ''; + continue; + } + _char = line[j]; + + if (colorCache === style.textBackgroundColor) { + colorCache = style.textBackgroundColor; + if (!leftCache) { + leftCache = leftOffset + lineLeftOffset + this._getWidthOfCharsAt(ctx, i, j); + } + topCache = topOffset + lineTopOffset; + widthCache += this._getWidthOfChar(ctx, _char, i, j); + heightCache = heightOfLine / this.lineHeight; + } + } + // if a textBackgroundColor ends on the last character of a line + if (heightCache && widthCache) { + ctx.fillStyle = colorCache; + ctx.fillRect(leftCache, topCache, widthCache, heightCache); + leftCache = topCache = widthCache = heightCache = 0; + } + lineTopOffset += heightOfLine; + } + ctx.restore(); + }, + + /** + * @private + */ + _getCacheProp: function(_char, styleDeclaration) { + return _char + + styleDeclaration.fontSize + + styleDeclaration.fontWeight + + styleDeclaration.fontStyle; + }, + + /** + * @private + * @param {String} fontFamily name + * @return {Object} reference to cache + */ + _getFontCache: function(fontFamily) { + if (!fabric.charWidthsCache[fontFamily]) { + fabric.charWidthsCache[fontFamily] = { }; + } + return fabric.charWidthsCache[fontFamily]; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} _char + * @param {Number} lineIndex + * @param {Number} charIndex + * @param {Object} [decl] + */ + _applyCharStylesGetWidth: function(ctx, _char, lineIndex, charIndex, decl) { + var charDecl = decl || this._getStyleDeclaration(lineIndex, charIndex), + styleDeclaration = clone(charDecl), + width, cacheProp, charWidthsCache; + + this._applyFontStyles(styleDeclaration); + charWidthsCache = this._getFontCache(styleDeclaration.fontFamily); + cacheProp = this._getCacheProp(_char, styleDeclaration); + + // short-circuit if no styles for this char + // global style from object is always applyed and handled by save and restore + if (!charDecl && charWidthsCache[cacheProp] && this.caching) { + return charWidthsCache[cacheProp]; + } + + if (typeof styleDeclaration.shadow === 'string') { + styleDeclaration.shadow = new fabric.Shadow(styleDeclaration.shadow); + } + + var fill = styleDeclaration.fill || this.fill; + ctx.fillStyle = fill.toLive + ? fill.toLive(ctx, this) + : fill; + + if (styleDeclaration.stroke) { + ctx.strokeStyle = (styleDeclaration.stroke && styleDeclaration.stroke.toLive) + ? styleDeclaration.stroke.toLive(ctx, this) + : styleDeclaration.stroke; + } + + ctx.lineWidth = styleDeclaration.strokeWidth || this.strokeWidth; + ctx.font = this._getFontDeclaration.call(styleDeclaration); + + //if we want this._setShadow.call to work with styleDeclarion + //we have to add those references + if (styleDeclaration.shadow) { + 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]) { + width = ctx.measureText(_char).width; + this.caching && (charWidthsCache[cacheProp] = width); + return width; + } + + return charWidthsCache[cacheProp]; + }, + + /** + * @private + * @param {Object} styleDeclaration + */ + _applyFontStyles: function(styleDeclaration) { + if (!styleDeclaration.fontFamily) { + styleDeclaration.fontFamily = this.fontFamily; + } + if (!styleDeclaration.fontSize) { + styleDeclaration.fontSize = this.fontSize; + } + if (!styleDeclaration.fontWeight) { + styleDeclaration.fontWeight = this.fontWeight; + } + if (!styleDeclaration.fontStyle) { + styleDeclaration.fontStyle = this.fontStyle; + } + }, + + /** + * @param {Number} lineIndex + * @param {Number} charIndex + * @param {Boolean} [returnCloneOrEmpty=false] + * @private + */ + _getStyleDeclaration: function(lineIndex, charIndex, returnCloneOrEmpty) { + if (returnCloneOrEmpty) { + return (this.styles[lineIndex] && this.styles[lineIndex][charIndex]) + ? clone(this.styles[lineIndex][charIndex]) + : { }; + } + + return this.styles[lineIndex] && this.styles[lineIndex][charIndex] ? this.styles[lineIndex][charIndex] : null; + }, + + /** + * @param {Number} lineIndex + * @param {Number} charIndex + * @param {Object} style + * @private + */ + _setStyleDeclaration: function(lineIndex, charIndex, style) { + this.styles[lineIndex][charIndex] = style; + }, + + /** + * + * @param {Number} lineIndex + * @param {Number} charIndex + * @private + */ + _deleteStyleDeclaration: function(lineIndex, charIndex) { + delete this.styles[lineIndex][charIndex]; + }, + + /** + * @param {Number} lineIndex + * @private + */ + _getLineStyle: function(lineIndex) { + return this.styles[lineIndex]; + }, + + /** + * @param {Number} lineIndex + * @param {Object} style + * @private + */ + _setLineStyle: function(lineIndex, style) { + this.styles[lineIndex] = style; + }, + + /** + * @param {Number} lineIndex + * @private + */ + _deleteLineStyle: function(lineIndex) { + delete this.styles[lineIndex]; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _getWidthOfChar: function(ctx, _char, lineIndex, charIndex) { + if (!this._isMeasuring && this.textAlign === 'justify' && this._reSpacesAndTabs.test(_char)) { + return this._getWidthOfSpace(ctx, lineIndex); + } + ctx.save(); + var width = this._applyCharStylesGetWidth(ctx, _char, lineIndex, charIndex); + if (this.charSpacing !== 0) { + width += this._getWidthOfCharSpacing(); + } + ctx.restore(); + return width > 0 ? width : 0; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Number} lineIndex + * @param {Number} charIndex + */ + _getHeightOfChar: function(ctx, lineIndex, charIndex) { + var style = this._getStyleDeclaration(lineIndex, charIndex); + return style && style.fontSize ? style.fontSize : this.fontSize; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Number} lineIndex + * @param {Number} charIndex + */ + _getWidthOfCharsAt: function(ctx, lineIndex, charIndex) { + var width = 0, i, _char; + for (i = 0; i < charIndex; i++) { + _char = this._textLines[lineIndex][i]; + width += this._getWidthOfChar(ctx, _char, lineIndex, i); + } + return width; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Number} lineIndex line number + * @return {Number} Line width + */ + _measureLine: function(ctx, lineIndex) { + this._isMeasuring = true; + var width = this._getWidthOfCharsAt(ctx, lineIndex, this._textLines[lineIndex].length); + if (this.charSpacing !== 0) { + width -= this._getWidthOfCharSpacing(); + } + this._isMeasuring = false; + return width > 0 ? width : 0; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {Number} lineIndex + */ + _getWidthOfSpace: function (ctx, lineIndex) { + if (this.__widthOfSpace[lineIndex]) { + return this.__widthOfSpace[lineIndex]; + } + var line = this._textLines[lineIndex], + wordsWidth = this._getWidthOfWords(ctx, line, lineIndex, 0), + widthDiff = this.width - wordsWidth, + numSpaces = line.length - line.replace(this._reSpacesAndTabs, '').length, + width = Math.max(widthDiff / numSpaces, ctx.measureText(' ').width); + this.__widthOfSpace[lineIndex] = width; + return width; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + * @param {String} line + * @param {Number} lineIndex + * @param {Number} charOffset + */ + _getWidthOfWords: function (ctx, line, lineIndex, charOffset) { + var width = 0; + + for (var charIndex = 0; charIndex < line.length; charIndex++) { + var _char = line[charIndex]; + + if (!_char.match(/\s/)) { + width += this._getWidthOfChar(ctx, _char, lineIndex, charIndex + charOffset); + } + } + + return width; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _getHeightOfLine: function(ctx, lineIndex) { + if (this.__lineHeights[lineIndex]) { + return this.__lineHeights[lineIndex]; + } + + var line = this._textLines[lineIndex], + maxHeight = this._getHeightOfChar(ctx, lineIndex, 0); + + for (var i = 1, len = line.length; i < len; i++) { + var currentCharHeight = this._getHeightOfChar(ctx, lineIndex, i); + if (currentCharHeight > maxHeight) { + maxHeight = currentCharHeight; + } + } + this.__lineHeights[lineIndex] = maxHeight * this.lineHeight * this._fontSizeMult; + return this.__lineHeights[lineIndex]; + }, + + /** + * @private + * @param {CanvasRenderingContext2D} ctx Context to render on + */ + _getTextHeight: function(ctx) { + var lineHeight, height = 0; + for (var i = 0, len = this._textLines.length; i < len; i++) { + lineHeight = this._getHeightOfLine(ctx, i); + height += (i === len - 1 ? lineHeight / this.lineHeight : lineHeight); + } + return height; + }, + + /** + * Returns object representation of an instance + * @method toObject + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), { + styles: clone(this.styles, true) + }); + } + }); + + /** + * Returns fabric.IText instance from an object representation + * @static + * @memberOf fabric.IText + * @param {Object} object Object to create an instance from + * @param {function} [callback] invoked with new instance as argument + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.IText} instance of fabric.IText + */ + fabric.IText.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('IText', object, callback, forceAsync, 'text'); + }; +})(); + + +(function() { + + var clone = fabric.util.object.clone; + + fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ { + + /** + * Initializes all the interactive behavior of IText + */ + initBehavior: function() { + this.initAddedHandler(); + this.initRemovedHandler(); + this.initCursorSelectionHandlers(); + this.initDoubleClickSimulation(); + this.mouseMoveHandler = this.mouseMoveHandler.bind(this); + }, + + onDeselect: function() { + this.isEditing && this.exitEditing(); + this.selected = false; + this.callSuper('onDeselect'); + }, + + /** + * Initializes "added" event handler + */ + initAddedHandler: function() { + var _this = this; + this.on('added', function() { + var canvas = _this.canvas; + if (canvas) { + if (!canvas._hasITextHandlers) { + canvas._hasITextHandlers = true; + _this._initCanvasHandlers(canvas); + } + canvas._iTextInstances = canvas._iTextInstances || []; + canvas._iTextInstances.push(_this); + } + }); + }, + + initRemovedHandler: function() { + var _this = this; + this.on('removed', function() { + var canvas = _this.canvas; + if (canvas) { + canvas._iTextInstances = canvas._iTextInstances || []; + fabric.util.removeFromArray(canvas._iTextInstances, _this); + if (canvas._iTextInstances.length === 0) { + canvas._hasITextHandlers = false; + _this._removeCanvasHandlers(canvas); + } + } + }); + }, + + /** + * register canvas event to manage exiting on other instances + * @private + */ + _initCanvasHandlers: function(canvas) { + canvas._mouseUpITextHandler = (function() { + if (canvas._iTextInstances) { + canvas._iTextInstances.forEach(function(obj) { + obj.__isMousedown = false; + }); + } + }).bind(this); + canvas.on('mouse:up', canvas._mouseUpITextHandler); + }, + + /** + * remove canvas event to manage exiting on other instances + * @private + */ + _removeCanvasHandlers: function(canvas) { + canvas.off('mouse:up', canvas._mouseUpITextHandler); + }, + + /** + * @private + */ + _tick: function() { + this._currentTickState = this._animateCursor(this, 1, this.cursorDuration, '_onTickComplete'); + }, + + /** + * @private + */ + _animateCursor: function(obj, targetOpacity, duration, completeMethod) { + + var tickState; + + tickState = { + isAborted: false, + abort: function() { + this.isAborted = true; + }, + }; + + obj.animate('_currentCursorOpacity', targetOpacity, { + duration: duration, + onComplete: function() { + if (!tickState.isAborted) { + obj[completeMethod](); + } + }, + onChange: function() { + // we do not want to animate a selection, only cursor + if (obj.canvas && obj.selectionStart === obj.selectionEnd) { + obj.renderCursorOrSelection(); + } + }, + abort: function() { + return tickState.isAborted; + } + }); + return tickState; + }, + + /** + * @private + */ + _onTickComplete: function() { + + var _this = this; + + if (this._cursorTimeout1) { + clearTimeout(this._cursorTimeout1); + } + this._cursorTimeout1 = setTimeout(function() { + _this._currentTickCompleteState = _this._animateCursor(_this, 0, this.cursorDuration / 2, '_tick'); + }, 100); + }, + + /** + * Initializes delayed cursor + */ + initDelayedCursor: function(restart) { + var _this = this, + delay = restart ? 0 : this.cursorDelay; + + this.abortCursorAnimation(); + this._currentCursorOpacity = 1; + this._cursorTimeout2 = setTimeout(function() { + _this._tick(); + }, delay); + }, + + /** + * Aborts cursor animation and clears all timeouts + */ + abortCursorAnimation: function() { + var shouldClear = this._currentTickState || this._currentTickCompleteState; + this._currentTickState && this._currentTickState.abort(); + this._currentTickCompleteState && this._currentTickCompleteState.abort(); + + clearTimeout(this._cursorTimeout1); + clearTimeout(this._cursorTimeout2); + + this._currentCursorOpacity = 0; + // to clear just itext area we need to transform the context + // it may not be worth it + if (shouldClear) { + this.canvas && this.canvas.clearContext(this.canvas.contextTop || this.ctx); + } + + }, + + /** + * Selects entire text + */ + selectAll: function() { + this.selectionStart = 0; + this.selectionEnd = this.text.length; + this._fireSelectionChanged(); + this._updateTextarea(); + }, + + /** + * Returns selected text + * @return {String} + */ + getSelectedText: function() { + return this.text.slice(this.selectionStart, this.selectionEnd); + }, + + /** + * Find new selection index representing start of current word according to current selection index + * @param {Number} startFrom Surrent selection index + * @return {Number} New selection index + */ + findWordBoundaryLeft: function(startFrom) { + var offset = 0, index = startFrom - 1; + + // remove space before cursor first + if (this._reSpace.test(this.text.charAt(index))) { + while (this._reSpace.test(this.text.charAt(index))) { + offset++; + index--; + } + } + while (/\S/.test(this.text.charAt(index)) && index > -1) { + offset++; + index--; + } + + return startFrom - offset; + }, + + /** + * Find new selection index representing end of current word according to current selection index + * @param {Number} startFrom Current selection index + * @return {Number} New selection index + */ + findWordBoundaryRight: function(startFrom) { + var offset = 0, index = startFrom; + + // remove space after cursor first + if (this._reSpace.test(this.text.charAt(index))) { + while (this._reSpace.test(this.text.charAt(index))) { + offset++; + index++; + } + } + while (/\S/.test(this.text.charAt(index)) && index < this.text.length) { + offset++; + index++; + } + + return startFrom + offset; + }, + + /** + * Find new selection index representing start of current line according to current selection index + * @param {Number} startFrom Current selection index + * @return {Number} New selection index + */ + findLineBoundaryLeft: function(startFrom) { + var offset = 0, index = startFrom - 1; + + while (!/\n/.test(this.text.charAt(index)) && index > -1) { + offset++; + index--; + } + + return startFrom - offset; + }, + + /** + * Find new selection index representing end of current line according to current selection index + * @param {Number} startFrom Current selection index + * @return {Number} New selection index + */ + findLineBoundaryRight: function(startFrom) { + var offset = 0, index = startFrom; + + while (!/\n/.test(this.text.charAt(index)) && index < this.text.length) { + offset++; + index++; + } + + return startFrom + offset; + }, + + /** + * Returns number of newlines in selected text + * @return {Number} Number of newlines in selected text + */ + getNumNewLinesInSelectedText: function() { + var selectedText = this.getSelectedText(), + numNewLines = 0; + + for (var i = 0, len = selectedText.length; i < len; i++) { + if (selectedText[i] === '\n') { + numNewLines++; + } + } + return numNewLines; + }, + + /** + * Finds index corresponding to beginning or end of a word + * @param {Number} selectionStart Index of a character + * @param {Number} direction 1 or -1 + * @return {Number} Index of the beginning or end of a word + */ + searchWordBoundary: function(selectionStart, direction) { + var index = this._reSpace.test(this.text.charAt(selectionStart)) ? selectionStart - 1 : selectionStart, + _char = this.text.charAt(index), + reNonWord = /[ \n\.,;!\?\-]/; + + while (!reNonWord.test(_char) && index > 0 && index < this.text.length) { + index += direction; + _char = this.text.charAt(index); + } + if (reNonWord.test(_char) && _char !== '\n') { + index += direction === 1 ? 0 : 1; + } + return index; + }, + + /** + * Selects a word based on the index + * @param {Number} selectionStart Index of a character + */ + selectWord: function(selectionStart) { + selectionStart = selectionStart || this.selectionStart; + var newSelectionStart = this.searchWordBoundary(selectionStart, -1), /* search backwards */ + newSelectionEnd = this.searchWordBoundary(selectionStart, 1); /* search forward */ + + this.selectionStart = newSelectionStart; + this.selectionEnd = newSelectionEnd; + this._fireSelectionChanged(); + this._updateTextarea(); + this.renderCursorOrSelection(); + }, + + /** + * Selects a line based on the index + * @param {Number} selectionStart Index of a character + */ + selectLine: function(selectionStart) { + selectionStart = selectionStart || this.selectionStart; + var newSelectionStart = this.findLineBoundaryLeft(selectionStart), + newSelectionEnd = this.findLineBoundaryRight(selectionStart); + + this.selectionStart = newSelectionStart; + this.selectionEnd = newSelectionEnd; + this._fireSelectionChanged(); + this._updateTextarea(); + }, + + /** + * Enters editing state + * @return {fabric.IText} thisArg + * @chainable + */ + enterEditing: function(e) { + if (this.isEditing || !this.editable) { + return; + } + + if (this.canvas) { + this.exitEditingOnOthers(this.canvas); + } + + this.isEditing = true; + this.selected = true; + this.initHiddenTextarea(e); + this.hiddenTextarea.focus(); + this._updateTextarea(); + this._saveEditingProps(); + this._setEditingProps(); + this._textBeforeEdit = this.text; + + this._tick(); + this.fire('editing:entered'); + this._fireSelectionChanged(); + if (!this.canvas) { + return this; + } + this.canvas.fire('text:editing:entered', { target: this }); + this.initMouseMoveHandler(); + this.canvas.renderAll(); + return this; + }, + + exitEditingOnOthers: function(canvas) { + if (canvas._iTextInstances) { + canvas._iTextInstances.forEach(function(obj) { + obj.selected = false; + if (obj.isEditing) { + obj.exitEditing(); + } + }); + } + }, + + /** + * Initializes "mousemove" event handler + */ + initMouseMoveHandler: function() { + this.canvas.on('mouse:move', this.mouseMoveHandler); + }, + + /** + * @private + */ + mouseMoveHandler: function(options) { + if (!this.__isMousedown || !this.isEditing) { + return; + } + + var newSelectionStart = this.getSelectionStartFromPointer(options.e), + currentStart = this.selectionStart, + currentEnd = this.selectionEnd; + if ( + (newSelectionStart !== this.__selectionStartOnMouseDown || currentStart === currentEnd) + && + (currentStart === newSelectionStart || currentEnd === newSelectionStart) + ) { + return; + } + if (newSelectionStart > this.__selectionStartOnMouseDown) { + this.selectionStart = this.__selectionStartOnMouseDown; + this.selectionEnd = newSelectionStart; + } + else { + this.selectionStart = newSelectionStart; + this.selectionEnd = this.__selectionStartOnMouseDown; + } + if (this.selectionStart !== currentStart || this.selectionEnd !== currentEnd) { + this.restartCursorIfNeeded(); + this._fireSelectionChanged(); + this._updateTextarea(); + this.renderCursorOrSelection(); + } + }, + + /** + * @private + */ + _setEditingProps: function() { + this.hoverCursor = 'text'; + + if (this.canvas) { + this.canvas.defaultCursor = this.canvas.moveCursor = 'text'; + } + + this.borderColor = this.editingBorderColor; + + this.hasControls = this.selectable = false; + this.lockMovementX = this.lockMovementY = true; + }, + + /** + * @private + */ + _updateTextarea: function() { + if (!this.hiddenTextarea || this.inCompositionMode) { + return; + } + this.cursorOffsetCache = { }; + this.hiddenTextarea.value = this.text; + this.hiddenTextarea.selectionStart = this.selectionStart; + this.hiddenTextarea.selectionEnd = this.selectionEnd; + if (this.selectionStart === this.selectionEnd) { + var style = this._calcTextareaPosition(); + this.hiddenTextarea.style.left = style.left; + this.hiddenTextarea.style.top = style.top; + this.hiddenTextarea.style.fontSize = style.fontSize; + } + }, + + /** + * @private + * @return {Object} style contains style for hiddenTextarea + */ + _calcTextareaPosition: function() { + if (!this.canvas) { + return { x: 1, y: 1 }; + } + var chars = this.text.split(''), + boundaries = this._getCursorBoundaries(chars, 'cursor'), + cursorLocation = this.get2DCursorLocation(), + lineIndex = cursorLocation.lineIndex, + charIndex = cursorLocation.charIndex, + charHeight = this.getCurrentCharFontSize(lineIndex, charIndex), + leftOffset = boundaries.leftOffset, + m = this.calcTransformMatrix(), + p = { + x: boundaries.left + leftOffset, + y: boundaries.top + boundaries.topOffset + charHeight + }, + upperCanvas = this.canvas.upperCanvasEl, + maxWidth = upperCanvas.width - charHeight, + maxHeight = upperCanvas.height - charHeight; + + p = fabric.util.transformPoint(p, m); + p = fabric.util.transformPoint(p, this.canvas.viewportTransform); + + if (p.x < 0) { + p.x = 0; + } + if (p.x > maxWidth) { + p.x = maxWidth; + } + if (p.y < 0) { + p.y = 0; + } + if (p.y > maxHeight) { + 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 }; + }, + + /** + * @private + */ + _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 + }; + }, + + /** + * @private + */ + _restoreEditingProps: function() { + if (!this._savedProps) { + return; + } + + 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; + + if (this.canvas) { + this.canvas.defaultCursor = this._savedProps.defaultCursor; + this.canvas.moveCursor = this._savedProps.moveCursor; + } + }, + + /** + * Exits from editing state + * @return {fabric.IText} thisArg + * @chainable + */ + exitEditing: function() { + var isTextChanged = (this._textBeforeEdit !== this.text); + this.selected = false; + this.isEditing = false; + this.selectable = true; + + this.selectionEnd = this.selectionStart; + + if (this.hiddenTextarea) { + this.hiddenTextarea.blur && this.hiddenTextarea.blur(); + this.canvas && this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea); + this.hiddenTextarea = null; + } + + this.abortCursorAnimation(); + this._restoreEditingProps(); + this._currentCursorOpacity = 0; + + this.fire('editing:exited'); + isTextChanged && this.fire('modified'); + if (this.canvas) { + this.canvas.off('mouse:move', this.mouseMoveHandler); + this.canvas.fire('text:editing:exited', { target: this }); + isTextChanged && this.canvas.fire('object:modified', { target: this }); + } + return this; + }, + + /** + * @private + */ + _removeExtraneousStyles: function() { + for (var prop in this.styles) { + if (!this._textLines[prop]) { + delete this.styles[prop]; + } + } + }, + + /** + * @private + */ + _removeCharsFromTo: function(start, end) { + while (end !== start) { + this._removeSingleCharAndStyle(start + 1); + end--; + } + this.selectionStart = start; + this.selectionEnd = start; + }, + + _removeSingleCharAndStyle: function(index) { + var isBeginningOfLine = this.text[index - 1] === '\n', + indexStyle = isBeginningOfLine ? index : index - 1; + this.removeStyleObject(isBeginningOfLine, indexStyle); + this.text = this.text.slice(0, index - 1) + + this.text.slice(index); + + this._textLines = this._splitTextIntoLines(); + }, + + /** + * Inserts characters where cursor is (replacing selection if one exists) + * @param {String} _chars Characters to insert + * @param {Boolean} useCopiedStyle use fabric.copiedTextStyle + */ + insertChars: function(_chars, useCopiedStyle) { + var style; + + if (this.selectionEnd - this.selectionStart > 1) { + this._removeCharsFromTo(this.selectionStart, this.selectionEnd); + } + //short circuit for block paste + if (!useCopiedStyle && this.isEmptyStyles()) { + this.insertChar(_chars, false); + return; + } + for (var i = 0, len = _chars.length; i < len; i++) { + if (useCopiedStyle) { + style = fabric.util.object.clone(fabric.copiedTextStyle[i], true); + } + this.insertChar(_chars[i], i < len - 1, style); + } + }, + + /** + * Inserts a character where cursor is + * @param {String} _char Characters to insert + * @param {Boolean} skipUpdate trigger rendering and updates at the end of text insert + * @param {Object} styleObject Style to be inserted for the new char + */ + insertChar: function(_char, skipUpdate, styleObject) { + var isEndOfLine = this.text[this.selectionStart] === '\n'; + this.text = this.text.slice(0, this.selectionStart) + + _char + this.text.slice(this.selectionEnd); + this._textLines = this._splitTextIntoLines(); + this.insertStyleObjects(_char, isEndOfLine, styleObject); + this.selectionStart += _char.length; + this.selectionEnd = this.selectionStart; + if (skipUpdate) { + return; + } + this._updateTextarea(); + this.setCoords(); + this._fireSelectionChanged(); + this.fire('changed'); + this.restartCursorIfNeeded(); + if (this.canvas) { + this.canvas.fire('text:changed', { target: this }); + this.canvas.renderAll(); + } + }, + + restartCursorIfNeeded: function() { + if (!this._currentTickState || this._currentTickState.isAborted + || !this._currentTickCompleteState || this._currentTickCompleteState.isAborted + ) { + this.initDelayedCursor(); + } + }, + + /** + * Inserts new style object + * @param {Number} lineIndex Index of a line + * @param {Number} charIndex Index of a char + * @param {Boolean} isEndOfLine True if it's end of line + */ + insertNewlineStyleObject: function(lineIndex, charIndex, isEndOfLine) { + + this.shiftLineStyles(lineIndex, +1); + + var currentCharStyle = {}, + newLineStyles = {}; + + if (this.styles[lineIndex] && this.styles[lineIndex][charIndex - 1]) { + currentCharStyle = this.styles[lineIndex][charIndex - 1]; + } + + // if there's nothing after cursor, + // we clone current char style onto the next (otherwise empty) line + if (isEndOfLine && currentCharStyle) { + newLineStyles[0] = clone(currentCharStyle); + this.styles[lineIndex + 1] = newLineStyles; + } + // otherwise we clone styles of all chars + // after cursor onto the next line, from the beginning + else { + var somethingAdded = false; + for (var index in this.styles[lineIndex]) { + var numIndex = parseInt(index, 10); + if (numIndex >= charIndex) { + somethingAdded = true; + newLineStyles[numIndex - charIndex] = this.styles[lineIndex][index]; + // remove lines from the previous line since they're on a new line now + delete this.styles[lineIndex][index]; + } + } + somethingAdded && (this.styles[lineIndex + 1] = newLineStyles); + } + this._forceClearCache = true; + }, + + /** + * Inserts style object for a given line/char index + * @param {Number} lineIndex Index of a line + * @param {Number} charIndex Index of a char + * @param {Object} [style] Style object to insert, if given + */ + insertCharStyleObject: function(lineIndex, charIndex, style) { + + var currentLineStyles = this.styles[lineIndex], + currentLineStylesCloned = clone(currentLineStyles); + + if (charIndex === 0 && !style) { + charIndex = 1; + } + + // shift all char styles by 1 forward + // 0,1,2,3 -> (charIndex=2) -> 0,1,3,4 -> (insert 2) -> 0,1,2,3,4 + for (var index in currentLineStylesCloned) { + var numericIndex = parseInt(index, 10); + + if (numericIndex >= charIndex) { + currentLineStyles[numericIndex + 1] = currentLineStylesCloned[numericIndex]; + + // only delete the style if there was nothing moved there + if (!currentLineStylesCloned[numericIndex - 1]) { + delete currentLineStyles[numericIndex]; + } + } + } + var newStyle = style || clone(currentLineStyles[charIndex - 1]); + newStyle && (this.styles[lineIndex][charIndex] = newStyle); + this._forceClearCache = true; + }, + + /** + * Inserts style object(s) + * @param {String} _chars Characters at the location where style is inserted + * @param {Boolean} isEndOfLine True if it's end of line + * @param {Object} [styleObject] Style to insert + */ + insertStyleObjects: function(_chars, isEndOfLine, styleObject) { + // removed shortcircuit over isEmptyStyles + + var cursorLocation = this.get2DCursorLocation(), + lineIndex = cursorLocation.lineIndex, + charIndex = cursorLocation.charIndex; + + if (!this._getLineStyle(lineIndex)) { + this._setLineStyle(lineIndex, {}); + } + + if (_chars === '\n') { + this.insertNewlineStyleObject(lineIndex, charIndex, isEndOfLine); + } + else { + this.insertCharStyleObject(lineIndex, charIndex, styleObject); + } + }, + + /** + * Shifts line styles up or down + * @param {Number} lineIndex Index of a line + * @param {Number} offset Can be -1 or +1 + */ + shiftLineStyles: function(lineIndex, offset) { + // shift all line styles by 1 upward or downward + var clonedStyles = clone(this.styles); + for (var line in clonedStyles) { + var numericLine = parseInt(line, 10); + if (numericLine <= lineIndex) { + delete clonedStyles[numericLine]; + } + } + for (var line in this.styles) { + var numericLine = parseInt(line, 10); + if (numericLine > lineIndex) { + this.styles[numericLine + offset] = clonedStyles[numericLine]; + if (!clonedStyles[numericLine - offset]) { + delete this.styles[numericLine]; + } + } + } + //TODO: evaluate if delete old style lines with offset -1 + }, + + /** + * Removes style object + * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line + * @param {Number} [index] Optional index. When not given, current selectionStart is used. + */ + removeStyleObject: function(isBeginningOfLine, index) { + + var cursorLocation = this.get2DCursorLocation(index), + lineIndex = cursorLocation.lineIndex, + charIndex = cursorLocation.charIndex; + + this._removeStyleObject(isBeginningOfLine, cursorLocation, lineIndex, charIndex); + }, + + _getTextOnPreviousLine: function(lIndex) { + return this._textLines[lIndex - 1]; + }, + + _removeStyleObject: function(isBeginningOfLine, cursorLocation, lineIndex, charIndex) { + + if (isBeginningOfLine) { + var textOnPreviousLine = this._getTextOnPreviousLine(cursorLocation.lineIndex), + newCharIndexOnPrevLine = textOnPreviousLine ? textOnPreviousLine.length : 0; + + if (!this.styles[lineIndex - 1]) { + this.styles[lineIndex - 1] = {}; + } + for (charIndex in this.styles[lineIndex]) { + this.styles[lineIndex - 1][parseInt(charIndex, 10) + newCharIndexOnPrevLine] + = this.styles[lineIndex][charIndex]; + } + this.shiftLineStyles(cursorLocation.lineIndex, -1); + } + else { + var currentLineStyles = this.styles[lineIndex]; + + if (currentLineStyles) { + delete currentLineStyles[charIndex]; + } + var currentLineStylesCloned = clone(currentLineStyles); + // shift all styles by 1 backwards + for (var i in currentLineStylesCloned) { + var numericIndex = parseInt(i, 10); + if (numericIndex >= charIndex && numericIndex !== 0) { + currentLineStyles[numericIndex - 1] = currentLineStylesCloned[numericIndex]; + delete currentLineStyles[numericIndex]; + } + } + } + }, + + /** + * Inserts new line + */ + 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; + } + } + }); +})(); + + +fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ { + /** + * Initializes "dbclick" event handler + */ + initDoubleClickSimulation: function() { + + // for double click + this.__lastClickTime = +new Date(); + + // for triple click + this.__lastLastClickTime = +new Date(); + + this.__lastPointer = { }; + + this.on('mousedown', this.onMouseDown.bind(this)); + }, + + onMouseDown: function(options) { + + this.__newClickTime = +new Date(); + var newPointer = this.canvas.getPointer(options.e); + + if (this.isTripleClick(newPointer, options.e)) { + this.fire('tripleclick', options); + this._stopEvent(options.e); + } + else if (this.isDoubleClick(newPointer)) { + this.fire('dblclick', options); + this._stopEvent(options.e); + } + + this.__lastLastClickTime = this.__lastClickTime; + this.__lastClickTime = this.__newClickTime; + this.__lastPointer = newPointer; + this.__lastIsEditing = this.isEditing; + this.__lastSelected = this.selected; + }, + + isDoubleClick: function(newPointer) { + return this.__newClickTime - this.__lastClickTime < 500 && + this.__lastPointer.x === newPointer.x && + this.__lastPointer.y === newPointer.y && this.__lastIsEditing; + }, + + isTripleClick: function(newPointer) { + return this.__newClickTime - this.__lastClickTime < 500 && + this.__lastClickTime - this.__lastLastClickTime < 500 && + this.__lastPointer.x === newPointer.x && + this.__lastPointer.y === newPointer.y; + }, + + /** + * @private + */ + _stopEvent: function(e) { + e.preventDefault && e.preventDefault(); + e.stopPropagation && e.stopPropagation(); + }, + + /** + * Initializes event handlers related to cursor or selection + */ + initCursorSelectionHandlers: function() { + this.initMousedownHandler(); + this.initMouseupHandler(); + this.initClicks(); + }, + + /** + * Initializes double and triple click event handlers + */ + initClicks: function() { + this.on('dblclick', function(options) { + this.selectWord(this.getSelectionStartFromPointer(options.e)); + }); + this.on('tripleclick', function(options) { + this.selectLine(this.getSelectionStartFromPointer(options.e)); + }); + }, + + /** + * Initializes "mousedown" event handler + */ + initMousedownHandler: function() { + this.on('mousedown', function(options) { + if (!this.editable || (options.e.button && options.e.button !== 1)) { + return; + } + var pointer = this.canvas.getPointer(options.e); + this.__mousedownX = pointer.x; + this.__mousedownY = pointer.y; + this.__isMousedown = true; + + if (this.selected) { + this.setCursorByClick(options.e); + } + + if (this.isEditing) { + this.__selectionStartOnMouseDown = this.selectionStart; + if (this.selectionStart === this.selectionEnd) { + this.abortCursorAnimation(); + } + this.renderCursorOrSelection(); + } + }); + }, + + /** + * @private + */ + _isObjectMoved: function(e) { + var pointer = this.canvas.getPointer(e); + + return this.__mousedownX !== pointer.x || + this.__mousedownY !== pointer.y; + }, + + /** + * Initializes "mouseup" event handler + */ + initMouseupHandler: function() { + this.on('mouseup', function(options) { + this.__isMousedown = false; + if (!this.editable || this._isObjectMoved(options.e) || (options.e.button && options.e.button !== 1)) { + return; + } + + if (this.__lastSelected && !this.__corner) { + this.enterEditing(options.e); + if (this.selectionStart === this.selectionEnd) { + this.initDelayedCursor(true); + } + else { + this.renderCursorOrSelection(); + } + } + this.selected = true; + }); + }, + + /** + * Changes cursor location in a text depending on passed pointer (x/y) object + * @param {Event} e Event object + */ + setCursorByClick: function(e) { + var newSelection = this.getSelectionStartFromPointer(e), + start = this.selectionStart, end = this.selectionEnd; + if (e.shiftKey) { + this.setSelectionStartEndWithShift(start, end, newSelection); + } + else { + this.selectionStart = newSelection; + this.selectionEnd = newSelection; + } + if (this.isEditing) { + this._fireSelectionChanged(); + this._updateTextarea(); + } + }, + + /** + * Returns index of a character corresponding to where an object was clicked + * @param {Event} e Event object + * @return {Number} Index of a character + */ + getSelectionStartFromPointer: function(e) { + var mouseOffset = this.getLocalPointer(e), + prevWidth = 0, + width = 0, + height = 0, + charIndex = 0, + newSelectionStart, + line; + + for (var i = 0, len = this._textLines.length; i < len; i++) { + line = this._textLines[i]; + height += this._getHeightOfLine(this.ctx, i) * this.scaleY; + + var widthOfLine = this._getLineWidth(this.ctx, i), + lineLeftOffset = this._getLineLeftOffset(widthOfLine); + + width = lineLeftOffset * this.scaleX; + + for (var j = 0, jlen = line.length; j < jlen; j++) { + + prevWidth = width; + + width += this._getWidthOfChar(this.ctx, line[j], i, this.flipX ? jlen - j : j) * + this.scaleX; + + if (height <= mouseOffset.y || width <= mouseOffset.x) { + charIndex++; + continue; + } + + return this._getNewSelectionStartFromOffset( + mouseOffset, prevWidth, width, charIndex + i, jlen); + } + + if (mouseOffset.y < height) { + //this happens just on end of lines. + return this._getNewSelectionStartFromOffset( + mouseOffset, prevWidth, width, charIndex + i - 1, jlen); + } + } + + // clicked somewhere after all chars, so set at the end + if (typeof newSelectionStart === 'undefined') { + return this.text.length; + } + }, + + /** + * @private + */ + _getNewSelectionStartFromOffset: function(mouseOffset, prevWidth, width, index, jlen) { + + var distanceBtwLastCharAndCursor = mouseOffset.x - prevWidth, + distanceBtwNextCharAndCursor = width - mouseOffset.x, + offset = distanceBtwNextCharAndCursor > distanceBtwLastCharAndCursor ? 0 : 1, + newSelectionStart = index + offset; + + // if object is horizontally flipped, mirror cursor location from the end + if (this.flipX) { + newSelectionStart = jlen - newSelectionStart; + } + + if (newSelectionStart > this.text.length) { + newSelectionStart = this.text.length; + } + + return newSelectionStart; + } +}); + + +fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ { + + /** + * Initializes hidden textarea (needed to bring up keyboard in iOS) + */ + initHiddenTextarea: function() { + this.hiddenTextarea = fabric.document.createElement('textarea'); + this.hiddenTextarea.setAttribute('autocapitalize', 'off'); + this.hiddenTextarea.setAttribute('autocorrect', 'off'); + this.hiddenTextarea.setAttribute('autocomplete', 'off'); + this.hiddenTextarea.setAttribute('spellcheck', 'false'); + this.hiddenTextarea.setAttribute('data-fabric-hiddentextarea', ''); + this.hiddenTextarea.setAttribute('wrap', 'off'); + var style = this._calcTextareaPosition(); + this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top + + '; left: ' + style.left + '; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px;' + + ' line-height: 1px; paddingーtop: ' + style.fontSize + ';'; + 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)); + + if (!this._clickHandlerInitialized && this.canvas) { + fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.onClick.bind(this)); + this._clickHandlerInitialized = true; + } + }, + + /** + * For functionalities on keyDown + * Map a special key to a function of the instance/prototype + * If you need different behaviour for ESC or TAB or arrows, you have to change + * this map setting the name of a function that you build on the fabric.Itext or + * your prototype. + * the map change will affect all Instances unless you need for only some text Instances + * in that case you have to clone this object and assign your Instance. + * this.keysMap = fabric.util.object.clone(this.keysMap); + * The function must be in fabric.Itext.prototype.myFunction And will receive event as args[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' + }, + + /** + * For functionalities on keyUp + ctrl || cmd + */ + ctrlKeysMapUp: { + 67: 'copy', + 88: 'cut' + }, + + /** + * For functionalities on keyDown + ctrl || cmd + */ + ctrlKeysMapDown: { + 65: 'selectAll' + }, + + onClick: function() { + // No need to trigger click event here, focus is enough to have the keyboard appear on Android + this.hiddenTextarea && this.hiddenTextarea.focus(); + }, + + /** + * Handles keyup event + * @param {Event} e Event object + */ + onKeyDown: function(e) { + if (!this.isEditing) { + return; + } + if (e.keyCode in this.keysMap) { + this[this.keysMap[e.keyCode]](e); + } + else if ((e.keyCode in this.ctrlKeysMapDown) && (e.ctrlKey || e.metaKey)) { + this[this.ctrlKeysMapDown[e.keyCode]](e); + } + else { + return; + } + e.stopImmediatePropagation(); + e.preventDefault(); + if (e.keyCode >= 33 && e.keyCode <= 40) { + // if i press an arrow key just update selection + this.clearContextTop(); + this.renderCursorOrSelection(); + } + else { + this.canvas && this.canvas.renderAll(); + } + }, + + /** + * Handles keyup event + * We handle KeyUp because ie11 and edge have difficulties copy/pasting + * if a copy/cut event fired, keyup is dismissed + * @param {Event} e Event object + */ + onKeyUp: function(e) { + if (!this.isEditing || this._copyDone) { + this._copyDone = false; + return; + } + if ((e.keyCode in this.ctrlKeysMapUp) && (e.ctrlKey || e.metaKey)) { + this[this.ctrlKeysMapUp[e.keyCode]](e); + } + else { + return; + } + e.stopImmediatePropagation(); + e.preventDefault(); + this.canvas && this.canvas.renderAll(); + }, + + /** + * Handles onInput event + * @param {Event} e Event object + */ + onInput: function(e) { + if (!this.isEditing || this.inCompositionMode) { + return; + } + var offset = this.selectionStart || 0, + offsetEnd = this.selectionEnd || 0, + textLength = this.text.length, + newTextLength = this.hiddenTextarea.value.length, + diff, charsToInsert, start; + if (newTextLength > textLength) { + //we added some character + start = this._selectionDirection === 'left' ? offsetEnd : offset; + diff = newTextLength - textLength; + charsToInsert = this.hiddenTextarea.value.slice(start, start + diff); + } + else { + //we selected a portion of text and then input something else. + //Internet explorer does not trigger this else + diff = newTextLength - textLength + offsetEnd - offset; + charsToInsert = this.hiddenTextarea.value.slice(offset, offset + diff); + } + this.insertChars(charsToInsert); + e.stopPropagation(); + }, + + /** + * Composition start + */ + onCompositionStart: function() { + this.inCompositionMode = true; + this.prevCompositionLength = 0; + this.compositionStart = this.selectionStart; + }, + + /** + * Composition end + */ + onCompositionEnd: function() { + this.inCompositionMode = false; + }, + + /** + * Composition update + */ + onCompositionUpdate: function(e) { + var data = e.data; + this.selectionStart = this.compositionStart; + this.selectionEnd = this.selectionEnd === this.selectionStart ? + this.compositionStart + this.prevCompositionLength : this.selectionEnd; + this.insertChars(data, false); + this.prevCompositionLength = data.length; + }, + + /** + * Forward delete + */ + forwardDelete: function(e) { + if (this.selectionStart === this.selectionEnd) { + if (this.selectionStart === this.text.length) { + return; + } + this.moveCursorRight(e); + } + this.removeChars(e); + }, + + /** + * Copies selected text + * @param {Event} e Event object + */ + copy: function(e) { + if (this.selectionStart === this.selectionEnd) { + //do not cut-copy if no selection + return; + } + var selectedText = this.getSelectedText(), + clipboardData = this._getClipboardData(e); + + // Check for backward compatibility with old browsers + if (clipboardData) { + clipboardData.setData('text', selectedText); + } + + fabric.copiedText = selectedText; + fabric.copiedTextStyle = this.getSelectionStyles(this.selectionStart, this.selectionEnd); + e.stopImmediatePropagation(); + e.preventDefault(); + this._copyDone = true; + }, + + /** + * Pastes text + * @param {Event} e Event object + */ + paste: function(e) { + var copiedText = null, + clipboardData = this._getClipboardData(e), + useCopiedStyle = true; + + // Check for backward compatibility with old browsers + if (clipboardData) { + copiedText = clipboardData.getData('text').replace(/\r/g, ''); + if (!fabric.copiedTextStyle || fabric.copiedText !== copiedText) { + useCopiedStyle = false; + } + } + else { + copiedText = fabric.copiedText; + } + + if (copiedText) { + this.insertChars(copiedText, useCopiedStyle); + } + e.stopImmediatePropagation(); + e.preventDefault(); + }, + + /** + * Cuts text + * @param {Event} e Event object + */ + cut: function(e) { + if (this.selectionStart === this.selectionEnd) { + return; + } + + this.copy(e); + this.removeChars(e); + }, + + /** + * @private + * @param {Event} e Event object + * @return {Object} Clipboard data object + */ + _getClipboardData: function(e) { + 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 + * @param {Boolean} isRight + * @return {Number} + */ + getDownCursorOffset: function(e, isRight) { + var selectionProp = this._getSelectionForOffset(e, isRight), + cursorLocation = this.get2DCursorLocation(selectionProp), + 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); + + 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 + */ + _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 = widthOfCharsOnLine - widthOfChar, + rightEdge = widthOfCharsOnLine, + offsetFromLeftEdge = Math.abs(leftEdge - width), + offsetFromRightEdge = Math.abs(rightEdge - width); + + indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1); + + break; + } + } + + // reached end + if (!foundMatch) { + indexOnLine = textOnLine.length - 1; + } + + return indexOnLine; + }, + + + /** + * Moves cursor down + * @param {Event} e Event object + */ + moveCursorDown: function(e) { + if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) { + return; + } + this._moveCursorUpOrDown('Down', e); + }, + + /** + * Moves cursor up + * @param {Event} e Event object + */ + moveCursorUp: function(e) { + if (this.selectionStart === 0 && this.selectionEnd === 0) { + return; + } + this._moveCursorUpOrDown('Up', e); + }, + + /** + * Moves cursor up or down, fires the events + * @param {String} direction 'Up' or 'Down' + * @param {Event} e Event object + */ + _moveCursorUpOrDown: function(direction, e) { + // getUpCursorOffset + // getDownCursorOffset + var action = 'get' + direction + 'CursorOffset', + offset = this[action](e, this._selectionDirection === 'right'); + if (e.shiftKey) { + this.moveCursorWithShift(offset); + } + else { + this.moveCursorWithoutShift(offset); + } + if (offset !== 0) { + this.setSelectionInBoundaries(); + this.abortCursorAnimation(); + this._currentCursorOpacity = 1; + this.initDelayedCursor(); + this._fireSelectionChanged(); + this._updateTextarea(); + } + }, + + /** + * Moves cursor with shift + * @param {Number} offset + */ + moveCursorWithShift: function(offset) { + var newSelection = this._selectionDirection === 'left' + ? this.selectionStart + offset + : this.selectionEnd + offset; + this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection); + return offset !== 0; + }, + + /** + * Moves cursor up without shift + * @param {Number} offset + */ + moveCursorWithoutShift: function(offset) { + if (offset < 0) { + this.selectionStart += offset; + this.selectionEnd = this.selectionStart; + } + else { + this.selectionEnd += offset; + this.selectionStart = this.selectionEnd; + } + return offset !== 0; + }, + + /** + * Moves cursor left + * @param {Event} e Event object + */ + moveCursorLeft: function(e) { + if (this.selectionStart === 0 && this.selectionEnd === 0) { + return; + } + this._moveCursorLeftOrRight('Left', e); + }, + + /** + * @private + * @return {Boolean} true if a change happened + */ + _move: function(e, prop, direction) { + var newValue; + if (e.altKey) { + newValue = this['findWordBoundary' + direction](this[prop]); + } + else if (e.metaKey || e.keyCode === 35 || e.keyCode === 36 ) { + newValue = this['findLineBoundary' + direction](this[prop]); + } + else { + this[prop] += direction === 'Left' ? -1 : 1; + return true; + } + if (typeof newValue !== undefined && this[prop] !== newValue) { + this[prop] = newValue; + return true; + } + }, + + /** + * @private + */ + _moveLeft: function(e, prop) { + return this._move(e, prop, 'Left'); + }, + + /** + * @private + */ + _moveRight: function(e, prop) { + return this._move(e, prop, 'Right'); + }, + + /** + * Moves cursor left without keeping selection + * @param {Event} e + */ + moveCursorLeftWithoutShift: function(e) { + var change = true; + this._selectionDirection = 'left'; + + // only move cursor when there is no selection, + // otherwise we discard it, and leave cursor on same place + if (this.selectionEnd === this.selectionStart && this.selectionStart !== 0) { + change = this._moveLeft(e, 'selectionStart'); + + } + this.selectionEnd = this.selectionStart; + return change; + }, + + /** + * Moves cursor left while keeping selection + * @param {Event} e + */ + moveCursorLeftWithShift: function(e) { + if (this._selectionDirection === 'right' && this.selectionStart !== this.selectionEnd) { + return this._moveLeft(e, 'selectionEnd'); + } + else if (this.selectionStart !== 0){ + this._selectionDirection = 'left'; + return this._moveLeft(e, 'selectionStart'); + } + }, + + /** + * Moves cursor right + * @param {Event} e Event object + */ + moveCursorRight: function(e) { + if (this.selectionStart >= this.text.length && this.selectionEnd >= this.text.length) { + return; + } + this._moveCursorLeftOrRight('Right', e); + }, + + /** + * Moves cursor right or Left, fires event + * @param {String} direction 'Left', 'Right' + * @param {Event} e Event object + */ + _moveCursorLeftOrRight: function(direction, e) { + var actionName = 'moveCursor' + direction + 'With'; + this._currentCursorOpacity = 1; + + if (e.shiftKey) { + actionName += 'Shift'; + } + else { + actionName += 'outShift'; + } + if (this[actionName](e)) { + this.abortCursorAnimation(); + this.initDelayedCursor(); + this._fireSelectionChanged(); + this._updateTextarea(); + } + }, + + /** + * Moves cursor right while keeping selection + * @param {Event} e + */ + moveCursorRightWithShift: function(e) { + if (this._selectionDirection === 'left' && this.selectionStart !== this.selectionEnd) { + return this._moveRight(e, 'selectionStart'); + } + else if (this.selectionEnd !== this.text.length) { + this._selectionDirection = 'right'; + return this._moveRight(e, 'selectionEnd'); + } + }, + + /** + * Moves cursor right without keeping selection + * @param {Event} e Event object + */ + moveCursorRightWithoutShift: function(e) { + var changed = true; + this._selectionDirection = 'right'; + + if (this.selectionStart === this.selectionEnd) { + changed = this._moveRight(e, 'selectionStart'); + this.selectionEnd = this.selectionStart; + } + else { + this.selectionStart = this.selectionEnd; + } + return changed; + }, + + /** + * Removes characters selected by selection + * @param {Event} e Event object + */ + removeChars: function(e) { + if (this.selectionStart === this.selectionEnd) { + this._removeCharsNearCursor(e); + } + else { + this._removeCharsFromTo(this.selectionStart, this.selectionEnd); + } + + this.set('dirty', true); + 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 }); + }, + + /** + * @private + * @param {Event} e Event object + */ + _removeCharsNearCursor: function(e) { + if (this.selectionStart === 0) { + return; + } + if (e.metaKey) { + // remove all till the start of current line + var leftLineBoundary = this.findLineBoundaryLeft(this.selectionStart); + + this._removeCharsFromTo(leftLineBoundary, this.selectionStart); + this.setSelectionStart(leftLineBoundary); + } + else if (e.altKey) { + // remove all till the start of current word + var leftWordBoundary = this.findWordBoundaryLeft(this.selectionStart); + + this._removeCharsFromTo(leftWordBoundary, this.selectionStart); + this.setSelectionStart(leftWordBoundary); + } + else { + this._removeSingleCharAndStyle(this.selectionStart); + this.setSelectionStart(this.selectionStart - 1); + } + } +}); + + +/* _TO_SVG_START_ */ +(function() { + var toFixed = fabric.util.toFixed, + NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS; + + fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ { + + /** + * @private + */ + _setSVGTextLineText: function(lineIndex, textSpans, height, textLeftOffset, textTopOffset, textBgRects) { + if (!this._getLineStyle(lineIndex)) { + fabric.Text.prototype._setSVGTextLineText.call(this, + lineIndex, textSpans, height, textLeftOffset, textTopOffset); + } + else { + this._setSVGTextLineChars( + lineIndex, textSpans, height, textLeftOffset, textBgRects); + } + }, + + /** + * @private + */ + _setSVGTextLineChars: function(lineIndex, textSpans, height, textLeftOffset, textBgRects) { + + var chars = this._textLines[lineIndex], + charOffset = 0, + lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, lineIndex)) - this.width / 2, + lineOffset = this._getSVGLineTopOffset(lineIndex), + heightOfLine = this._getHeightOfLine(this.ctx, lineIndex); + + for (var i = 0, len = chars.length; i < len; i++) { + var styleDecl = this._getStyleDeclaration(lineIndex, i) || { }; + + textSpans.push( + this._createTextCharSpan( + chars[i], styleDecl, lineLeftOffset, lineOffset.lineTop + lineOffset.offset, charOffset)); + + var charWidth = this._getWidthOfChar(this.ctx, chars[i], lineIndex, i); + + if (styleDecl.textBackgroundColor) { + textBgRects.push( + this._createTextCharBg( + styleDecl, lineLeftOffset, lineOffset.lineTop, heightOfLine, charWidth, charOffset)); + } + + charOffset += charWidth; + } + }, + + /** + * @private + */ + _getSVGLineTopOffset: function(lineIndex) { + var lineTopOffset = 0, lastHeight = 0; + for (var j = 0; j < lineIndex; j++) { + lineTopOffset += this._getHeightOfLine(this.ctx, j); + } + lastHeight = this._getHeightOfLine(this.ctx, j); + return { + lineTop: lineTopOffset, + offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult) + }; + }, + + /** + * @private + */ + _createTextCharBg: function(styleDecl, lineLeftOffset, lineTopOffset, heightOfLine, charWidth, charOffset) { + return [ + '\t\t\n' + ].join(''); + }, + + /** + * @private + */ + _createTextCharSpan: function(_char, styleDecl, lineLeftOffset, lineTopOffset, charOffset) { + + var fillStyles = this.getSvgStyles.call(fabric.util.object.extend({ + visible: true, + fill: this.fill, + stroke: this.stroke, + type: 'text', + getSvgFilter: fabric.Object.prototype.getSvgFilter + }, styleDecl)); + + return [ + '\t\t\t', + fabric.util.string.escapeXml(_char), + '\n' + ].join(''); + }, + }); +})(); +/* _TO_SVG_END_ */ + + +(function(global) { + + 'use strict'; + + var fabric = global.fabric || (global.fabric = {}); + + /** + * Textbox class, based on IText, allows the user to resize the text rectangle + * and wraps lines automatically. Textboxes have their Y scaling locked, the + * user can only change width. Height is adjusted automatically based on the + * wrapping of lines. + * @class fabric.Textbox + * @extends fabric.IText + * @mixes fabric.Observable + * @return {fabric.Textbox} thisArg + * @see {@link fabric.Textbox#initialize} for constructor definition + */ + fabric.Textbox = fabric.util.createClass(fabric.IText, fabric.Observable, { + + /** + * Type of an object + * @type String + * @default + */ + type: 'textbox', + + /** + * Minimum width of textbox, in pixels. + * @type Number + * @default + */ + minWidth: 20, + + /** + * 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: 2, + + /** + * Cached array of text wrapping. + * @type Array + */ + __cachedLines: null, + + /** + * Override standard Object class values + */ + lockScalingY: true, + + /** + * Override standard Object class values + */ + lockScalingFlip: true, + + /** + * Override standard Object class values + * Textbox needs this on false + */ + noScaleCache: false, + + /** + * Properties which when set cause object to change dimensions + * @type Object + * @private + */ + _dimensionAffectingProps: fabric.Text.prototype._dimensionAffectingProps.concat('width'), + + /** + * Constructor. Some scaling related property values are forced. Visibility + * of controls is also fixed; only the rotation and width controls are + * made available. + * @param {String} text Text string + * @param {Object} [options] Options object + * @return {fabric.Textbox} thisArg + */ + initialize: function(text, options) { + + this.callSuper('initialize', text, options); + this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility()); + this.ctx = this.objectCaching ? this._cacheContext : fabric.util.createCanvasElement().getContext('2d'); + }, + + /** + * Unlike superclass's version of this function, Textbox does not update + * its width. + * @param {CanvasRenderingContext2D} ctx Context to use for measurements + * @private + * @override + */ + _initDimensions: function(ctx) { + if (this.__skipDimension) { + return; + } + + if (!ctx) { + ctx = fabric.util.createCanvasElement().getContext('2d'); + this._setTextStyles(ctx); + this.clearContextTop(); + } + + // clear dynamicMinWidth as it will be different after we re-wrap line + this.dynamicMinWidth = 0; + + // wrap lines + this._textLines = this._splitTextIntoLines(ctx); + // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap + if (this.dynamicMinWidth > this.width) { + this._set('width', this.dynamicMinWidth); + } + + // clear cache and re-calculate height + this._clearCache(); + this.height = this._getTextHeight(ctx); + this.setCoords(); + }, + + /** + * Generate an object that translates the style object so that it is + * broken up by visual lines (new lines and automatic wrapping). + * The original text styles object is broken up by actual lines (new lines only), + * which is only sufficient for Text / IText + * @private + */ + _generateStyleMap: function() { + var realLineCount = 0, + realLineCharCount = 0, + charCount = 0, + map = {}; + + for (var i = 0; i < this._textLines.length; i++) { + if (this.text[charCount] === '\n' && i > 0) { + realLineCharCount = 0; + charCount++; + realLineCount++; + } + else if (this.text[charCount] === ' ' && i > 0) { + // this case deals with space's that are removed from end of lines when wrapping + realLineCharCount++; + charCount++; + } + + map[i] = { line: realLineCount, offset: realLineCharCount }; + + charCount += this._textLines[i].length; + realLineCharCount += this._textLines[i].length; + } + + return map; + }, + + /** + * @param {Number} lineIndex + * @param {Number} charIndex + * @param {Boolean} [returnCloneOrEmpty=false] + * @private + */ + _getStyleDeclaration: function(lineIndex, charIndex, returnCloneOrEmpty) { + if (this._styleMap) { + var map = this._styleMap[lineIndex]; + if (!map) { + return returnCloneOrEmpty ? { } : null; + } + lineIndex = map.line; + charIndex = map.offset + charIndex; + } + return this.callSuper('_getStyleDeclaration', lineIndex, charIndex, returnCloneOrEmpty); + }, + + /** + * @param {Number} lineIndex + * @param {Number} charIndex + * @param {Object} style + * @private + */ + _setStyleDeclaration: function(lineIndex, charIndex, style) { + var map = this._styleMap[lineIndex]; + lineIndex = map.line; + charIndex = map.offset + charIndex; + + this.styles[lineIndex][charIndex] = style; + }, + + /** + * @param {Number} lineIndex + * @param {Number} charIndex + * @private + */ + _deleteStyleDeclaration: function(lineIndex, charIndex) { + var map = this._styleMap[lineIndex]; + lineIndex = map.line; + charIndex = map.offset + charIndex; + + delete this.styles[lineIndex][charIndex]; + }, + + /** + * @param {Number} lineIndex + * @private + */ + _getLineStyle: function(lineIndex) { + var map = this._styleMap[lineIndex]; + return this.styles[map.line]; + }, + + /** + * @param {Number} lineIndex + * @param {Object} style + * @private + */ + _setLineStyle: function(lineIndex, style) { + var map = this._styleMap[lineIndex]; + this.styles[map.line] = style; + }, + + /** + * @param {Number} lineIndex + * @private + */ + _deleteLineStyle: function(lineIndex) { + var map = this._styleMap[lineIndex]; + delete this.styles[map.line]; + }, + + /** + * Wraps text using the 'width' property of Textbox. First this function + * splits text on newlines, so we preserve newlines entered by the user. + * Then it wraps each line using the width of the Textbox by calling + * _wrapLine(). + * @param {CanvasRenderingContext2D} ctx Context to use for measurements + * @param {String} text The string of text that is split into lines + * @returns {Array} Array of lines + */ + _wrapText: function(ctx, text) { + var lines = text.split(this._reNewline), wrapped = [], i; + + for (i = 0; i < lines.length; i++) { + wrapped = wrapped.concat(this._wrapLine(ctx, lines[i], i)); + } + + return wrapped; + }, + + /** + * Helper function to measure a string of text, given its lineIndex and charIndex offset + * + * @param {CanvasRenderingContext2D} ctx + * @param {String} text + * @param {number} lineIndex + * @param {number} charOffset + * @returns {number} + * @private + */ + _measureText: function(ctx, text, lineIndex, charOffset) { + var width = 0; + charOffset = charOffset || 0; + for (var i = 0, len = text.length; i < len; i++) { + width += this._getWidthOfChar(ctx, text[i], lineIndex, i + charOffset); + } + return width; + }, + + /** + * Wraps a line of text using the width of the Textbox and a context. + * @param {CanvasRenderingContext2D} ctx Context to use for measurements + * @param {String} text The string of text to split into lines + * @param {Number} lineIndex + * @returns {Array} Array of line(s) into which the given text is wrapped + * to. + */ + _wrapLine: function(ctx, text, lineIndex) { + var lineWidth = 0, + lines = [], + line = '', + words = text.split(' '), + word = '', + offset = 0, + infix = ' ', + wordWidth = 0, + infixWidth = 0, + largestWordWidth = 0, + lineJustStarted = true, + additionalSpace = this._getWidthOfCharSpacing(); + + for (var i = 0; i < words.length; i++) { + word = words[i]; + wordWidth = this._measureText(ctx, word, lineIndex, offset); + + offset += word.length; + + lineWidth += infixWidth + wordWidth - additionalSpace; + + if (lineWidth >= this.width && !lineJustStarted) { + lines.push(line); + line = ''; + lineWidth = wordWidth; + lineJustStarted = true; + } + else { + lineWidth += additionalSpace; + } + + if (!lineJustStarted) { + line += infix; + } + line += word; + + infixWidth = this._measureText(ctx, infix, lineIndex, offset); + offset++; + lineJustStarted = false; + // keep track of largest word + if (wordWidth > largestWordWidth) { + largestWordWidth = wordWidth; + } + } + + i && lines.push(line); + + if (largestWordWidth > this.dynamicMinWidth) { + this.dynamicMinWidth = largestWordWidth - additionalSpace; + } + + return lines; + }, + /** + * Gets lines of text to render in the Textbox. This function calculates + * text wrapping on the fly everytime it is called. + * @returns {Array} Array of lines in the Textbox. + * @override + */ + _splitTextIntoLines: function(ctx) { + ctx = ctx || this.ctx; + var originalAlign = this.textAlign; + this._styleMap = null; + ctx.save(); + this._setTextStyles(ctx); + this.textAlign = 'left'; + var lines = this._wrapText(ctx, this.text); + this.textAlign = originalAlign; + ctx.restore(); + this._textLines = lines; + this._styleMap = this._generateStyleMap(); + return lines; + }, + + /** + * When part of a group, we don't want the Textbox's scale to increase if + * the group's increases. That's why we reduce the scale of the Textbox by + * the amount that the group's increases. This is to maintain the effective + * scale of the Textbox at 1, so that font-size values make sense. Otherwise + * the same font-size value would result in different actual size depending + * on the value of the scale. + * @param {String} key + * @param {*} value + */ + setOnGroup: function(key, value) { + if (key === 'scaleX') { + this.set('scaleX', Math.abs(1 / value)); + this.set('width', (this.get('width') * value) / + (typeof this.__oldScaleX === 'undefined' ? 1 : this.__oldScaleX)); + this.__oldScaleX = value; + } + }, + + /** + * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start). + * Overrides the superclass function to take into account text wrapping. + * + * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used. + */ + get2DCursorLocation: function(selectionStart) { + if (typeof selectionStart === 'undefined') { + selectionStart = this.selectionStart; + } + + var numLines = this._textLines.length, + removed = 0; + + for (var i = 0; i < numLines; i++) { + var line = this._textLines[i], + lineLen = line.length; + + if (selectionStart <= removed + lineLen) { + return { + lineIndex: i, + charIndex: selectionStart - removed + }; + } + + removed += lineLen; + + if (this.text[removed] === '\n' || this.text[removed] === ' ') { + removed++; + } + } + + return { + lineIndex: numLines - 1, + charIndex: this._textLines[numLines - 1].length + }; + }, + + /** + * Overrides superclass function and uses text wrapping data to get cursor + * boundary offsets instead of the array of chars. + * @param {Array} chars Unused + * @param {String} typeOfBoundaries Can be 'cursor' or 'selection' + * @returns {Object} Object with 'top', 'left', and 'lineLeft' properties set. + */ + _getCursorBoundariesOffsets: function(chars, typeOfBoundaries) { + var topOffset = 0, + leftOffset = 0, + cursorLocation = this.get2DCursorLocation(), + lineChars = this._textLines[cursorLocation.lineIndex].split(''), + lineLeftOffset = this._getLineLeftOffset(this._getLineWidth(this.ctx, cursorLocation.lineIndex)); + + for (var i = 0; i < cursorLocation.charIndex; i++) { + leftOffset += this._getWidthOfChar(this.ctx, lineChars[i], cursorLocation.lineIndex, i); + } + + for (i = 0; i < cursorLocation.lineIndex; i++) { + topOffset += this._getHeightOfLine(this.ctx, i); + } + + if (typeOfBoundaries === 'cursor') { + topOffset += (1 - this._fontSizeFraction) * this._getHeightOfLine(this.ctx, cursorLocation.lineIndex) + / this.lineHeight - this.getCurrentCharFontSize(cursorLocation.lineIndex, cursorLocation.charIndex) + * (1 - this._fontSizeFraction); + } + + return { + top: topOffset, + left: leftOffset, + lineLeft: lineLeftOffset + }; + }, + + getMinWidth: function() { + return Math.max(this.minWidth, this.dynamicMinWidth); + }, + + /** + * Returns object representation of an instance + * @method toObject + * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output + * @return {Object} object representation of an instance + */ + toObject: function(propertiesToInclude) { + return this.callSuper('toObject', ['minWidth'].concat(propertiesToInclude)); + } + }); + + /** + * Returns fabric.Textbox instance from an object representation + * @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 + * @param {Boolean} [forceAsync] Force an async behaviour trying to create pattern first + * @return {fabric.Textbox} instance of fabric.Textbox + */ + fabric.Textbox.fromObject = function(object, callback, forceAsync) { + return fabric.Object._fromObject('Textbox', object, callback, forceAsync, 'text'); + }; + + /** + * Returns the default controls visibility required for Textboxes. + * @returns {Object} + */ + fabric.Textbox.getTextboxControlVisibility = function() { + return { + tl: false, + tr: false, + br: false, + bl: false, + ml: true, + mt: false, + mr: true, + mb: false, + mtr: true + }; + }; + +})(typeof exports !== 'undefined' ? exports : this); + + +(function() { + + /** + * Override _setObjectScale and add Textbox specific resizing behavior. Resizing + * a Textbox doesn't scale text, it only changes width and makes text wrap automatically. + */ + var setObjectScaleOverridden = fabric.Canvas.prototype._setObjectScale; + + fabric.Canvas.prototype._setObjectScale = function(localMouse, transform, + lockScalingX, lockScalingY, by, lockScalingFlip, _dim) { + + var t = transform.target; + if (t instanceof fabric.Textbox) { + var w = t.width * ((localMouse.x / transform.scaleX) / (t.width + t.strokeWidth)); + if (w >= t.getMinWidth()) { + t.set('width', w); + return true; + } + } + else { + return setObjectScaleOverridden.call(fabric.Canvas.prototype, localMouse, transform, + lockScalingX, lockScalingY, by, lockScalingFlip, _dim); + } + }; + + /** + * Sets controls of this group to the Textbox's special configuration if + * one is present in the group. Deletes _controlsVisibility otherwise, so that + * it gets initialized to default value at runtime. + */ + fabric.Group.prototype._refreshControlsVisibility = function() { + if (typeof fabric.Textbox === 'undefined') { + return; + } + for (var i = this._objects.length; i--;) { + if (this._objects[i] instanceof fabric.Textbox) { + this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility()); + return; + } + } + }; + + fabric.util.object.extend(fabric.Textbox.prototype, /** @lends fabric.IText.prototype */ { + /** + * @private + */ + _removeExtraneousStyles: function() { + for (var prop in this._styleMap) { + if (!this._textLines[prop]) { + delete this.styles[this._styleMap[prop].line]; + } + } + }, + + /** + * Inserts style object for a given line/char index + * @param {Number} lineIndex Index of a line + * @param {Number} charIndex Index of a char + * @param {Object} [style] Style object to insert, if given + */ + insertCharStyleObject: function(lineIndex, charIndex, style) { + // adjust lineIndex and charIndex + var map = this._styleMap[lineIndex]; + lineIndex = map.line; + charIndex = map.offset + charIndex; + + fabric.IText.prototype.insertCharStyleObject.apply(this, [lineIndex, charIndex, style]); + }, + + /** + * Inserts new style object + * @param {Number} lineIndex Index of a line + * @param {Number} charIndex Index of a char + * @param {Boolean} isEndOfLine True if it's end of line + */ + insertNewlineStyleObject: function(lineIndex, charIndex, isEndOfLine) { + // adjust lineIndex and charIndex + var map = this._styleMap[lineIndex]; + lineIndex = map.line; + charIndex = map.offset + charIndex; + + fabric.IText.prototype.insertNewlineStyleObject.apply(this, [lineIndex, charIndex, isEndOfLine]); + }, + + /** + * Shifts line styles up or down. This function is slightly different than the one in + * itext_behaviour as it takes into account the styleMap. + * + * @param {Number} lineIndex Index of a line + * @param {Number} offset Can be -1 or +1 + */ + shiftLineStyles: function(lineIndex, offset) { + // shift all line styles by 1 upward + var map = this._styleMap[lineIndex]; + // adjust line index + lineIndex = map.line; + fabric.IText.prototype.shiftLineStyles.call(this, lineIndex, offset); + }, + + /** + * Figure out programatically the text on previous actual line (actual = separated by \n); + * + * @param {Number} lIndex + * @returns {String} + * @private + */ + _getTextOnPreviousLine: function(lIndex) { + var textOnPreviousLine = this._textLines[lIndex - 1]; + + while (this._styleMap[lIndex - 2] && this._styleMap[lIndex - 2].line === this._styleMap[lIndex - 1].line) { + textOnPreviousLine = this._textLines[lIndex - 2] + textOnPreviousLine; + + lIndex--; + } + + return textOnPreviousLine; + }, + + /** + * Removes style object + * @param {Boolean} isBeginningOfLine True if cursor is at the beginning of line + * @param {Number} [index] Optional index. When not given, current selectionStart is used. + */ + removeStyleObject: function(isBeginningOfLine, index) { + + var cursorLocation = this.get2DCursorLocation(index), + map = this._styleMap[cursorLocation.lineIndex], + lineIndex = map.line, + charIndex = map.offset + cursorLocation.charIndex; + this._removeStyleObject(isBeginningOfLine, cursorLocation, lineIndex, charIndex); + } + }); +})(); + + +(function() { + var override = fabric.IText.prototype._getNewSelectionStartFromOffset; + /** + * Overrides the IText implementation and adjusts character index as there is not always a linebreak + * + * @param {Number} mouseOffset + * @param {Number} prevWidth + * @param {Number} width + * @param {Number} index + * @param {Number} jlen + * @returns {Number} + */ + fabric.IText.prototype._getNewSelectionStartFromOffset = function(mouseOffset, prevWidth, width, index, jlen) { + index = override.call(this, mouseOffset, prevWidth, width, index, jlen); + + // the index passed into the function is padded by the amount of lines from _textLines (to account for \n) + // we need to remove this padding, and pad it by actual lines, and / or spaces that are meant to be there + var tmp = 0, + removed = 0; + + // account for removed characters + for (var i = 0; i < this._textLines.length; i++) { + tmp += this._textLines[i].length; + + if (tmp + removed >= index) { + break; + } + + if (this.text[tmp + removed] === '\n' || this.text[tmp + removed] === ' ') { + removed++; + } + } + + return index - i + removed; + }; +})(); + + +(function() { + + if (typeof document !== 'undefined' && typeof window !== 'undefined') { + return; + } + + var DOMParser = require('xmldom').DOMParser, + URL = require('url'), + HTTP = require('http'), + HTTPS = require('https'), + + Canvas = require('canvas'), + Image = require('canvas').Image; + + /** @private */ + function request(url, encoding, callback) { + var oURL = URL.parse(url); + + // detect if http or https is used + if ( !oURL.port ) { + oURL.port = ( oURL.protocol.indexOf('https:') === 0 ) ? 443 : 80; + } + + // assign request handler based on protocol + var reqHandler = (oURL.protocol.indexOf('https:') === 0 ) ? HTTPS : HTTP, + req = reqHandler.request({ + hostname: oURL.hostname, + port: oURL.port, + path: oURL.path, + method: 'GET' + }, function(response) { + var body = ''; + if (encoding) { + response.setEncoding(encoding); + } + response.on('end', function () { + callback(body); + }); + response.on('data', function (chunk) { + if (response.statusCode === 200) { + body += chunk; + } + }); + }); + + req.on('error', function(err) { + if (err.errno === process.ECONNREFUSED) { + fabric.log('ECONNREFUSED: connection refused to ' + oURL.hostname + ':' + oURL.port); + } + else { + fabric.log(err.message); + } + callback(null); + }); + + req.end(); + } + + /** @private */ + function requestFs(path, callback) { + var fs = require('fs'); + fs.readFile(path, function (err, data) { + if (err) { + fabric.log(err); + throw err; + } + else { + callback(data); + } + }); + } + + fabric.util.loadImage = function(url, callback, context) { + function createImageAndCallBack(data) { + if (data) { + img.src = new Buffer(data, 'binary'); + // preserving original url, which seems to be lost in node-canvas + img._src = url; + callback && callback.call(context, img); + } + else { + img = null; + callback && callback.call(context, null, true); + } + } + var img = new Image(); + if (url && (url instanceof Buffer || url.indexOf('data') === 0)) { + img.src = img._src = url; + callback && callback.call(context, img); + } + else if (url && url.indexOf('http') !== 0) { + requestFs(url, createImageAndCallBack); + } + else if (url) { + request(url, 'binary', createImageAndCallBack); + } + else { + callback && callback.call(context, url); + } + }; + + fabric.loadSVGFromURL = function(url, callback, reviver) { + url = url.replace(/^\n\s*/, '').replace(/\?.*$/, '').trim(); + if (url.indexOf('http') !== 0) { + requestFs(url, function(body) { + fabric.loadSVGFromString(body.toString(), callback, reviver); + }); + } + else { + request(url, '', function(body) { + fabric.loadSVGFromString(body, callback, reviver); + }); + } + }; + + fabric.loadSVGFromString = function(string, callback, reviver) { + var doc = new DOMParser().parseFromString(string); + fabric.parseSVGDocument(doc.documentElement, function(results, options) { + callback && callback(results, options); + }, reviver); + }; + + fabric.util.getScript = function(url, callback) { + request(url, '', function(body) { + // eslint-disable-next-line no-eval + eval(body); + callback && callback(); + }); + }; + + // fabric.util.createCanvasElement = function(_, width, height) { + // return new Canvas(width, height); + // } + + /** + * Only available when running fabric on node.js + * @param {Number} width Canvas width + * @param {Number} height Canvas height + * @param {Object} [options] Options to pass to FabricCanvas. + * @param {Object} [nodeCanvasOptions] Options to pass to NodeCanvas. + * @return {Object} wrapped canvas instance + */ + fabric.createCanvasForNode = function(width, height, options, nodeCanvasOptions) { + nodeCanvasOptions = nodeCanvasOptions || options; + + var canvasEl = fabric.document.createElement('canvas'), + nodeCanvas = new Canvas(width || 600, height || 600, nodeCanvasOptions), + nodeCacheCanvas = new Canvas(width || 600, height || 600, nodeCanvasOptions); + + // jsdom doesn't create style on canvas element, so here be temp. workaround + 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.nodeCanvas = nodeCanvas; + 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(); + }; + + fabric.StaticCanvas.prototype.createJPEGStream = function(opts) { + return this.nodeCanvas.createJPEGStream(opts); + }; + + 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._initRetinaScaling = fabric.StaticCanvas.prototype._initRetinaScaling; + } + + 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._setBackstoreDimension = fabric.StaticCanvas.prototype._setBackstoreDimension; + } + +})(); + diff --git a/js9-allinone.js b/js9-allinone.js index d7428fa5..2e3b8050 100644 --- a/js9-allinone.js +++ b/js9-allinone.js @@ -220,7 +220,562 @@ b)},cleanup:function(){for(var a=0;a-1},complexity:function(){return this.getObjects().reduce(function(t,e){return t+=e.complexity?e.complexity():0},0)}},fabric.CommonMethods={_setOptions:function(t){for(var e in t)this.set(e,t[e])},_initGradient:function(t,e){!t||!t.colorStops||t instanceof fabric.Gradient||this.set(e,new fabric.Gradient(t))},_initPattern:function(t,e,i){!t||!t.source||t instanceof fabric.Pattern?i&&i():this.set(e,new fabric.Pattern(t,i))},_initClipping:function(t){if(t.clipTo&&"string"==typeof t.clipTo){var e=fabric.util.getFunctionBody(t.clipTo);void 0!==e&&(this.clipTo=new Function("ctx",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,e){this[t]=e},toggle:function(t){var e=this.get(t);return"boolean"==typeof e&&this.set(t,!e),this},get:function(t){return this[t]}},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-1!==i&&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);return{x:t.x*r-t.y*i,y:t.x*i+t.y*r}},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);return{left:i,top:o,width:n,height:Math.abs(o-a)}},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])>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--;)n="set"+(r=(i=o.stateProperties[e]).charAt(0).toUpperCase()+i.slice(1)),o[s="get"+r]||(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?P-=2*f:1===c&&P<0&&(P+=2*f);for(var E=Math.ceil(Math.abs(P/f*2)),I=[],L=P/E,F=8/3*Math.sin(L/4)*Math.sin(L/4)/Math.sin(L/2),B=A+L,R=0;R=n?s-n:2*Math.PI-(n-s)}function i(t,e,i,r,n,a,h,c){var l=o.call(arguments);if(s[l])return s[l];var u,f,d,g,p,v,b,m,_=Math.sqrt,y=Math.min,x=Math.max,C=Math.abs,S=[],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*a,u=-3*e+9*r-9*a+3*c,d=3*r-3*e),C(u)<1e-12){if(C(f)<1e-12)continue;0<(g=-d/f)&&g<1&&S.push(g)}else(b=f*f-4*d*u)<0||(0<(p=(-f+(m=_(b)))/(2*u))&&p<1&&S.push(p),0<(v=(-f-m)/(2*u))&&v<1&&S.push(v));for(var T,j,k,M=S.length,D=M;M--;)T=(k=1-(g=S[M]))*k*k*t+3*k*k*g*i+3*k*g*g*n+g*g*g*h,w[0][M]=T,j=k*k*k*e+3*k*k*g*r+3*k*g*g*a+g*g*g*c,w[1][M]=j;w[0][D]=t,w[1][D]=e,w[0][D+1]=h,w[1][D+1]=c;var A=[{x:y.apply(null,w[0]),y:y.apply(null,w[1])},{x:x.apply(null,w[0]),y:x.apply(null,w[1])}];return s[l]=A,A}var r={},n={},s={},o=Array.prototype.join;fabric.util.drawArc=function(e,i,r,n){for(var s=n[0],o=n[1],a=n[2],h=n[3],c=n[4],l=[[],[],[],[]],u=t(n[5]-i,n[6]-r,s,o,h,c,a),f=0,d=u.length;f>>0;if(0===i)return-1;var r=0;if(arguments.length>0&&((r=Number(arguments[1]))!=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=e})}}}(),function(){function t(e,i,r){if(r)if(!fabric.isLikelyNode&&i instanceof Element)e=i;else if(i instanceof Array){e=[];for(var n=0,s=i.length;n/g,">")}}}(),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){for(var e=null,r=this;r.constructor.superclass;){var n=r.constructor.superclass.prototype[t];if(r[t]!==n){e=n;break}r=r.constructor.superclass.prototype}return e?arguments.length>1?e.apply(this,i.call(arguments,1)):e.call(this):console.log("tried to callSuper "+t+", method not found in prototype chain",this)}var i=Array.prototype.slice,r=function(){},n=function(){for(var t in{toString:1})if("toString"===t)return!1;return!0}(),s=function(t,e,i){for(var r in e)r in t.prototype&&"function"==typeof t.prototype[r]&&(e[r]+"").indexOf("callSuper")>-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],n&&(e.toString!==Object.prototype.toString&&(t.prototype.toString=e.toString),e.valueOf!==Object.prototype.valueOf&&(t.prototype.valueOf=e.valueOf))};fabric.util.createClass=function(){function n(){this.initialize.apply(this,arguments)}var o=null,a=i.call(arguments,0);"function"==typeof a[0]&&(o=a.shift()),n.superclass=o,n.subclasses=[],o&&(t.prototype=o.prototype,n.prototype=new t,o.subclasses.push(n));for(var h=0,c=a.length;h=.9999?"":"alpha(opacity="+100*e+")",i.filter=i.filter.replace(r,e)):i.filter+=" alpha(opacity="+100*e+")",t}),fabric.util.setStyle=function(t,e){var i=t.style;if(!i)return t;if("string"==typeof e)return t.style.cssText+=";"+e,e.indexOf("opacity")>-1?n(t,e.match(/opacity:\s*(\d?\.?\d*)/)[1]):t;for(var r in e)"opacity"===r?n(t,e[r]):i["float"===r||"cssFloat"===r?void 0===i.styleFloat?"cssFloat":"styleFloat":r]=e[r];return t}}(),function(){function t(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 e(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)===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}}var i,r=Array.prototype.slice,n=function(t){return r.call(t,0)};try{i=n(fabric.document.childNodes)instanceof Array}catch(t){}i||(n=function(t){for(var e=new Array(t.length),i=t.length;i--;)e[i]=t[i];return e});var s;s=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(){var t=fabric.document.documentElement.style,e="userSelect"in t?"userSelect":"MozUserSelect"in t?"MozUserSelect":"WebkitUserSelect"in t?"WebkitUserSelect":"KhtmlUserSelect"in t?"KhtmlUserSelect":"";fabric.util.makeElementUnselectable=function(t){return void 0!==t.onselectstart&&(t.onselectstart=fabric.util.falseFunction),e?t.style[e]="none":"string"==typeof t.unselectable&&(t.unselectable="on"),t},fabric.util.makeElementSelectable=function(t){return void 0!==t.onselectstart&&(t.onselectstart=null),e?t.style[e]="":"string"==typeof t.unselectable&&(t.unselectable=""),t}}(),function(){fabric.util.getScript=function(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.getById=function(t){return"string"==typeof t?fabric.document.getElementById(t):t},fabric.util.toArray=n,fabric.util.makeElement=t,fabric.util.addClass=function(t,e){t&&-1===(" "+t.className+" ").indexOf(" "+e+" ")&&(t.className+=(t.className?" ":"")+e)},fabric.util.wrapElement=function(e,i,r){return"string"==typeof i&&(i=t(i,r)),e.parentNode&&e.parentNode.replaceChild(i,e),i.appendChild(e),i},fabric.util.getScrollLeftTop=e,fabric.util.getElementOffset=function(t){var i,r,n=t&&t.ownerDocument,o={left:0,top:0},a={left:0,top:0},h={borderLeftWidth:"left",borderTopWidth:"top",paddingLeft:"left",paddingTop:"top"};if(!n)return a;for(var c in h)a[h[c]]+=parseInt(s(t,c),10)||0;return i=n.documentElement,void 0!==t.getBoundingClientRect&&(o=t.getBoundingClientRect()),r=e(t),{left:o.left+r.left-(i.clientLeft||0)+a.left,top:o.top+r.top-(i.clientTop||0)+a.top}},fabric.util.getElementStyle=s}(),function(){function t(){}var e=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{if(t[e]())return t[e]}catch(t){}}();fabric.util.request=function(i,r){r||(r={});var n=r.method?r.method.toUpperCase():"GET",s=r.onComplete||function(){},o=e(),a=r.body||r.parameters;return o.onreadystatechange=function(){4===o.readyState&&(s(o),o.onreadystatechange=t)},"GET"===n&&(a=null,"string"==typeof r.parameters&&(i=function(t,e){return t+(/\?/.test(t)?"&":"?")+e}(i,r.parameters))),o.open(n,i,!0),"POST"!==n&&"PUT"!==n||o.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),o.send(a),o}}(),fabric.log=function(){},fabric.warn=function(){},"undefined"!=typeof console&&["log","warn"].forEach(function(t){void 0!==console[t]&&"function"==typeof console[t].apply&&(fabric[t]=function(){return console[t].apply(console,arguments)})}),function(){function t(){return!1}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=function(i){e(function(r){i||(i={});var n,s=r||+new Date,o=i.duration||500,a=s+o,h=i.onChange||t,c=i.abort||t,l=i.onComplete||t,u=i.easing||function(t,e,i,r){return-i*Math.cos(t/r*(Math.PI/2))+i+e},f="startValue"in i?i.startValue:0,d="endValue"in i?i.endValue:100,g=i.byValue||d-f;i.onStart&&i.onStart(),function t(r){if(c())l(d,1,1);else{var p=(n=r||+new Date)>a?o:n-s,v=p/o,b=u(p,f,g,o),m=Math.abs((b-f)/g);h(b,m,v),n>a?i.onComplete&&i.onComplete():e(t)}}(s)})},fabric.util.requestAnimFrame=e}(),function(){fabric.util.animateColor=function(t,e,i,r){var n=new fabric.Color(t).getSource(),s=new fabric.Color(e).getSource();r=r||{},fabric.util.animate(fabric.util.object.extend(r,{duration:i||500,startValue:n,endValue:s,byValue:s,easing:function(t,e,i,n){return function(t,e,i){var r="rgba("+parseInt(t[0]+i*(e[0]-t[0]),10)+","+parseInt(t[1]+i*(e[1]-t[1]),10)+","+parseInt(t[2]+i*(e[2]-t[2]),10);return r+=","+(t&&e?parseFloat(t[3]+i*(e[3]-t[3])):1),r+=")"}(e,i,r.colorEasing?r.colorEasing(t,n):1-Math.cos(t/n*(Math.PI/2)))}}))}}(),function(){function t(t,e,i,r){return ta?a:o),1===o&&1===a&&0===c&&0===l&&0===g&&0===v)return C;if((g||v)&&(S=" translate("+f(g)+" "+f(v)+") "),r=S+" matrix("+o+" 0 0 "+a+" "+c*o+" "+l*a+") ","svg"===t.nodeName){for(n=t.ownerDocument.createElement("g");t.firstChild;)n.appendChild(t.firstChild);t.appendChild(n)}else r=(n=t).getAttribute("transform")+r;return n.setAttribute("transform",r),C}var h=t.fabric||(t.fabric={}),c=h.util.object.extend,l=h.util.object.clone,u=h.util.toFixed,f=h.util.parseUnit,d=h.util.multiplyTransformMatrices,g=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i,p=/^(symbol|image|marker|pattern|view|svg)$/i,v=/^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i,b=/^(symbol|g|a|svg)$/i,m={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",opacity:"opacity"},_={stroke:"strokeOpacity",fill:"fillOpacity"};h.cssRules={},h.gradientDefs={},h.parseTransformAttribute=function(){function t(t,e,i){t[i]=Math.tan(h.util.degreesToRadians(e[0]))}var e=[1,0,0,1,0,0],i=h.reNum,r="(?:\\s+,?\\s*|,\\s*)",n="(?:"+("(?:(matrix)\\s*\\(\\s*("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")\\s*\\))")+"|"+("(?:(translate)\\s*\\(\\s*("+i+")(?:"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(scale)\\s*\\(\\s*("+i+")(?:"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(rotate)\\s*\\(\\s*("+i+")(?:"+r+"("+i+")"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(skewX)\\s*\\(\\s*("+i+")\\s*\\))")+"|"+("(?:(skewY)\\s*\\(\\s*("+i+")\\s*\\))")+")",s="^\\s*(?:"+("(?:"+n+"(?:"+r+"*"+n+")*)")+"?)\\s*$",o=new RegExp(s),a=new RegExp(n,"g");return function(i){var r=e.concat(),s=[];if(!i||i&&!o.test(i))return r;i.replace(a,function(i){var o=new RegExp(n).exec(i).filter(function(t){return!!t}),a=o[1],c=o.slice(2).map(parseFloat);switch(a){case"translate":!function(t,e){t[4]=e[0],2===e.length&&(t[5]=e[1])}(r,c);break;case"rotate":c[0]=h.util.degreesToRadians(c[0]),function(t,e){var i=Math.cos(e[0]),r=Math.sin(e[0]),n=0,s=0;3===e.length&&(n=e[1],s=e[2]),t[0]=i,t[1]=r,t[2]=-r,t[3]=i,t[4]=n-(i*n-r*s),t[5]=s-(r*n+i*s)}(r,c);break;case"scale":!function(t,e){var i=e[0],r=2===e.length?e[1]:e[0];t[0]=i,t[3]=r}(r,c);break;case"skewX":t(r,c,2);break;case"skewY":t(r,c,1);break;case"matrix":r=c}s.push(r.concat()),r=e.concat()});for(var c=s[0];s.length>1;)s.shift(),c=h.util.multiplyTransformMatrices(c,s[0]);return c}}();var y=new RegExp("^\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*$");h.parseSVGDocument=function(t,e,i,n){if(t){!function(t){for(var e=r(t,["use","svg:use"]),i=0;e.length&&i/i,""))),n&&n.documentElement||e&&e(null),h.parseSVGDocument(n.documentElement,function(t,i){e&&e(t,i)},i,r)}})},loadSVGFromString:function(t,e,i,r){t=t.trim();var n;if("undefined"!=typeof DOMParser){var s=new DOMParser;s&&s.parseFromString&&(n=s.parseFromString(t,"text/xml"))}else h.window.ActiveXObject&&((n=new ActiveXObject("Microsoft.XMLDOM")).async="false",n.loadXML(t.replace(//i,"")));h.parseSVGDocument(n.documentElement,function(t,i){e(t,i)},i,r)}})}("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,i){return void 0===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={});i.Intersection?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")).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},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={});r.Color?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,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}var i=fabric.util.object.clone;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:parseFloat(e),color:i.toRgb(),opacity:i.getAlpha()})}return this},toObject:function(t){var e={type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY,gradientTransform:this.gradientTransform?this.gradientTransform.concat():this.gradientTransform};return fabric.util.populateWithProperties(this,e,t),e},toSVG:function(t){var e,r,n=i(this.coords,!0),s=i(this.colorStops,!0),o=n.r1>n.r2;if(s.sort(function(t,e){return t.offset-e.offset}),!t.group||"path-group"!==t.group.type)for(var a in n)"x1"===a||"x2"===a?n[a]+=this.offsetX-t.width/2:"y1"!==a&&"y2"!==a||(n[a]+=this.offsetY-t.height/2);if(r='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"',this.gradientTransform&&(r+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" '),"linear"===this.type?e=["\n']:"radial"===this.type&&(e=["\n']),"radial"===this.type){if(o){(s=s.concat()).reverse();for(l=0;l0)for(var c=h/Math.max(n.r1,n.r2),l=0;l\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'},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 e=t.fabric||(t.fabric={}),i=e.util.toFixed;e.Shadow?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)||[];return{color:(i.replace(e.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").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));return t.width&&t.height&&(r=100*i((Math.abs(o.x)+this.blur)/t.width,s)+20,n=100*i((Math.abs(o.y)+this.blur)/t.height,s)+20),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}}),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)fabric.warn("fabric.StaticCanvas is already defined.");else{var t=fabric.util.object.extend,e=fabric.util.getElementOffset,i=fabric.util.removeFromArray,r=fabric.util.toFixed,n=fabric.util.transformPoint,s=fabric.util.invertTransform,o=new Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(t,e){e||(e={}),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:!1,_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){return this[t]=e,this._initGradient(e,t),this._initPattern(e,t,i),this},_createCanvasElement:function(t){var e=fabric.util.createCanvasElement(t);if(e.style||(e.style={}),!e)throw o;if(void 0===e.getContext)throw o;return e},_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){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 this.viewportTransform[0]},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","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),"\n")},createSVGRefElementsMarkup:function(){var t=this;return["backgroundColor","overlayColor"].map(function(e){var i=t[e];if(i&&i.toLive)return i.toSVG(t,!1)}).join("")},createSVGFontFacesMarkup:function(){for(var t,e,i,r,n,s,o="",a={},h=fabric.fontPaths,c=this.getObjects(),l=0,u=c.length;l',"\n",o,"","\n"].join("")),o},_setSVGObjects:function(t,e){for(var i,r=0,n=this.getObjects(),s=n.length;r
\n")}else t.push('\n")},sendToBack:function(t){if(!t)return this;var e,r,n,s=this._activeGroup;if(t===s)for(e=(n=s._objects).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;e0+c&&(o=s-1,i(this._objects,n),this._objects.splice(o,0,n)),c++;else 0!==(s=this._objects.indexOf(t))&&(o=this._findNewLowerIndex(t,s,e),i(this._objects,t),this._objects.splice(o,0,t));return this.renderAll&&this.renderAll(),this},_findNewLowerIndex:function(t,e,i){var r;if(i){r=e;for(var n=e-1;n>=0;--n){if(t.intersectsWithObject(this._objects[n])||t.isContainedWithinObject(this._objects[n])||this._objects[n].isContainedWithinObject(t)){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,c=0;if(t===h)for(r=(a=h._objects).length;r--;)n=a[r],(s=this._objects.indexOf(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 void 0!==i.getImageData;case"setLineDash":return void 0!==i.setLineDash;case"toDataURL":return void 0!==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,e=this.canvas.getZoom();t.shadowColor=this.shadow.color,t.shadowBlur=this.shadow.blur*e,t.shadowOffsetX=this.shadow.offsetX*e,t.shadowOffsetY=this.shadow.offsetY*e}},_resetShadow:function(){var t=this.canvas.contextTop;t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0}}),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.length>1&&t.eq(this._points[this._points.length-1])||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,e,i=this.canvas.contextTop,r=this.canvas.viewportTransform,n=this._points[0],s=this._points[1];if(i.save(),i.transform(r[0],r[1],r[2],r[3],r[4],r[5]),i.beginPath(),2===this._points.length&&n.x===s.x&&n.y===s.y){var o=this.width/1e3;n=new fabric.Point(n.x,n.y),s=new fabric.Point(s.x,s.y),n.x-=o,s.x+=o}for(i.moveTo(n.x,n.y),t=1,e=this._points.length;t2;for(c&&(a=t[2].xt[e-2].x?1:n.x===t[e-2].x?0:-1,h=n.y>t[e-2].y?1:n.y===t[e-2].y?0:-1),i.push("L ",n.x+a*r," ",n.y+h*r),i},createPath:function(t){var e=new fabric.Path(t,{fill:null,stroke:this.color,strokeWidth:this.width,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeDashArray:this.strokeDashArray,originX:"center",originY:"center"}),i=new fabric.Point(e.left,e.top);return e.originX=fabric.Object.prototype.originX,e.originY=fabric.Object.prototype.originY,i=e.translateToGivenOrigin(i,"center","center",e.originX,e.originY),e.top=i.y,e.left=i.x,this.shadow&&(this.shadow.affectStroke=!0,e.setShadow(this.shadow)),e},_finalizeAndAddPath:function(){this.canvas.contextTop.closePath();var t=this.convertPointsToSVGPath(this._points).join("");if("M 0 0 Q 0 0 0 0 L 0 0"!==t){var e=this.createPath(t);this.canvas.add(e),e.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire("path:created",{path:e})}else this.canvas.renderAll()}}),fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(t){this.canvas=t,this.points=[]},drawDot:function(t){var e=this.addPoint(t),i=this.canvas.contextTop,r=this.canvas.viewportTransform;i.save(),i.transform(r[0],r[1],r[2],r[3],r[4],r[5]),i.fillStyle=e.fill,i.beginPath(),i.arc(e.x,e.y,e.radius,0,2*Math.PI,!1),i.closePath(),i.fill(),i.restore()},onMouseDown:function(t){this.points.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.drawDot(t)},onMouseMove:function(t){this.drawDot(t)},onMouseUp:function(){var t=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var e=[],i=0,r=this.points.length;i0?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])<=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&&cs?t.x<0?t.x+=s:t.x-=s:t.x=0,n(t.y)>s?t.y<0?t.y+=s:t.y-=s: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),h=!0;if(n.target.snapAngle>0){var c=n.target.snapAngle,l=n.target.snapThreshold||c,u=Math.ceil(a/c)*c,f=Math.floor(a/c)*c;Math.abs(a-f)0?0:-i),e.ey-(r>0?0:-r),o,a)),this.selectionLineWidth&&this.selectionBorderColor)if(t.lineWidth=this.selectionLineWidth,t.strokeStyle=this.selectionBorderColor,this.selectionDashArray.length>1&&!s){var h=e.ex+.5-(i>0?0:o),c=e.ey+.5-(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 fabric.Object.prototype._setLineDash.call(this,t,this.selectionDashArray),t.strokeRect(e.ex+.5-(i>0?0:o),e.ey+.5-(r>0?0:a),o,a)},findTarget:function(t,e){if(!this.skipTargetFind){var i,r,n=this.getPointer(t,!0),s=this.getActiveGroup(),o=this.getActiveObject();if(this.targets=[],s&&!e&&s===this._searchPossibleTargets([s],n))return this._fireOverOutEvents(s,t),s;if(o&&o._findTargetCorner(n))return this._fireOverOutEvents(o,t),o;if(o&&o===this._searchPossibleTargets([o],n)){if(!this.preserveObjectStacking)return this._fireOverOutEvents(o,t),o;i=o,r=this.targets,this.targets=[]}var a=this._searchPossibleTargets(this._objects,n);return t[this.altSelectionKey]&&a&&i&&a!==i&&(a=i,this.targets=r),this._fireOverOutEvents(a,t),a}},_fireOverOutEvents:function(t,e){var i,r,n=this._hoveredTarget;n!==t&&(i={e:e,target:t,previousTarget:this._hoveredTarget},r={e:e,target:this._hoveredTarget,nextTarget:t},this._hoveredTarget=t),t?n!==t&&(n&&(this.fire("mouse:out",r),n.fire("mouseout",r)),this.fire("mouse:over",i),t.fire("mouseover",i)):n&&(this.fire("mouse:out",r),n.fire("mouseout",r))},_checkTarget:function(t,e){if(e&&e.visible&&e.evented&&this.containsPoint(null,e,t)){if(!this.perPixelTargetFind&&!e.perPixelTargetFind||e.isEditing)return!0;if(!this.isTargetTransparent(e,t.x,t.y))return!0}},_searchPossibleTargets:function(t,e){for(var i,r,n,s=t.length;s--;)if(this._checkTarget(e,t[s])){"group"===(i=t[s]).type&&i.subTargetCheck&&(r=this._normalizePointer(i,e),(n=this._searchPossibleTargets(i._objects,r))&&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.upperCanvasEl.className="":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,"touch-action":"none"}),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){var e=this._activeObject;e&&(e.set("active",!1),t!==e&&e.onDeselect&&"function"==typeof e.onDeselect&&e.onDeselect()),this._activeObject=t,t.set("active",!0)},setActiveObject:function(t,e){var i=this.getActiveObject();return i&&i!==t&&i.fire("deselected",{e:e}),this._setActiveObject(t),this.fire("object:selected",{target:t,e:e}),t.fire("selected",{e:e}),this.renderAll(),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._hoveredTarget===t&&(this._hoveredTarget=null),this.callSuper("_onObjectRemoved",t)},_discardActiveObject:function(){var t=this._activeObject;t&&(t.set("active",!1),t.onDeselect&&"function"==typeof t.onDeselect&&t.onDeselect()),this._activeObject=null},discardActiveObject:function(t){var e=this._activeObject;return e&&(this.fire("before:selection:cleared",{target:e,e:t}),this._discardActiveObject(),this.fire("selection:cleared",{e:t}),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 e&&(this.fire("before:selection:cleared",{e:t,target:e}),this._discardActiveGroup(),this.fire("selection:cleared",{e:t})),this},deactivateAll:function(){for(var t,e=this.getObjects(),i=0,r=e.length;i1)){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||null)}},__onMouseWheel:function(t){this._handleEvent(t,"wheel")},_transformObject:function(t){var e=this.getPointer(t),i=this._currentTransform;i.reset=!1,i.target.isMoving=!0,i.shiftKey=t.shiftKey,i.altKey=t[this.centeredKey],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))&&(this._fire("moving",s,t),this.setCursor(s.moveCursor||this.moveCursor)),e.actionPerformed=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,r=this.getActiveGroup(),n=e._findTargetCorner&&(!r||!r.contains(e))&&e._findTargetCorner(this.getPointer(t,!0));return n?this._setCornerCursor(n,e,t):this.setCursor(i),!0},_setCornerCursor:function(t,i,r){if(t in e)this.setCursor(this._getRotatedCornerCursor(t,i,r));else{if("mtr"!==t||!i.hasRotatingPoint)return this.setCursor(this.defaultCursor),!1;this.setCursor(this.rotationCursor)}},_getRotatedCornerCursor:function(t,i,r){var n=Math.round(i.getAngle()%360/45);return n<0&&(n+=8),n+=e[t],r[this.altActionKey]&&e[t]%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),e)}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,e),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})).addWithUpdate(),this.setActiveGroup(e,t),e.saveCoords(),this.fire("selection:created",{target:e,e:t}),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.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.height||this.getHeight())*r,h=this.getZoom()*r,c=this.viewportTransform,l=[h,0,0,h,(c[4]-i.left)*r,(c[5]-i.top)*r],u=this.interactive;this.viewportTransform=l,this.interactive&&(this.interactive=!1),n!==o||s!==a?this.setDimensions({width:o,height:a},{backstoreOnly:!0}):this.renderAll();var f=this.__toDataURL(t,e,i);return u&&(this.interactive=u),this.viewportTransform=c,this.setDimensions({width:n,height:s},{backstoreOnly:!0}),f},__toDataURL:function(e,i){var r=this.contextContainer.canvas;"jpg"===e&&(e="jpeg");return t?r.toDataURL("image/"+e,i):r.toDataURL("image/"+e)},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),n=this,s=this.renderOnAddRemove;return this.renderOnAddRemove=!1,this._enlivenObjects(r.objects,function(t){n.clear(),n._setBgOverlay(r,function(){t.forEach(function(t,e){n.insertAt(t,e)}),n.renderOnAddRemove=s,delete r.objects,delete r.backgroundImage,delete r.overlayImage,delete r.background,delete r.overlay,n._setOptions(r),n.renderAll(),e&&e()})},i),this}},_setBgOverlay:function(t,e){var i={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(t.backgroundImage||t.overlayImage||t.background||t.overlay){var r=function(){i.backgroundImage&&i.overlayImage&&i.backgroundColor&&i.overlayColor&&e&&e()};this.__setBgOverlay("backgroundImage",t.backgroundImage,i,r),this.__setBgOverlay("overlayImage",t.overlayImage,i,r),this.__setBgOverlay("backgroundColor",t.background,i,r),this.__setBgOverlay("overlayColor",t.overlay,i,r)}else e&&e()},__setBgOverlay:function(t,e,i,r){var n=this;if(!e)return i[t]=!0,void(r&&r());"backgroundImage"===t||"overlayImage"===t?fabric.util.enlivenObjects([e],function(e){n[t]=e[0],i[t]=!0,r&&r()}):this["set"+fabric.util.string.capitalize(t,!0)](e,function(){i[t]=!0,r&&r()})},_enlivenObjects:function(t,e,i){t&&0!==t.length?fabric.util.enlivenObjects(t,function(t){e&&e(t)},null,i):e&&e([])},_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.object.clone,n=e.util.toFixed,s=e.util.string.capitalize,o=e.util.degreesToRadians,a=e.StaticCanvas.supports("setLineDash"),h=!e.isLikelyNode;e.Object||(e.Object=e.util.createClass(e.CommonMethods,{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,objectCaching:h,statefullCache:!1,noScaleCache:!0,dirty:!0,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor skewX skewY fillRule".split(" "),cacheProperties:"fill stroke strokeWidth strokeDashArray width height strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor".split(" "),initialize:function(t){(t=t||{})&&this.setOptions(t)},_createCacheCanvas:function(){this._cacheProperties={},this._cacheCanvas=e.document.createElement("canvas"),this._cacheContext=this._cacheCanvas.getContext("2d"),this._updateCacheCanvas()},_limitCacheSize:function(t){var i=e.perfLimitSizeTotal,r=t.width,n=t.height,s=e.maxCacheSideLimit,o=e.minCacheSideLimit;if(r<=s&&n<=s&&r*n<=i)return rl&&(t.zoomX/=r/l,t.width=l,t.capped=!0),n>u&&(t.zoomY/=n/u,t.height=u,t.capped=!0),t},_getCacheCanvasDimensions:function(){var t=this.canvas&&this.canvas.getZoom()||1,i=this.getObjectScaling(),r=this.canvas&&this.canvas._isRetinaScaling()?e.devicePixelRatio:1,n=this._getNonTransformedDimensions(),s=i.scaleX*t*r,o=i.scaleY*t*r;return{width:n.x*s+2,height:n.y*o+2,zoomX:s,zoomY:o,x:n.x,y:n.y}},_updateCacheCanvas:function(){if(this.noScaleCache&&this.canvas&&this.canvas._currentTransform){var t=this.canvas._currentTransform.target,i=this.canvas._currentTransform.action;if(this===t&&i.slice&&"scale"===i.slice(0,5))return!1}var r,n,s=this._cacheCanvas,o=this._limitCacheSize(this._getCacheCanvasDimensions()),a=e.minCacheSideLimit,h=o.width,c=o.height,l=o.zoomX,u=o.zoomY,f=h!==this.cacheWidth||c!==this.cacheHeight,d=this.zoomX!==l||this.zoomY!==u,g=f||d,p=0,v=0,b=!1;if(f){var m=this._cacheCanvas.width,_=this._cacheCanvas.height,y=h>m||c>_;b=y||(h<.9*m||c<.9*_)&&m>a&&_>a,y&&!o.capped&&(h>a||c>a)&&(p=.1*h,v=.1*c)}return!!g&&(b?(s.width=Math.ceil(h+p),s.height=Math.ceil(c+v)):(this._cacheContext.setTransform(1,0,0,1,0,0),this._cacheContext.clearRect(0,0,s.width,s.height)),r=o.x*l/2,n=o.y*u/2,this.cacheTranslationX=Math.round(s.width/2-r)+r,this.cacheTranslationY=Math.round(s.height/2-n)+n,this.cacheWidth=h,this.cacheHeight=c,this._cacheContext.translate(this.cacheTranslationX,this.cacheTranslationY),this._cacheContext.scale(l,u),this.zoomX=l,this.zoomY=u,!0)},setOptions:function(t){this._setOptions(t),this._initGradient(t.fill,"fill"),this._initGradient(t.stroke,"stroke"),this._initClipping(t),this._initPattern(t.fill,"fill"),this._initPattern(t.stroke,"stroke")},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),this.angle&&t.rotate(o(this.angle)),t.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1)),this.skewX&&t.transform(1,0,Math.tan(o(this.skewX)),1,0,0),this.skewY&&t.transform(1,Math.tan(o(this.skewY)),0,1,0,0)},toObject:function(t){var i=e.Object.NUM_FRACTION_DIGITS,r={type:this.type,originX:this.originX,originY:this.originY,left:n(this.left,i),top:n(this.top,i),width:n(this.width,i),height:n(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:n(this.strokeWidth,i),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:n(this.strokeMiterLimit,i),scaleX:n(this.scaleX,i),scaleY:n(this.scaleY,i),angle:n(this.getAngle(),i),flipX:this.flipX,flipY:this.flipY,opacity:n(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():null,skewX:n(this.skewX,i),skewY:n(this.skewY,i)};return e.util.populateWithProperties(this,r,t),this.includeDefaultValues||(r=this._removeDefaultValues(r)),r},toDatalessObject:function(t){return this.toObject(t)},_removeDefaultValues:function(t){var i=e.util.getKlass(t.type).prototype;return i.stateProperties.forEach(function(e){t[e]===i[e]&&delete t[e];"[object Array]"===Object.prototype.toString.call(t[e])&&"[object Array]"===Object.prototype.toString.call(i[e])&&0===t[e].length&&0===i[e].length&&delete t[e]}),t},toString:function(){return"#"},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}},_set:function(t,i){var r="scaleX"===t||"scaleY"===t,n=this[t]!==i;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?"dirty"===t&&this.group&&this.group.set("dirty",i):i=new e.Shadow(i),this[t]=i,n&&this.cacheProperties.indexOf(t)>-1&&(this.group&&this.group.set("dirty",!0),this.dirty=!0),n&&this.group&&this.stateProperties.indexOf(t)>-1&&this.group.set("dirty",!0),"width"!==t&&"height"!==t||(this.minScaleLimit=Math.min(.1,1/Math.max(this.width,this.height))),this},setOnGroup:function(){},setSourcePath:function(t){return this.sourcePath=t,this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:e.iMatrix.concat()},isNotVisible:function(){return 0===this.opacity||0===this.width&&0===this.height||!this.visible},render:function(t,i){this.isNotVisible()||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(t.save(),this._setupCompositeOperation(t),this.drawSelectionBackground(t),i||this.transform(t),this._setOpacity(t),this._setShadow(t),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.clipTo&&e.util.clipContext(this,t),this.shouldCache(i)?(this._cacheCanvas||this._createCacheCanvas(),this.isCacheDirty(i)&&(this.statefullCache&&this.saveState({propertySet:"cacheProperties"}),this.drawObject(this._cacheContext,i),this.dirty=!1),this.drawCacheOnCanvas(t)):(this._removeCacheCanvas(),this.dirty=!1,this.drawObject(t,i),i&&this.objectCaching&&this.statefullCache&&this.saveState({propertySet:"cacheProperties"})),this.clipTo&&t.restore(),t.restore())},_removeCacheCanvas:function(){this._cacheCanvas=null,this.cacheWidth=0,this.cacheHeight=0},needsItsOwnCache:function(){return!1},shouldCache:function(t){return!t&&this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching())},willDrawShadow:function(){return!!this.shadow&&(0!==this.shadow.offsetX||0!==this.shadow.offsetY)},drawObject:function(t,e){this._renderBackground(t),this._setStrokeStyles(t),this._setFillStyles(t),this._render(t,e)},drawCacheOnCanvas:function(t){t.scale(1/this.zoomX,1/this.zoomY),t.drawImage(this._cacheCanvas,-this.cacheTranslationX,-this.cacheTranslationY)},isCacheDirty:function(t){if(this.isNotVisible())return!1;if(this._cacheCanvas&&!t&&this._updateCacheCanvas())return!0;if(this.dirty||this.statefullCache&&this.hasStateChanged("cacheProperties")){if(this._cacheCanvas&&!t){var e=this.cacheWidth/this.zoomX,i=this.cacheHeight/this.zoomY;this._cacheContext.clearRect(-e/2,-i/2,e,i)}return!0}return!1},_renderBackground:function(t){if(this.backgroundColor){var e=this._getNonTransformedDimensions();t.fillStyle=this.backgroundColor,t.fillRect(-e.x/2,-e.y/2,e.x,e.y),this._removeShadow(t)}},_setOpacity:function(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),a?t.setLineDash(e):i&&i(t))},_renderControls:function(t){if(this.active&&(!this.group||this.group===this.canvas.getActiveGroup())){var i,r=this.getViewportTransform(),n=this.calcTransformMatrix();n=e.util.multiplyTransformMatrices(r,n),i=e.util.qrDecompose(n),t.save(),t.translate(i.translateX,i.translateY),t.lineWidth=1*this.borderScaleFactor,this.group||(t.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1),this.group&&this.group===this.canvas.getActiveGroup()?(t.rotate(o(i.angle)),this.drawBordersInGroup(t,i)):(t.rotate(o(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)},_applyPatternGradientTransform:function(t,e){if(e.toLive){var i=e.gradientTransform||e.patternTransform;i&&t.transform.apply(t,i);var r=-this.width/2+e.offsetX||0,n=-this.height/2+e.offsetY||0;t.translate(r,n)}},_renderFill:function(t){this.fill&&(t.save(),this._applyPatternGradientTransform(t,this.fill),"evenodd"===this.fillRule?t.fill("evenodd"):t.fill(),t.restore())},_renderStroke:function(t){this.stroke&&0!==this.strokeWidth&&(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(t),t.save(),this._setLineDash(t,this.strokeDashArray,this._renderDashedStroke),this._applyPatternGradientTransform(t,this.stroke),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 1},toJSON:function(t){return this.toObject(t)},setGradient:function(t,i){i||(i={});var r={colorStops:[]};return 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),r.gradientTransform=i.gradientTransform,e.Gradient.prototype.addColorStop.call(r,i.colorStops),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.group&&this.group===this.canvas._activeGroup&&this.group.remove(this),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,o(-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._fromObject=function(t,i,n,s,o){var a=e[t];if(i=r(i,!0),!s){var h=o?new a(i[o],i):new a(i);return n&&n(h),h}e.util.enlivenPatterns([i.fill,i.stroke],function(t){void 0!==t[0]&&(i.fill=t[0]),void 0!==t[1]&&(i.stroke=t[1]);var e=o?new a(i[o],i):new a(i);n&&n(e)})},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=void 0!==i&&void 0!==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")},onDeselect:function(){}})}(),function(){var t=fabric.util.degreesToRadians,e=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,aCoords:null,getCoords:function(t,e){this.oCoords||this.setCoords();var i=t?this.aCoords:this.oCoords;return function(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)]}(e?this.calcCoords(t):i)},intersectsWithRect:function(t,e,i,r){var n=this.getCoords(i,r);return"Intersection"===fabric.Intersection.intersectPolygonRectangle(n,t,e).status},intersectsWithObject:function(t,e,i){return"Intersection"===fabric.Intersection.intersectPolygonPolygon(this.getCoords(e,i),t.getCoords(e,i)).status||t.isContainedWithinObject(this,e,i)||this.isContainedWithinObject(t,e,i)},isContainedWithinObject:function(t,e,i){for(var r=this.getCoords(e,i),n=0,s=t._getImageLines(i?t.calcCoords(e):e?t.aCoords:t.oCoords);n<4;n++)if(!t.containsPoint(r[n],s))return!1;return!0},isContainedWithinRect:function(t,e,i,r){var n=this.getBoundingRect(i,r);return n.left>=t.x&&n.left+n.width<=e.x&&n.top>=t.y&&n.top+n.height<=e.y},containsPoint:function(t,e,i,r){var e=e||this._getImageLines(r?this.calcCoords(i):i?this.aCoords:this.oCoords),n=this._findCrossPoints(t,e);return 0!==n&&n%2==1},isOnScreen:function(t){if(!this.canvas)return!1;for(var e,i=this.canvas.vptCoords.tl,r=this.canvas.vptCoords.br,n=this.getCoords(!0,t),s=0;s<4;s++)if((e=n[s]).x<=r.x&&e.x>=i.x&&e.y<=r.y&&e.y>=i.y)return!0;if(this.intersectsWithRect(i,r,!0))return!0;var o={x:(i.x+r.x)/2,y:(i.y+r.y)/2};return!!this.containsPoint(o,null,!0)},_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=0;for(var a in e)if(!((s=e[a]).o.y=t.y&&s.d.y>=t.y||(s.o.x===s.d.x&&s.o.x>=t.x?n=s.o.x:(i=0,r=(s.d.y-s.o.y)/(s.d.x-s.o.x),n=-(t.y-i*t.x-(s.o.y-r*s.o.x))/(i-r)),n>=t.x&&(o+=1),2!==o)))break;return o},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(t,e){var i=this.getCoords(t,e);return fabric.util.makeBoundingBoxFromPoints(i)},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(t){return Math.abs(t)0?Math.atan(o/s):0,l=s/Math.cos(c)/2,u=Math.cos(c+i)*l,f=Math.sin(c+i)*l,d=this.getCenterPoint(),g=e?d:fabric.util.transformPoint(d,r),p=new fabric.Point(g.x-u,g.y-f),v=new fabric.Point(p.x+s*h,p.y+s*a),b=new fabric.Point(p.x-o*a,p.y+o*h),m=new fabric.Point(g.x+u,g.y+f);if(!e)var _=new fabric.Point((p.x+b.x)/2,(p.y+b.y)/2),y=new fabric.Point((v.x+p.x)/2,(v.y+p.y)/2),x=new fabric.Point((m.x+v.x)/2,(m.y+v.y)/2),C=new fabric.Point((m.x+b.x)/2,(m.y+b.y)/2),S=new fabric.Point(y.x+a*this.rotatingPointOffset,y.y-h*this.rotatingPointOffset);g={tl:p,tr:v,br:m,bl:b};return e||(g.ml=_,g.mt=y,g.mr=x,g.mb=C,g.mtr=S),g},setCoords:function(t,e){return this.oCoords=this.calcCoords(t),e||(this.aCoords=this.calcCoords(!0)),t||this._setCornerCoords&&this._setCornerCoords(),this},_calcRotateMatrix:function(){if(this.angle){var e=t(this.angle),i=Math.cos(e),r=Math.sin(e);return 6.123233995736766e-17!==i&&-1.8369701987210297e-16!==i||(i=0),[i,r,-r,i,0,0]}return fabric.iMatrix.concat()},calcTransformMatrix:function(t){var i,r,n=this.getCenterPoint(),s=[1,0,0,1,n.x,n.y],o=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0);return r=this.group&&!t?e(this.group.calcTransformMatrix(),s):s,this.angle&&(i=this._calcRotateMatrix(),r=e(r,i)),r=e(r,o)},_calcDimensionsTransformMatrix:function(i,r,n){var s,o=[this.scaleX*(n&&this.flipX?-1:1),0,0,this.scaleY*(n&&this.flipY?-1:1),0,0];return i&&(s=[1,0,Math.tan(t(i)),1],o=e(o,s,!0)),r&&(s=[1,Math.tan(t(r)),0,1],o=e(o,s,!0)),o},_getNonTransformedDimensions:function(){var t=this.strokeWidth;return{x:this.width+t,y:this.height+t}},_getTransformedDimensions:function(t,e){void 0===t&&(t=this.skewX),void 0===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("")}}),i.Line.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),i.Line.fromElement=function(t,e){e=e||{};var n=i.parseAttributes(t,i.Line.ATTRIBUTE_NAMES),s=[n.x1||0,n.y1||0,n.x2||0,n.y2||0];return e.originX="left",e.originY="top",new i.Line(s,r(n,e))},i.Line.fromObject=function(t,e,r){var s=n(t,!0);s.points=[t.x1,t.y1,t.x2,t.y2];var o=i.Object._fromObject("Line",s,function(t){delete t.points,e&&e(t)},r,"points");return o&&delete o.points,o})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=Math.PI,r=e.util.object.extend;e.Circle?e.warn("fabric.Circle is already defined."):(e.Circle=e.util.createClass(e.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*i,cacheProperties:e.Object.prototype.cacheProperties.concat("radius"),initialize:function(t){this.callSuper("initialize",t),this.set("radius",t&&t.radius||0)},_set:function(t,e){return this.callSuper("_set",t,e),"radius"===t&&this.setRadius(e),this},toObject:function(t){return this.callSuper("toObject",["radius","startAngle","endAngle"].concat(t))},toSVG:function(t){var e=this._createBaseSVGMarkup(),r=0,n=0,s=(this.endAngle-this.startAngle)%(2*i);if(0===s)this.group&&"path-group"===this.group.type&&(r=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>i?"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)}}),e.Circle.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),e.Circle.fromElement=function(t,i){i||(i={});var n=e.parseAttributes(t,e.Circle.ATTRIBUTE_NAMES);if(!function(t){return"radius"in t&&t.radius>=0}(n))throw new Error("value of `r` attribute is required and can not be negative");n.left=n.left||0,n.top=n.top||0;var s=new e.Circle(r(n,i));return s.left-=s.radius,s.top-=s.radius,s},e.Circle.fromObject=function(t,i,r){return e.Object._fromObject("Circle",t,i,r)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={});e.Triangle?e.warn("fabric.Triangle is already defined"):(e.Triangle=e.util.createClass(e.Object,{type:"triangle",initialize:function(t){this.callSuper("initialize",t),this.set("width",t&&t.width||100).set("height",t&&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("")}}),e.Triangle.fromObject=function(t,i,r){return e.Object._fromObject("Triangle",t,i,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;e.Ellipse?e.warn("fabric.Ellipse is already defined."):(e.Ellipse=e.util.createClass(e.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:e.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this.set("rx",t&&t.rx||0),this.set("ry",t&&t.ry||0)},_set:function(t,e){switch(this.callSuper("_set",t,e),t){case"rx":this.rx=e,this.set("width",2*e);break;case"ry":this.ry=e,this.set("height",2*e)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(t){return this.callSuper("toObject",["rx","ry"].concat(t))},toSVG:function(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)}}),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},e.Ellipse.fromObject=function(t,i,r){return e.Object._fromObject("Ellipse",t,i,r)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;e.Rect?e.warn("fabric.Rect is already defined"):(e.Rect=e.util.createClass(e.Object,{stateProperties:e.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:e.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(t,e){if(1!==this.width||1!==this.height){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)}else t.fillRect(-.5,-.5,1,1)},_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){return this.callSuper("toObject",["rx","ry"].concat(t))},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("")}}),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,r){return e.Object._fromObject("Rect",t,i,r)})}("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.toFixed,o=e.Object.NUM_FRACTION_DIGITS;e.Polyline?e.warn("fabric.Polyline is already defined"):(e.Polyline=e.util.createClass(e.Object,{type:"polyline",points:null,minX:0,minY:0,cacheProperties:e.Object.prototype.cacheProperties.concat("points"),initialize:function(t,e){e=e||{},this.points=t||[],this.callSuper("initialize",e),this._calcDimensions(),"top"in e||(this.top=this.minY),"left"in e||(this.left=this.minX),this.pathOffset={x:this.minX+this.width/2,y:this.minY+this.height/2}},_calcDimensions:function(){var t=this.points,e=r(t,"x"),i=r(t,"y"),s=n(t,"x"),o=n(t,"y");this.width=s-e||0,this.height=o-i||0,this.minX=e||0,this.minY=i||0},toObject:function(t){return i(this.callSuper("toObject",t),{points:this.points.concat()})},toSVG:function(t){var e=[],i=0,r=0,n=this._createBaseSVGMarkup();this.group&&"path-group"===this.group.type||(i=this.pathOffset.x,r=this.pathOffset.y);for(var a=0,h=this.points.length;a\n'),t?t(n.join("")):n.join("")},commonRender:function(t,e){var i,r=this.points.length,n=e?0:this.pathOffset.x,s=e?0:this.pathOffset.y;if(!r||isNaN(this.points[r-1].y))return!1;t.beginPath(),t.moveTo(this.points[0].x-n,this.points[0].y-s);for(var o=0;o"},toObject:function(t){return n(this.callSuper("toObject",["sourcePath","pathOffset"].concat(t)),{path:this.path.map(function(t){return t.slice()}),top:this.top,left:this.left})},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){var r=t.paths;delete t.paths,"string"==typeof r?e.loadSVGFromURL(r,function(n){var s=r,o=e.util.groupSVGElements(n,t,s);t.paths=r,i(o)}):e.util.enlivenObjects(r,function(n){var s=new e.PathGroup(n,t);t.paths=r,i(s)})},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;if(!e.Group){var s={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,cacheProperties:[],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;e.originX&&(this.originX=e.originX),e.originY&&(this.originY=e.originY),i?(this._updateObjectsCoords(!0),this._updateObjectsACoords()):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",e)),this.setCoords(),this.saveCoords()},_updateObjectsACoords:function(){for(var t=this._objects.length;t--;)this._objects[t].setCoords(!0,!0)},_updateObjectsCoords:function(t){for(var e=this.getCenterPoint(),i=this._objects.length;i--;)this._updateObjectCoords(this._objects[i],e,t)},_updateObjectCoords:function(t,e,i){if(t.__origHasControls=t.hasControls,t.hasControls=!1,!i){var r=t.getLeft(),n=t.getTop();t.set({left:r-e.x,top:n-e.y}),t.setCoords(!0,!0)}},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.setCoords(),this.dirty=!0,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.setCoords(),this.dirty=!0,this},_onObjectAdded:function(t){this.dirty=!0,t.group=this,t._set("canvas",this.canvas)},_onObjectRemoved:function(t){this.dirty=!0,delete t.group,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){var e=this.getObjects().map(function(e){var i=e.includeDefaultValues;e.includeDefaultValues=e.group.includeDefaultValues;var r=e.toObject(t);return e.includeDefaultValues=i,r});return i(this.callSuper("toObject",t),{objects:e})},toDatalessObject:function(t){var e=this.getObjects().map(function(e){var i=e.includeDefaultValues;e.includeDefaultValues=e.group.includeDefaultValues;var r=e.toDatalessObject(t);return e.includeDefaultValues=i,r});return i(this.callSuper("toDatalessObject",t),{objects:e})},render:function(t){this._transformDone=!0,this.callSuper("render",t),this._transformDone=!1},shouldCache:function(){var t=this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching());if(this.caching=t,t)for(var e=0,i=this._objects.length;e\n');for(var i=0,r=this._objects.length;i\n"),t?t(e.join("")):e.join("")},get:function(t){if(t in s){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(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){var e=function(){},i=(t=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()}}),fabric.Image.filters.BaseFilter.fromObject=function(t,e){var i=new fabric.Image.filters[t.type](t);return e&&e(i),i},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[S*d+w],e+=p[h]*c,i+=p[h+1]*c,r+=p[h+2]*c,n+=p[h+3]*c);_[s]=e,_[s+1]=i,_[s+2]=r,_[s+3]=n+y*(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=e.Image.filters.BaseFilter.fromObject}("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).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*f=e)){P=r(1e3*s(c-O.x)),w[P]||(w[P]={});for(var I=T.y-S;I<=T.y+S;I++)I<0||I>=o||(E=r(1e3*s(I-O.y)),w[P][E]||(w[P][E]=b(n(i(P*y,2)+i(E*x,2))/1e3)),(f=w[P][E])>0&&(j+=f,k+=f*p[d=4*(I*e+c)],M+=f*p[d+1],D+=f*p[d+2],A+=f*p[d+3]))}v[d=4*(h*a+t)]=k/j,v[d+1]=M/j,v[d+2]=D/j,v[d+3]=A/j}return++tt)return 0;if(e*=Math.PI,s(e)<1e-16)return 1;var i=e/t;return h(e)*h(i)/e/i}}(this.lanczosLobes),m=this.rcpScaleX,_=this.rcpScaleY,y=2/this.rcpScaleX,x=2/this.rcpScaleY,C=c(m*this.lanczosLobes/2),S=c(_*this.lanczosLobes/2),w={},O={},T={};return u(0)},bilinearFiltering:function(t,e,i,n,s){var o,a,h,c,l,u,f,d,g,p=0,v=this.rcpScaleX,b=this.rcpScaleY,m=t.getContext("2d"),_=4*(e-1),y=m.getImageData(0,0,e,i).data,x=m.getImageData(0,0,n,s),C=x.data;for(h=0;h1&&I<-1||(y=2*I*I*I-3*I*I+1)>0&&(T+=y*g[(E=4*(P+k*e))+3],C+=y,g[E+3]<255&&(y=y*g[E+3]/250),S+=y*g[E],w+=y*g[E+1],O+=y*g[E+2],x+=y)}v[_]=S/x,v[_+1]=w/x,v[_+2]=O/x,v[_+3]=T/C}return p},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}}),e.Image.filters.Resize.fromObject=e.Image.filters.BaseFilter.fromObject}("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'},_getCacheCanvasDimensions:function(){var t=this.callSuper("_getCacheCanvasDimensions"),e=this.fontSize;return t.width+=e*t.zoomX,t.height+=e*t.zoomY,t},_render:function(t){this._setTextStyles(t),this.group&&"path-group"===this.group.type&&t.translate(this.left,this.top),this._renderTextLinesBackground(t),this._renderText(t),this._renderTextDecoration(t)},_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},_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)for(var l=this._getWidthOfCharSpacing(),u=0,f=(i=i.split("")).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?i: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;t.fillStyle=s,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=[]},_shouldClearDimensionCache:function(){var t=this._forceClearCache;return t||(t=this.hasStateChanged("_dimensionAffectingProps")),t&&(this.saveState({propertySet:"_dimensionAffectingProps"}),this.dirty=!0),t},_getLineWidth:function(t,e){if(this.__lineWidths[e])return-1===this.__lineWidths[e]?this.width:this.__lineWidths[e];var i,r=this._textLines[e];return i=""===r?0:this._measureLine(t,e),this.__lineWidths[e]=i,i&&"justify"===this.textAlign&&r.split(/\s+/).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=this._textLines[e],n=t.measureText(r).width,s=0;return 0!==this.charSpacing&&(s=(r.split("").length-1)*this._getWidthOfCharSpacing()),(i=n+s)>0?i:0},_renderTextDecoration:function(t){if(this.textDecoration){var e=this.height/2,i=this,r=[];this.textDecoration.indexOf("underline")>-1&&r.push(.85),this.textDecoration.indexOf("line-through")>-1&&r.push(.43),this.textDecoration.indexOf("overline")>-1&&r.push(-.12),r.length>0&&function(r){var n,s,o,a,h,c,l,u=0;for(n=0,s=i._textLines.length;n\n",e.textBgRects.join(""),'\t\t\n',e.textSpans.join(""),"\t\t\n","\t\n")},getSvgStyles:function(t){return e.Object.prototype.getSvgStyles.call(this,t)+" white-space: pre;"},_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"):this._setSVGTextLineJustifed(t,n,h,o)},_setSVGTextLineJustifed:function(t,n,s,o){var a=e.util.createCanvasElement().getContext("2d");this._setTextStyles(a);var h,c,l=this._textLines[t].split(/\s+/),u=this._getWidthOfWords(a,l.join("")),f=this.width-u,d=l.length-1,g=d>0?f/d:0,p=this._getFillAttributes(this.fill);for(o+=this._getLineLeftOffset(this._getLineWidth(a,t)),t=0,c=l.length;t",e.util.string.escapeXml(h),"\n"),o+=this._getWidthOfWords(a,h)+g},_setSVGTextLineBg:function(t,e,n,s,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),this._dimensionAffectingProps.indexOf(t)>-1&&(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)).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)*o,h=s.getHeight()+a,c=0;return"left"===s.originX&&(c=s.getWidth()/2),"right"===s.originX&&(c=-s.getWidth()/2),s.set({left:s.getLeft()+c,top:s.getTop()-h/2+s.fontSize*(.18+s._fontSizeFraction)/s.lineHeight}),s},e.Text.fromObject=function(t,i,r){return e.Object._fromObject("Text",t,i,r,"text")},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=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(),h=0;for(var m,_=0,y=(g=n.split("")).length;_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);var e,i,r,n,s,o,a,h,c,l,u=0,f=this._getLeftOffset(),d=this._getTopOffset(),g="";t.save();for(var p=0,v=this._textLines.length;p0?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.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()))}},_setEditingProps:function(){this.hoverCursor="text",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},_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=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)).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.hiddenTextarea.blur&&this.hiddenTextarea.blur(),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())for(var r=0,n=t.length;r=i&&(o=!0,s[h-i]=this.styles[e][a],delete this.styles[e][a])}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])}var h=r||t(n[i-1]);h&&(this.styles[e][i]=h),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 r){(s=parseInt(n,10))<=e&&delete r[s]}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,t.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.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&&(!t.e.button||1===t.e.button)){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)||t.e.button&&1!==t.e.button||(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.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(t){for(var e,i=this.getLocalPointer(t),r=0,n=0,s=0,o=0,a=0,h=this._textLines.length;as?0:1);return this.flipX&&(o=n-o),o>this.text.length&&(o=this.text.length),o}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.setAttribute("autocorrect","off"),this.hiddenTextarea.setAttribute("autocomplete","off"),this.hiddenTextarea.setAttribute("spellcheck","false"),this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea",""),this.hiddenTextarea.setAttribute("wrap","off");var t=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+t.top+"; left: "+t.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; line-height: 1px; paddingーtop: "+t.fontSize+";",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(),t.keyCode>=33&&t.keyCode<=40?(this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.renderAll()}},onKeyUp:function(t){this.isEditing&&!this._copyDone?t.keyCode in this.ctrlKeysMapUp&&(t.ctrlKey||t.metaKey)&&(this[this.ctrlKeysMapUp[t.keyCode]](t),t.stopImmediatePropagation(),t.preventDefault(),this.canvas&&this.canvas.renderAll()):this._copyDone=!1},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 u=s-l,f=s,d=Math.abs(u-e);o=Math.abs(f-e)=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorUpOrDown("Down",t)},moveCursorUp:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",t)},_moveCursorUpOrDown:function(t,e){var i=this["get"+t+"CursorOffset"](e,"right"===this._selectionDirection);e.shiftKey?this.moveCursorWithShift(i):this.moveCursorWithoutShift(i),0!==i&&(this.setSelectionInBoundaries(),this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(t){var e="left"===this._selectionDirection?this.selectionStart+t:this.selectionEnd+t;return this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,e),0!==t},moveCursorWithoutShift:function(t){return t<0?(this.selectionStart+=t,this.selectionEnd=this.selectionStart):(this.selectionEnd+=t,this.selectionStart=this.selectionEnd),0!==t},moveCursorLeft:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorLeftOrRight("Left",t)},_move:function(t,e,i){var r;if(t.altKey)r=this["findWordBoundary"+i](this[e]);else{if(!t.metaKey&&35!==t.keyCode&&36!==t.keyCode)return this[e]+="Left"===i?-1:1,!0;r=this["findLineBoundary"+i](this[e])}if(void 0!==typeof r&&this[e]!==r)return this[e]=r,!0},_moveLeft:function(t,e){return this._move(t,e,"Left")},_moveRight:function(t,e){return this._move(t,e,"Right")},moveCursorLeftWithoutShift:function(t){var e=!0;return this._selectionDirection="left",this.selectionEnd===this.selectionStart&&0!==this.selectionStart&&(e=this._moveLeft(t,"selectionStart")),this.selectionEnd=this.selectionStart,e},moveCursorLeftWithShift:function(t){return"right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveLeft(t,"selectionEnd"):0!==this.selectionStart?(this._selectionDirection="left",this._moveLeft(t,"selectionStart")):void 0},moveCursorRight:function(t){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorLeftOrRight("Right",t)},_moveCursorLeftOrRight:function(t,e){var i="moveCursor"+t+"With";this._currentCursorOpacity=1,e.shiftKey?i+="Shift":i+="outShift",this[i](e)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(t){return"left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveRight(t,"selectionStart"):this.selectionEnd!==this.text.length?(this._selectionDirection="right",this._moveRight(t,"selectionEnd")):void 0},moveCursorRightWithoutShift:function(t){var e=!0;return this._selectionDirection="right",this.selectionStart===this.selectionEnd?(e=this._moveRight(t,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd,e},removeChars:function(t){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(t):this._removeCharsFromTo(this.selectionStart,this.selectionEnd),this.set("dirty",!0),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={});e.Textbox=e.util.createClass(e.IText,e.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:2,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,noScaleCache:!1,_dimensionAffectingProps:e.Text.prototype._dimensionAffectingProps.concat("width"),initialize:function(t,i){this.callSuper("initialize",t,i),this.setControlsVisibility(e.Textbox.getTextboxControlVisibility()),this.ctx=this.objectCaching?this._cacheContext:e.util.createCanvasElement().getContext("2d")},_initDimensions:function(t){this.__skipDimension||(t||(t=e.util.createCanvasElement().getContext("2d"),this._setTextStyles(t),this.clearContextTop()),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(t),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(t),this.setCoords())},_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&&!f?(n.push(s),s="",r=c,f=!0):r+=d,f||(s+=" "),s+=a,l=this._measureText(t," ",i,h),h++,f=!1,c>u&&(u=c);return g&&n.push(s),u>this.dynamicMinWidth&&(this.dynamicMinWidth=u-d),n},_splitTextIntoLines:function(t){t=t||this.ctx;var e=this.textAlign;this._styleMap=null,t.save(),this._setTextStyles(t),this.textAlign="left";var i=this._wrapText(t,this.text);return this.textAlign=e,t.restore(),this._textLines=i,this._styleMap=this._generateStyleMap(),i},setOnGroup:function(t,e){"scaleX"===t&&(this.set("scaleX",Math.abs(1/e)),this.set("width",this.get("width")*e/(void 0===this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=e)},get2DCursorLocation:function(t){void 0===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(void 0!==fabric.Textbox)for(var t=this._objects.length;t--;)if(this._objects[t]instanceof fabric.Textbox)return void this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility())},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,e){t=this._styleMap[t].line,fabric.IText.prototype.shiftLineStyles.call(this,t,e)},_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).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)})});n.on("error",function(t){t.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+r.hostname+":"+r.port):fabric.log(t.message),i(null)}),n.end()}function requestFs(t,e){require("fs").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){0!==(t=t.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim()).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||{}).nodeCanvas=s,i.nodeCacheCanvas=o;var a=new(fabric.Canvas||fabric.StaticCanvas)(n,i);return a.nodeCanvas=s,a.nodeCacheCanvas=o,a.contextContainer=s.getContext("2d"),a.contextCache=o.getContext("2d"),a.Font=Canvas.Font,a};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)}}();/* pako 0.2.3 nodeca/pako */ +var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(e,b,d){if(d.get||d.set)throw new TypeError("ES3 does not support getters and setters.");e!=Array.prototype&&e!=Object.prototype&&(e[b]=d.value)};$jscomp.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global?global:e};$jscomp.global=$jscomp.getGlobal(this); +$jscomp.polyfill=function(e,b,d,c){if(b){d=$jscomp.global;e=e.split(".");for(c=0;cd&&(d=Math.max(0,a+d));if(null==c||c>a)c=a;c=Number(c);0>c&&(c=Math.max(0,a+c));for(d=Number(d||0);db||1342177279>>=1)d+=d;return c}},"es6-impl","es3");$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.symbolCounter_=0; +$jscomp.Symbol=function(e){return $jscomp.SYMBOL_PREFIX+(e||"")+$jscomp.symbolCounter_++};$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var e=$jscomp.global.Symbol.iterator;e||(e=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[e]&&$jscomp.defineProperty(Array.prototype,e,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}}; +$jscomp.arrayIterator=function(e){var b=0;return $jscomp.iteratorPrototype(function(){return bf;)f+=n[l++%h], +f>e&&(f=e),a[k?"lineTo":"moveTo"](f,0),k=!k;a.restore()},createCanvasElement:function(a){a||(a=fabric.document.createElement("canvas"));a.getContext||"undefined"===typeof G_vmlCanvasManager||G_vmlCanvasManager.initElement(a);return a},createImage:function(){return fabric.isLikelyNode?new (require("canvas").Image):fabric.document.createElement("img")},createAccessors:function(a){a=a.prototype;var f,c,b,d;for(f=a.stateProperties.length;f--;)c=a.stateProperties[f],b=c.charAt(0).toUpperCase()+c.slice(1), +d="set"+b,b="get"+b,a[b]||(a[b]=new Function('return this.get("'+c+'")')),a[d]||(a[d]=new Function("value",'return this.set("'+c+'", value)'))},clipContext:function(a,f){f.save();f.beginPath();a.clipTo(f);f.clip()},multiplyTransformMatrices:function(a,f,c){return[a[0]*f[0]+a[2]*f[1],a[1]*f[0]+a[3]*f[1],a[0]*f[2]+a[2]*f[3],a[1]*f[2]+a[3]*f[3],c?0:a[0]*f[4]+a[2]*f[5]+a[4],c?0:a[1]*f[4]+a[3]*f[5]+a[5]]},qrDecompose:function(a){var f=d(a[1],a[0]),h=c(a[0],2)+c(a[1],2),k=b(h),e=(a[0]*a[3]-a[2]*a[1])/k, +h=d(a[0]*a[2]+a[1]*a[3],h);return{angle:f/g,scaleX:k,scaleY:e,skewX:h/g,skewY:0,translateX:a[4],translateY:a[5]}},customTransformMatrix:function(c,f,b){b=[1,0,a(Math.tan(b*g)),1];c=[a(c),0,0,a(f)];return fabric.util.multiplyTransformMatrices(c,b,!0)},resetObjectTransform:function(a){a.scaleX=1;a.scaleY=1;a.skewX=0;a.skewY=0;a.flipX=!1;a.flipY=!1;a.setAngle(0)},getFunctionBody:function(a){return(String(a).match(/function[^{]*\{([\s\S]*)\}/)||{})[1]},isTransparent:function(a,f,c,b){0b?f-b: +0,c=c>b?c-b:0);var d=!0;f=a.getImageData(f,c,2*b||1,2*b||1);c=f.data.length;for(a=3;a=d,!1!==d);a+=4);return d},parsePreserveAspectRatioAttribute:function(a){var f="meet",c;(a=a.split(" "))&&a.length&&(f=a.pop(),"meet"!==f&&"slice"!==f?(c=f,f="meet"):a.length&&(c=a.pop()));a="none"!==c?c.slice(1,4):"none";c="none"!==c?c.slice(5,8):"none";return{meetOrSlice:f,alignX:a,alignY:c}},clearFabricFontCache:function(a){a?fabric.charWidthsCache[a]&&delete fabric.charWidthsCache[a]:fabric.charWidthsCache= +{}},limitDimsByArea:function(a,f){var c=Math.sqrt(f*a);return{x:Math.floor(c),y:Math.floor(f/c)}},capValue:function(a,f,c){return Math.max(a,Math.min(f,c))}}})("undefined"!==typeof exports?exports:this); +(function(){function e(c,g,h,e,p,q,t){var l=f.call(arguments);if(a[l])return a[l];var k=Math.PI,m=t*k/180,n=Math.sin(m),m=Math.cos(m),y=0,x=0;h=Math.abs(h);e=Math.abs(e);var u=-m*c*.5-n*g*.5,C=-m*g*.5+n*c*.5,D=h*h,z=e*e,E=C*C,B=u*u,F=D*z-D*E-z*B,G=0;0>F?(D=Math.sqrt(1-F/(D*z)),h*=D,e*=D):G=(p===q?-1:1)*Math.sqrt(F/(D*E+z*B));E=G*h*C/e;B=-G*e*u/h;G=m*E-n*B+.5*c;D=n*E+m*B+.5*g;z=d(1,0,(u-E)/h,(C-B)/e);C=d((u-E)/h,(C-B)/e,(-u-E)/h,(-C-B)/e);0===q&&0C&&(C+=2*k);k=Math.ceil(Math.abs(C/ +k*2));u=[];C/=k;E=8/3*Math.sin(C/4)*Math.sin(C/4)/Math.sin(C/2);B=z+C;for(F=0;F=a?c-a:2*Math.PI- +(a-c)}function c(a,c,b,d,g,e,t,r){var l=f.call(arguments);if(h[l])return h[l];var k=Math.sqrt,m=Math.min,n=Math.max,p=Math.abs,q=[],C=[[],[]],D,z,E,B,F;z=6*a-12*b+6*g;D=-3*a+9*b-9*g+3*t;E=3*b-3*a;for(var G=0;2>G;++G)0p(D)?1E-12>p(z)||(B=-E/z,0B&&q.push(B)):(B=z*z-4*E*D,0>B||(F=k(B),B=(-z+F)/(2*D),0B&&q.push(B),B=(-z-F)/(2*D),0B&&q.push(B)));for(p=k=q.length;k--;)B=q[k],z=1-B,D=z*z*z*a+3*z*z*B*b+3*z*B*B*g+B*B*B*t,C[0][k]=D,D= +z*z*z*c+3*z*z*B*d+3*z*B*B*e+B*B*B*r,C[1][k]=D;C[0][p]=a;C[1][p]=c;C[0][p+1]=t;C[1][p+1]=r;m=[{x:m.apply(null,C[0]),y:m.apply(null,C[1])},{x:n.apply(null,C[0]),y:n.apply(null,C[1])}];return h[l]=m}var a={},g={},h={},f=Array.prototype.join;fabric.util.drawArc=function(a,f,c,b){var d=[[],[],[],[]];b=e(b[5]-f,b[6]-c,b[0],b[1],b[3],b[4],b[2]);for(var g=0,h=b.length;g>>0;if(0===a)return-1;var d=0;0=a)return-1;for(d=0<=d?d:Math.max(a-Math.abs(d),0);d>>0;a>>0;d>> +0;a>>0;a>>0;h>>0,a=0,d;if(1=c)throw new TypeError;}while(1)}for(;a=c})}}})(); +(function(){function e(b,d,c){if(c)if(!fabric.isLikelyNode&&d instanceof Element)b=d;else if(d instanceof Array){b=[];for(var a=0,g=d.length;a/g,">")}}})(); +(function(){var e=Array.prototype.slice,b=Function.prototype.apply,d=function(){};Function.prototype.bind||(Function.prototype.bind=function(c){var a=this,g=e.call(arguments,1),h;h=g.length?function(){return b.call(a,this instanceof d?this:c,g.concat(e.call(arguments)))}:function(){return b.call(a,this instanceof d?this:c,arguments)};d.prototype=this.prototype;h.prototype=new d;return h})})(); +(function(){function e(){}function b(a){for(var f=null,c=this;c.constructor.superclass;){var b=c.constructor.superclass.prototype[a];if(c[a]!==b){f=b;break}c=c.constructor.superclass.prototype}return f?1f?h:l-d;a=g/h;g=p(g,q,r,h);k(g,Math.abs((g-q)/r),a);l>f?c.onComplete&&c.onComplete():b(A)}})(d)})};fabric.util.requestAnimFrame=b})(); +(function(){fabric.util.animateColor=function(e,b,d,c){e=(new fabric.Color(e)).getSource();b=(new fabric.Color(b)).getSource();c=c||{};fabric.util.animate(fabric.util.object.extend(c,{duration:d||500,startValue:e,endValue:b,byValue:b,easing:function(a,b,d,f){a=c.colorEasing?c.colorEasing(a,f):1-Math.cos(a/f*(Math.PI/2));f="rgba("+parseInt(b[0]+a*(d[0]-b[0]),10)+","+parseInt(b[1]+a*(d[1]-b[1]),10)+","+parseInt(b[2]+a*(d[2]-b[2]),10);f+=","+(b&&d?parseFloat(b[3]+a*(d[3]-b[3])):1);return f+")"}}))}})(); +(function(){function e(a,c,b,f){aa?b/2*a*a+c:-b/2*(--a*(a-2)-1)+c},easeInCubic:function(a,c,b,f){return b*(a/=f)*a*a+c},easeOutCubic:function(a,c,b,f){return b*((a=a/f-1)*a*a+1)+c},easeInOutCubic:function(a,c,b,f){a/=f/2;return 1>a?b/2*a*a*a+c:b/2*((a-=2)*a*a+2)+c},easeInQuart:function(a,c,b,f){return b*(a/=f)*a*a*a+c},easeOutQuart:function(a,c,b,f){return-b*((a=a/f-1)*a*a*a-1)+c},easeInOutQuart:function(a, +c,b,f){a/=f/2;return 1>a?b/2*a*a*a*a+c:-b/2*((a-=2)*a*a*a-2)+c},easeInQuint:function(a,c,b,f){return b*(a/=f)*a*a*a*a+c},easeOutQuint:function(a,c,b,f){return b*((a=a/f-1)*a*a*a*a+1)+c},easeInOutQuint:function(a,c,b,f){a/=f/2;return 1>a?b/2*a*a*a*a*a+c:b/2*((a-=2)*a*a*a*a+2)+c},easeInSine:function(a,c,b,f){return-b*Math.cos(a/f*(Math.PI/2))+b+c},easeOutSine:function(a,c,b,f){return b*Math.sin(a/f*(Math.PI/2))+c},easeInOutSine:function(a,c,b,f){return-b/2*(Math.cos(Math.PI*a/f)-1)+c},easeInExpo:function(a, +c,b,f){return 0===a?c:b*Math.pow(2,10*(a/f-1))+c},easeOutExpo:function(a,c,b,f){return a===f?c+b:b*(-Math.pow(2,-10*a/f)+1)+c},easeInOutExpo:function(a,c,b,f){if(0===a)return c;if(a===f)return c+b;a/=f/2;return 1>a?b/2*Math.pow(2,10*(a-1))+c:b/2*(-Math.pow(2,-10*--a)+2)+c},easeInCirc:function(a,c,b,f){return-b*(Math.sqrt(1-(a/=f)*a)-1)+c},easeOutCirc:function(a,c,b,f){return b*Math.sqrt(1-(a=a/f-1)*a)+c},easeInOutCirc:function(a,c,b,f){a/=f/2;return 1>a?-b/2*(Math.sqrt(1-a*a)-1)+c:b/2*(Math.sqrt(1- +(a-=2)*a)+1)+c},easeInElastic:function(a,c,d,f){var g=0;if(0===a)return c;a/=f;if(1===a)return c+d;g||(g=.3*f);d=e(d,d,g,1.70158);return-b(d,a,f)+c},easeOutElastic:function(a,c,b,f){var d=0;if(0===a)return c;a/=f;if(1===a)return c+b;d||(d=.3*f);b=e(b,b,d,1.70158);return b.a*Math.pow(2,-10*a)*Math.sin(2*(a*f-b.s)*Math.PI/b.p)+b.c+c},easeInOutElastic:function(a,c,d,f){var g=0;if(0===a)return c;a/=f/2;if(2===a)return c+d;g||(g=.3*f*1.5);d=e(d,d,g,1.70158);return 1>a?-.5*b(d,a,f)+c:d.a*Math.pow(2,-10* +--a)*Math.sin(2*(a*f-d.s)*Math.PI/d.p)*.5+d.c+c},easeInBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);return b*(a/=f)*a*((d+1)*a-d)+c},easeOutBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);return b*((a=a/f-1)*a*((d+1)*a+d)+1)+c},easeInOutBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);a/=f/2;return 1>a?b/2*a*a*(((d*=1.525)+1)*a-d)+c:b/2*((a-=2)*a*(((d*=1.525)+1)*a+d)+2)+c},easeInBounce:d,easeOutBounce:c,easeInOutBounce:function(a,b,h,f){return ab?b:c);if(1===c&&1===b&&0===d&&0===g&& +0===m&&0===n)return r;if(m||n)A=" translate("+q(m)+" "+q(n)+") ";c=A+" matrix("+c+" 0 0 "+b+" "+d*c+" "+g*b+") ";if("svg"===a.nodeName){for(b=a.ownerDocument.createElement("g");a.firstChild;)b.appendChild(a.firstChild);a.appendChild(b)}else b=a,c=b.getAttribute("transform")+c;b.setAttribute("transform",c);return r}var k=e.fabric||(e.fabric={}),m=k.util.object.extend,n=k.util.object.clone,p=k.util.toFixed,q=k.util.parseUnit,t=k.util.multiplyTransformMatrices,r=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i, +v=/^(symbol|image|marker|pattern|view|svg)$/i,A=/^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i,w=/^(symbol|g|a|svg)$/i,y={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",opacity:"opacity"},x={stroke:"strokeOpacity",fill:"fillOpacity"};k.cssRules={};k.gradientDefs={};k.parseTransformAttribute=function(){function a(a,f){var c=Math.cos(f[0]),b=Math.sin(f[0]),d=0,g=0;3===f.length&&(d=f[1],g=f[2]);a[0]=c;a[1]=b;a[2]=-b;a[3]=c;a[4]=d-(c*d-b*g);a[5]=g-(b*d+c*g)}function f(a,f){var c=2===f.length?f[1]:f[0];a[0]=f[0];a[3]=c}function c(a,f){a[4]=f[0];2=== +f.length&&(a[5]=f[1])}var b=[1,0,0,1,0,0],d=k.reNum,g="(?:"+("(?:(matrix)\\s*\\(\\s*("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")\\s*\\))")+"|"+("(?:(translate)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+("(?:(scale)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+("(?:(rotate)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+ +("(?:(skewX)\\s*\\(\\s*("+d+")\\s*\\))")+"|"+("(?:(skewY)\\s*\\(\\s*("+d+")\\s*\\))")+")",l=new RegExp("^\\s*(?:"+("(?:"+g+"(?:(?:\\s+,?\\s*|,\\s*)*"+g+")*)")+"?)\\s*$"),h=new RegExp(g,"g");return function(d){var e=b.concat(),m=[];if(!d||d&&!l.test(d))return e;d.replace(h,function(d){var l=(new RegExp(g)).exec(d).filter(function(a){return!!a});d=l[1];l=l.slice(2).map(parseFloat);switch(d){case "translate":c(e,l);break;case "rotate":l[0]=k.util.degreesToRadians(l[0]);a(e,l);break;case "scale":f(e, +l);break;case "skewX":e[2]=Math.tan(k.util.degreesToRadians(l[0]));break;case "skewY":e[1]=Math.tan(k.util.degreesToRadians(l[0]));break;case "matrix":e=l}m.push(e.concat());e=b.concat()});for(d=m[0];1/i,"")));d&&d.documentElement||f&&f(null);k.parseSVGDocument(d.documentElement,function(a,c){f&&f(a,c)},c,b)}})},loadSVGFromString:function(a,f,c,b){a=a.trim();var d;if("undefined"!==typeof DOMParser){var g=new DOMParser;g&&g.parseFromString&&(d=g.parseFromString(a,"text/xml"))}else k.window.ActiveXObject&& +(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(a.replace(//i,"")));k.parseSVGDocument(d.documentElement,function(a,c){f(a,c)},c,b)}})})("undefined"!==typeof exports?exports:this);fabric.ElementsParser=function(e,b,d,c,a){this.elements=e;this.callback=b;this.options=d;this.reviver=c;this.svgUid=d&&d.svgUid||0;this.parsingOptions=a}; +fabric.ElementsParser.prototype.parse=function(){this.instances=Array(this.elements.length);this.numElements=this.elements.length;this.createObjects()};fabric.ElementsParser.prototype.createObjects=function(){for(var e=0,b=this.elements.length;eb.x&&this.y>b.y},gte:function(b){return this.x>=b.x&&this.y>=b.y},lerp:function(d,c){"undefined"===typeof c&&(c=.5);c=Math.max(Math.min(1,c),0);return new b(this.x+(d.x-this.x)*c,this.y+(d.y-this.y)*c)},distanceFrom:function(b){var c=this.x-b.x;b=this.y-b.y;return Math.sqrt(c*c+b*b)},midPointFrom:function(b){return this.lerp(b)},min:function(d){return new b(Math.min(this.x,d.x),Math.min(this.y,d.y))},max:function(d){return new b(Math.max(this.x,d.x),Math.max(this.y, +d.y))},toString:function(){return this.x+","+this.y},setXY:function(b,c){this.x=b;this.y=c;return this},setX:function(b){this.x=b;return this},setY:function(b){this.y=b;return this},setFromPoint:function(b){this.x=b.x;this.y=b.y;return this},swap:function(b){var c=this.x,a=this.y;this.x=b.x;this.y=b.y;b.x=c;b.y=a},clone:function(){return new b(this.x,this.y)}})})("undefined"!==typeof exports?exports:this); +(function(e){function b(b){this.status=b;this.points=[]}var d=e.fabric||(e.fabric={});d.Intersection?d.warn("fabric.Intersection is already defined"):(d.Intersection=b,d.Intersection.prototype={constructor:b,appendPoint:function(b){this.points.push(b);return this},appendPoints:function(b){this.points=this.points.concat(b);return this}},d.Intersection.intersectLineLine=function(c,a,g,h){var f,l=(h.x-g.x)*(c.y-g.y)-(h.y-g.y)*(c.x-g.x);f=(a.x-c.x)*(c.y-g.y)-(a.y-c.y)*(c.x-g.x);g=(h.y-g.y)*(a.x-c.x)- +(h.x-g.x)*(a.y-c.y);0!==g?(l/=g,f/=g,0<=l&&1>=l&&0<=f&&1>=f?(f=new b("Intersection"),f.appendPoint(new d.Point(c.x+l*(a.x-c.x),c.y+l*(a.y-c.y)))):f=new b):f=0===l||0===f?new b("Coincident"):new b("Parallel");return f},d.Intersection.intersectLinePolygon=function(c,a,d){for(var g=new b,f=d.length,l,e,m=0;mc&&(c+=1);1c?b:c<2/3?a+(b-a)*(2/3-c)*6:a}var c=e.fabric||(e.fabric={});c.Color?c.warn("fabric.Color is already defined."):(c.Color=b,c.Color.prototype={_tryParsingColor:function(a){var c;a in b.colorNameMap&&(a=b.colorNameMap[a]);"transparent"===a&&(c=[255,255,255,0]);c||(c=b.sourceFromHex(a));c||(c=b.sourceFromRgb(a));c||(c=b.sourceFromHsl(a));c||(c=[0,0,0,1]);c&& +this.setSource(c)},_rgbToHsl:function(a,b,d){a/=255;b/=255;d/=255;var f,g,h,e=c.util.array.max([a,b,d]);g=c.util.array.min([a,b,d]);h=(e+g)/2;if(e===g)f=g=0;else{var n=e-g;g=.5l;l++)c.push(Math.round(.5*f[l]+.5*a[l]));c[3]=d;this.setSource(c);return this}},c.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*)?\)$/,c.Color.reHSLa= +/^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/,c.Color.reHex=/^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i,c.Color.colorNameMap={aqua:"#00FFFF",black:"#000000",blue:"#0000FF",fuchsia:"#FF00FF",gray:"#808080",grey:"#808080",green:"#008000",lime:"#00FF00",maroon:"#800000",navy:"#000080",olive:"#808000",orange:"#FFA500",purple:"#800080",red:"#FF0000",silver:"#C0C0C0",teal:"#008080",white:"#FFFFFF",yellow:"#FFFF00"},c.Color.fromRgb=function(a){return b.fromSource(b.sourceFromRgb(a))}, +c.Color.sourceFromRgb=function(a){if(a=a.match(b.reRGBa)){var c=parseInt(a[1],10)/(/%$/.test(a[1])?100:1)*(/%$/.test(a[1])?255:1),d=parseInt(a[2],10)/(/%$/.test(a[2])?100:1)*(/%$/.test(a[2])?255:1),f=parseInt(a[3],10)/(/%$/.test(a[3])?100:1)*(/%$/.test(a[3])?255:1);return[parseInt(c,10),parseInt(d,10),parseInt(f,10),a[4]?parseFloat(a[4]):1]}},c.Color.fromRgba=b.fromRgb,c.Color.fromHsl=function(a){return b.fromSource(b.sourceFromHsl(a))},c.Color.sourceFromHsl=function(a){if(a=a.match(b.reHSLa)){var c= +(parseFloat(a[1])%360+360)%360/360,h=parseFloat(a[2])/(/%$/.test(a[2])?100:1),f=parseFloat(a[3])/(/%$/.test(a[3])?100:1);if(0===h)f=h=c=f;else var l=.5>=f?f*(h+1):f+h-f*h,e=2*f-l,f=d(e,l,c+1/3),h=d(e,l,c),c=d(e,l,c-1/3);return[Math.round(255*f),Math.round(255*h),Math.round(255*c),a[4]?parseFloat(a[4]):1]}},c.Color.fromHsla=b.fromHsl,c.Color.fromHex=function(a){return b.fromSource(b.sourceFromHex(a))},c.Color.sourceFromHex=function(a){if(a.match(b.reHex)){var c=a.slice(a.indexOf("#")+1),d=3===c.length|| +4===c.length,f=8===c.length||4===c.length;a=d?c.charAt(0)+c.charAt(0):c.substring(0,2);var l=d?c.charAt(1)+c.charAt(1):c.substring(2,4),e=d?c.charAt(2)+c.charAt(2):c.substring(4,6),c=f?d?c.charAt(3)+c.charAt(3):c.substring(6,8):"FF";return[parseInt(a,16),parseInt(l,16),parseInt(e,16),parseFloat((parseInt(c,16)/255).toFixed(2))]}},c.Color.fromSource=function(a){var c=new b;c.setSource(a);return c})})("undefined"!==typeof exports?exports:this); +(function(){function e(c){var a=c.getAttribute("style"),b=c.getAttribute("offset")||0,d,f,b=parseFloat(b)/(/%$/.test(b)?100:1),b=0>b?0:1a.r2;h.sort(function(a,f){return a.offset-f.offset});if(!b.group||"path-group"!==b.group.type)for(var l in a)if("x1"===l||"x2"===l)a[l]+=this.offsetX-b.width/2;else if("y1"===l||"y2"===l)a[l]+=this.offsetY-b.height/2;b='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"';this.gradientTransform&&(b+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" ');"linear"===this.type?c=["\n']:"radial"===this.type&&(c=["\n']);if("radial"===this.type){if(f)for(h=h.concat(),h.reverse(),f=0;f\n');c.push("linear"===this.type?"\n":"\n");return c.join("")},toLive:function(b,a){var c,d,f=fabric.util.object.clone(this.coords);if(this.type){if(a.group&&"path-group"===a.group.type)for(d in f)if("x1"===d||"x2"===d)f[d]+=-this.offsetX+a.width/2;else if("y1"===d||"y2"===d)f[d]+=-this.offsetY+a.height/2;"linear"===this.type?c=b.createLinearGradient(f.x1,f.y1,f.x2,f.y2):"radial"=== +this.type&&(c=b.createRadialGradient(f.x1,f.y1,f.r1,f.x2,f.y2,f.r2));d=0;for(f=this.colorStops.length;d\n\n\n'},setOptions:function(b){for(var d in b)this[d]=b[d]}, +toLive:function(b){var d="function"===typeof this.source?this.source():this.source;return d&&("undefined"===typeof d.src||d.complete&&0!==d.naturalWidth&&0!==d.naturalHeight)?b.createPattern(d,this.repeat):""}})})(); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.toFixed;b.Shadow?b.warn("fabric.Shadow is already defined."):(b.Shadow=b.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(c){"string"===typeof c&&(c=this._parseShadow(c));for(var a in c)this[a]=c[a];this.id=b.Object.__uid++},_parseShadow:function(c){c=c.trim();var a=b.Shadow.reOffsetsAndBlur.exec(c)||[];return{color:(c.replace(b.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(), +offsetX:parseInt(a[1],10)||0,offsetY:parseInt(a[2],10)||0,blur:parseInt(a[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(c){var a=40,g=40,h=b.Object.NUM_FRACTION_DIGITS,f=b.util.rotateVector({x:this.offsetX,y:this.offsetY},b.util.degreesToRadians(-c.angle));c.width&&c.height&&(a=100*d((Math.abs(f.x)+this.blur)/c.width,h)+20,g=100*d((Math.abs(f.y)+this.blur)/c.height,h)+20);c.flipX&&(f.x*=-1);c.flipY&&(f.y*=-1);return'\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 c={},a=b.Shadow.prototype;["color","blur","offsetX","offsetY","affectStroke"].forEach(function(b){this[b]!==a[b]&&(c[b]=this[b])},this);return c}}),b.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/)})("undefined"!==typeof exports?exports:this); +(function(){if(fabric.StaticCanvas)fabric.warn("fabric.StaticCanvas is already defined.");else{var e=fabric.util.object.extend,b=fabric.util.getElementOffset,d=fabric.util.removeFromArray,c=fabric.util.toFixed,a=fabric.util.transformPoint,g=fabric.util.invertTransform,h=Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(a,b){b||(b={});this._initStatic(a,b)},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:!1,_initStatic:function(a,b){var f=fabric.StaticCanvas.prototype.renderAll.bind(this);this._objects=[];this._createLowerCanvas(a);this._initOptions(b);this._setImageSmoothing();this.interactive||this._initRetinaScaling(); +b.overlayImage&&this.setOverlayImage(b.overlayImage,f);b.backgroundImage&&this.setBackgroundImage(b.backgroundImage,f);b.backgroundColor&&this.setBackgroundColor(b.backgroundColor,f);b.overlayColor&&this.setOverlayColor(b.overlayColor,f);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(){this._offset=b(this.lowerCanvasEl);return this},setOverlayImage:function(a,b,c){return this.__setBgOverlayImage("overlayImage",a,b,c)},setBackgroundImage:function(a,b,c){return this.__setBgOverlayImage("backgroundImage",a,b,c)},setOverlayColor:function(a,b){return this.__setBgOverlayColor("overlayColor", +a,b)},setBackgroundColor:function(a,b){return this.__setBgOverlayColor("backgroundColor",a,b)},_setImageSmoothing:function(){var a=this.getContext();a.imageSmoothingEnabled=a.imageSmoothingEnabled||a.webkitImageSmoothingEnabled||a.mozImageSmoothingEnabled||a.msImageSmoothingEnabled||a.oImageSmoothingEnabled;a.imageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(a,b,c,d){"string"===typeof b?fabric.util.loadImage(b,function(b){b&&(this[a]=new fabric.Image(b,d));c&&c(b)},this, +d&&d.crossOrigin):(d&&b.setOptions(d),this[a]=b,c&&c(b));return this},__setBgOverlayColor:function(a,b,c){this[a]=b;this._initGradient(b,a);this._initPattern(b,a,c);return this},_createCanvasElement:function(a){a=fabric.util.createCanvasElement(a);a.style||(a.style={});if(!a)throw h;if("undefined"===typeof a.getContext)throw h;return a},_initOptions:function(a){this._setOptions(a);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(a){this.lowerCanvasEl=fabric.util.getById(a)||this._createCanvasElement(a);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(a,b){return this.setDimensions({width:a},b)},setHeight:function(a,b){return this.setDimensions({height:a},b)},setDimensions:function(a,b){var f;b=b||{};for(var c in a)f=a[c],b.cssOnly||(this._setBackstoreDimension(c,a[c]),f+="px"),b.backstoreOnly||this._setCssDimension(c,f);this._initRetinaScaling();this._setImageSmoothing();this.calcOffset();b.cssOnly||this.renderAll(); +return this},_setBackstoreDimension:function(a,b){this.lowerCanvasEl[a]=b;this.upperCanvasEl&&(this.upperCanvasEl[a]=b);this.cacheCanvasEl&&(this.cacheCanvasEl[a]=b);this[a]=b;return this},_setCssDimension:function(a,b){this.lowerCanvasEl.style[a]=b;this.upperCanvasEl&&(this.upperCanvasEl.style[a]=b);this.wrapperEl&&(this.wrapperEl.style[a]=b);return this},getZoom:function(){return this.viewportTransform[0]},setViewportTransform:function(a){var b=this._activeGroup;this.viewportTransform=a;for(var f= +0,c=this._objects.length;f");return c.join("")},_setSVGPreamble:function(a,b){b.suppressPreamble||a.push('\n','\n')},_setSVGHeader:function(a,b){var f=b.width||this.width,d= +b.height||this.height,g;g='viewBox="0 0 '+this.width+" "+this.height+'" ';var h=fabric.Object.NUM_FRACTION_DIGITS;b.viewBox?g='viewBox="'+b.viewBox.x+" "+b.viewBox.y+" "+b.viewBox.width+" "+b.viewBox.height+'" ':this.svgViewportTransformation&&(g=this.viewportTransform,g='viewBox="'+c(-g[4]/g[0],h)+" "+c(-g[5]/g[3],h)+" "+c(this.width/g[0],h)+" "+c(this.height/g[3],h)+'" ');a.push("\n',"Created with Fabric.js ",fabric.version,"\n","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),"\n")},createSVGRefElementsMarkup:function(){var a=this;return["backgroundColor","overlayColor"].map(function(b){if((b=a[b])&&b.toLive)return b.toSVG(a,!1)}).join("")},createSVGFontFacesMarkup:function(){for(var a="",b={},c,d,g,h,e,t=fabric.fontPaths,r=this.getObjects(),v=0,A=r.length;v\n',a,"]]\x3e</style>\n"].join(""));return a},_setSVGObjects:function(a,b){for(var c,f=0,d=this.getObjects(),g=d.length;f<g;f++)c=d[f],c.excludeFromExport||this._setSVGObject(a,c,b)},_setSVGObject:function(a, +b,c){a.push(b.toSVG(c))},_setSVGBgOverlayImage:function(a,b,c){this[b]&&this[b].toSVG&&a.push(this[b].toSVG(c))},_setSVGBgOverlayColor:function(a,b){var c=this[b];if(c)if(c.toLive){var f=c.repeat;a.push('<rect transform="translate(',this.width/2,",",this.height/2,')"',' x="',c.offsetX-this.width/2,'" y="',c.offsetY-this.height/2,'" ','width="',"repeat-y"===f||"no-repeat"===f?c.source.width:this.width,'" height="',"repeat-x"===f||"no-repeat"===f?c.source.height:this.height,'" fill="url(#SVGID_'+c.id+ +')"',"></rect>\n")}else a.push('<rect x="0" y="0" ','width="',this.width,'" height="',this.height,'" fill="',this[b],'"',"></rect>\n")},sendToBack:function(a){if(!a)return this;var b=this._activeGroup,c;if(a===b)for(c=b._objects,a=c.length;a--;)b=c[a],d(this._objects,b),this._objects.unshift(b);else d(this._objects,a),this._objects.unshift(a);return this.renderAll&&this.renderAll()},bringToFront:function(a){if(!a)return this;var b=this._activeGroup,c;if(a===b)for(c=b._objects,a=0;a<c.length;a++)b= +c[a],d(this._objects,b),this._objects.push(b);else d(this._objects,a),this._objects.push(a);return this.renderAll&&this.renderAll()},sendBackwards:function(a,b){if(!a)return this;var c=this._activeGroup,f,g,h,e=0;if(a===c)for(h=c._objects,c=0;c<h.length;c++)f=h[c],g=this._objects.indexOf(f),g>0+e&&(--g,d(this._objects,f),this._objects.splice(g,0,f)),e++;else g=this._objects.indexOf(a),0!==g&&(g=this._findNewLowerIndex(a,g,b),d(this._objects,a),this._objects.splice(g,0,a));this.renderAll&&this.renderAll(); +return this},_findNewLowerIndex:function(a,b,c){if(c)for(c=b,--b;0<=b;--b){if(a.intersectsWithObject(this._objects[b])||a.isContainedWithinObject(this._objects[b])||this._objects[b].isContainedWithinObject(a)){c=b;break}}else c=b-1;return c},bringForward:function(a,b){if(!a)return this;var c=this._activeGroup,f,g,h,e=0;if(a===c)for(h=c._objects,c=h.length;c--;)f=h[c],g=this._objects.indexOf(f),g<this._objects.length-1-e&&(g+=1,d(this._objects,f),this._objects.splice(g,0,f)),e++;else g=this._objects.indexOf(a), +g!==this._objects.length-1&&(g=this._findNewUpperIndex(a,g,b),d(this._objects,a),this._objects.splice(g,0,a));this.renderAll&&this.renderAll();return this},_findNewUpperIndex:function(a,b,c){if(c)for(c=b,b+=1;b<this._objects.length;++b){if(a.intersectsWithObject(this._objects[b])||a.isContainedWithinObject(this._objects[b])||this._objects[b].isContainedWithinObject(a)){c=b;break}}else c=b+1;return c},moveTo:function(a,b){d(this._objects,a);this._objects.splice(b,0,a);return this.renderAll&&this.renderAll()}, +dispose:function(){this.clear();return this},toString:function(){return"#<fabric.Canvas ("+this.complexity()+"): { objects: "+this.getObjects().length+" }>"}});e(fabric.StaticCanvas.prototype,fabric.Observable);e(fabric.StaticCanvas.prototype,fabric.Collection);e(fabric.StaticCanvas.prototype,fabric.DataURLExporter);e(fabric.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(a){var b=fabric.util.createCanvasElement();if(!b||!b.getContext)return null;var c=b.getContext("2d"); +if(!c)return null;switch(a){case "getImageData":return"undefined"!==typeof c.getImageData;case "setLineDash":return"undefined"!==typeof c.setLineDash;case "toDataURL":return"undefined"!==typeof b.toDataURL;case "toDataURLWithQuality":try{return b.toDataURL("image/jpeg",0),!0}catch(m){}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(e){this.shadow=new fabric.Shadow(e);return this},_setBrushStyles:function(){var e=this.canvas.contextTop;e.strokeStyle=this.color;e.lineWidth=this.width;e.lineCap=this.strokeLineCap;e.lineJoin=this.strokeLineJoin;this.strokeDashArray&&fabric.StaticCanvas.supports("setLineDash")&&e.setLineDash(this.strokeDashArray)},_setShadow:function(){if(this.shadow){var e= +this.canvas.contextTop,b=this.canvas.getZoom();e.shadowColor=this.shadow.color;e.shadowBlur=this.shadow.blur*b;e.shadowOffsetX=this.shadow.offsetX*b;e.shadowOffsetY=this.shadow.offsetY*b}},_resetShadow:function(){var e=this.canvas.contextTop;e.shadowColor="";e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0}}); +(function(){fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{initialize:function(e){this.canvas=e;this._points=[]},onMouseDown:function(e){this._prepareForDrawing(e);this._captureDrawingPath(e);this._render()},onMouseMove:function(e){this._captureDrawingPath(e);this.canvas.clearContext(this.canvas.contextTop);this._render()},onMouseUp:function(){this._finalizeAndAddPath()},_prepareForDrawing:function(e){e=new fabric.Point(e.x,e.y);this._reset();this._addPoint(e);this.canvas.contextTop.moveTo(e.x, +e.y)},_addPoint:function(e){1<this._points.length&&e.eq(this._points[this._points.length-1])||this._points.push(e)},_reset:function(){this._points.length=0;this._setBrushStyles();this._setShadow()},_captureDrawingPath:function(e){e=new fabric.Point(e.x,e.y);this._addPoint(e)},_render:function(){var e=this.canvas.contextTop,b,d;b=this.canvas.viewportTransform;var c=this._points[0],a=this._points[1];e.save();e.transform(b[0],b[1],b[2],b[3],b[4],b[5]);e.beginPath();2===this._points.length&&c.x===a.x&& +c.y===a.y&&(b=this.width/1E3,c=new fabric.Point(c.x,c.y),a=new fabric.Point(a.x,a.y),c.x-=b,a.x+=b);e.moveTo(c.x,c.y);b=1;for(d=this._points.length;b<d;b++)a=c.midPointFrom(a),e.quadraticCurveTo(c.x,c.y,a.x,a.y),c=this._points[b],a=this._points[b+1];e.lineTo(c.x,c.y);e.stroke();e.restore()},convertPointsToSVGPath:function(e){var b=[],d,c=this.width/1E3,a=new fabric.Point(e[0].x,e[0].y),g=new fabric.Point(e[1].x,e[1].y),h=e.length,f=1,l=1,k=2<h;k&&(f=e[2].x<g.x?-1:e[2].x===g.x?0:1,l=e[2].y<g.y?-1: +e[2].y===g.y?0:1);b.push("M ",a.x-f*c," ",a.y-l*c," ");for(d=1;d<h;d++){if(!a.eq(g)){var m=a.midPointFrom(g);b.push("Q ",a.x," ",a.y," ",m.x," ",m.y," ")}a=e[d];d+1<e.length&&(g=e[d+1])}k&&(f=a.x>e[d-2].x?1:a.x===e[d-2].x?0:-1,l=a.y>e[d-2].y?1:a.y===e[d-2].y?0:-1);b.push("L ",a.x+f*c," ",a.y+l*c);return b},createPath:function(e){e=new fabric.Path(e,{fill:null,stroke:this.color,strokeWidth:this.width,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeDashArray:this.strokeDashArray, +originX:"center",originY:"center"});var b=new fabric.Point(e.left,e.top);e.originX=fabric.Object.prototype.originX;e.originY=fabric.Object.prototype.originY;b=e.translateToGivenOrigin(b,"center","center",e.originX,e.originY);e.top=b.y;e.left=b.x;this.shadow&&(this.shadow.affectStroke=!0,e.setShadow(this.shadow));return e},_finalizeAndAddPath:function(){this.canvas.contextTop.closePath();var e=this.convertPointsToSVGPath(this._points).join("");"M 0 0 Q 0 0 0 0 L 0 0"===e?this.canvas.renderAll():(e= +this.createPath(e),this.canvas.add(e),e.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire("path:created",{path:e}))}})})(); +fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(e){this.canvas=e;this.points=[]},drawDot:function(e){e=this.addPoint(e);var b=this.canvas.contextTop,d=this.canvas.viewportTransform;b.save();b.transform(d[0],d[1],d[2],d[3],d[4],d[5]);b.fillStyle=e.fill;b.beginPath();b.arc(e.x,e.y,e.radius,0,2*Math.PI,!1);b.closePath();b.fill();b.restore()},onMouseDown:function(e){this.points.length=0;this.canvas.clearContext(this.canvas.contextTop);this._setShadow();this.drawDot(e)}, +onMouseMove:function(e){this.drawDot(e)},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var b=[],d=0,c=this.points.length;d<c;d++){var a=this.points[d],a=new fabric.Circle({radius:a.radius,left:a.x,top:a.y,originX:"center",originY:"center",fill:a.fill});this.shadow&&a.setShadow(this.shadow);b.push(a)}b=new fabric.Group(b,{originX:"center",originY:"center"});b.canvas=this.canvas;this.canvas.add(b);this.canvas.fire("path:created",{path:b});this.canvas.clearContext(this.canvas.contextTop); +this._resetShadow();this.canvas.renderOnAddRemove=e;this.canvas.renderAll()},addPoint:function(e){e=new fabric.Point(e.x,e.y);var b=fabric.util.getRandomInt(Math.max(0,this.width-20),this.width+20)/2,d=(new fabric.Color(this.color)).setAlpha(fabric.util.getRandomInt(0,100)/100).toRgba();e.radius=b;e.fill=d;this.points.push(e);return e}}); +fabric.SprayBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,density:20,dotWidth:1,dotWidthVariance:1,randomOpacity:!1,optimizeOverlapping:!0,initialize:function(e){this.canvas=e;this.sprayChunks=[]},onMouseDown:function(e){this.sprayChunks.length=0;this.canvas.clearContext(this.canvas.contextTop);this._setShadow();this.addSprayChunk(e);this.render()},onMouseMove:function(e){this.addSprayChunk(e);this.render()},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove= +!1;for(var b=[],d=0,c=this.sprayChunks.length;d<c;d++)for(var a=this.sprayChunks[d],g=0,h=a.length;g<h;g++){var f=new fabric.Rect({width:a[g].width,height:a[g].width,left:a[g].x+1,top:a[g].y+1,originX:"center",originY:"center",fill:this.color});this.shadow&&f.setShadow(this.shadow);b.push(f)}this.optimizeOverlapping&&(b=this._getOptimizedRects(b));b=new fabric.Group(b,{originX:"center",originY:"center"});b.canvas=this.canvas;this.canvas.add(b);this.canvas.fire("path:created",{path:b});this.canvas.clearContext(this.canvas.contextTop); +this._resetShadow();this.canvas.renderOnAddRemove=e;this.canvas.renderAll()},_getOptimizedRects:function(e){for(var b={},d,c=0,a=e.length;c<a;c++)d=e[c].left+""+e[c].top,b[d]||(b[d]=e[c]);e=[];for(d in b)e.push(b[d]);return e},render:function(){var e=this.canvas.contextTop;e.fillStyle=this.color;var b=this.canvas.viewportTransform;e.save();e.transform(b[0],b[1],b[2],b[3],b[4],b[5]);for(var b=0,d=this.sprayChunkPoints.length;b<d;b++){var c=this.sprayChunkPoints[b];"undefined"!==typeof c.opacity&&(e.globalAlpha= +c.opacity);e.fillRect(c.x,c.y,c.width,c.width)}e.restore()},addSprayChunk:function(e){this.sprayChunkPoints=[];for(var b,d,c,a=this.width/2,g=0;g<this.density;g++)b=fabric.util.getRandomInt(e.x-a,e.x+a),d=fabric.util.getRandomInt(e.y-a,e.y+a),c=this.dotWidthVariance?fabric.util.getRandomInt(Math.max(1,this.dotWidth-this.dotWidthVariance),this.dotWidth+this.dotWidthVariance):this.dotWidth,b=new fabric.Point(b,d),b.width=c,this.randomOpacity&&(b.opacity=fabric.util.getRandomInt(0,100)/100),this.sprayChunkPoints.push(b); +this.sprayChunks.push(this.sprayChunkPoints)}}); +fabric.PatternBrush=fabric.util.createClass(fabric.PencilBrush,{getPatternSrc:function(){var e=fabric.document.createElement("canvas"),b=e.getContext("2d");e.width=e.height=25;b.fillStyle=this.color;b.beginPath();b.arc(10,10,10,0,2*Math.PI,!1);b.closePath();b.fill();return e},getPatternSrcFunction:function(){return String(this.getPatternSrc).replace("this.color",'"'+this.color+'"')},getPattern:function(){return this.canvas.contextTop.createPattern(this.source||this.getPatternSrc(),"repeat")},_setBrushStyles:function(){this.callSuper("_setBrushStyles"); +this.canvas.contextTop.strokeStyle=this.getPattern()},createPath:function(e){e=this.callSuper("createPath",e);var b=e._getLeftTopCoords().scalarAdd(e.strokeWidth/2);e.stroke=new fabric.Pattern({source:this.source||this.getPatternSrcFunction(),offsetX:-b.x,offsetY:-b.y});return e}}); +(function(){var e=fabric.util.getPointer,b=fabric.util.degreesToRadians,d=fabric.util.radiansToDegrees,c=Math.atan2,a=Math.abs,g=fabric.StaticCanvas.supports("setLineDash");fabric.Canvas=fabric.util.createClass(fabric.StaticCanvas,{initialize:function(a,b){b||(b={});this._initStatic(a,b);this._initInteractive();this._createCacheCanvas()},uniScaleTransform:!1,uniScaleKey:"shiftKey",centeredScaling:!1,centeredRotation:!1,centeredKey:"altKey",altActionKey:"shiftKey",interactive:!0,selection:!0,selectionKey:"shiftKey", +altSelectionKey:null,selectionColor:"rgba(100, 100, 255, 0.3)",selectionDashArray:[],selectionBorderColor:"rgba(255, 255, 255, 0.3)",selectionLineWidth:1,hoverCursor:"move",moveCursor:"move",defaultCursor:"default",freeDrawingCursor:"crosshair",rotationCursor:"crosshair",containerClass:"canvas-container",perPixelTargetFind:!1,targetFindTolerance:0,skipTargetFind:!1,isDrawingMode:!1,preserveObjectStacking:!1,snapAngle:0,snapThreshold:null,stopContextMenu:!1,fireRightClick:!1,fireMiddleClick:!1,_initInteractive:function(){this._groupSelector= +this._currentTransform=null;this._initWrapperElement();this._createUpperCanvas();this._initEventListeners();this._initRetinaScaling();this.freeDrawingBrush=fabric.PencilBrush&&new fabric.PencilBrush(this);this.calcOffset()},_chooseObjectsToRender:function(){var a=this.getActiveGroup(),b=this.getActiveObject(),c,d=[],g=[];if(!a&&!b||this.preserveObjectStacking)d=this._objects;else{for(var h=0,e=this._objects.length;h<e;h++)c=this._objects[h],a&&a.contains(c)||c===b?g.push(c):d.push(c);a&&(a._set("_objects", +g),d.push(a));b&&d.push(b)}return d},renderAll:function(){!this.contextTopDirty||this._groupSelector||this.isDrawingMode||(this.clearContext(this.contextTop),this.contextTopDirty=!1);this.renderCanvas(this.contextContainer,this._chooseObjectsToRender());return this},renderTop:function(){var a=this.contextTop;this.clearContext(a);this.selection&&this._groupSelector&&this._drawSelection(a);this.fire("after:render");this.contextTopDirty=!0;return this},_resetCurrentTransform:function(){var a=this._currentTransform; +a.target.set({scaleX:a.original.scaleX,scaleY:a.original.scaleY,skewX:a.original.skewX,skewY:a.original.skewY,left:a.original.left,top:a.original.top});this._shouldCenterTransform(a.target)?"rotate"===a.action?this._setOriginToCenter(a.target):("center"!==a.originX&&(a.mouseXSign="right"===a.originX?-1:1),"center"!==a.originY&&(a.mouseYSign="bottom"===a.originY?-1:1),a.originX="center",a.originY="center"):(a.originX=a.original.originX,a.originY=a.original.originY)},containsPoint:function(a,b,c){a= +c||this.getPointer(a,!0);c=b.group&&b.group===this.getActiveGroup()?this._normalizePointer(b.group,a):{x:a.x,y:a.y};return b.containsPoint(c)||b._findTargetCorner(a)},_normalizePointer:function(a,b){var c=a.calcTransformMatrix(),c=fabric.util.invertTransform(c),f=this.restorePointerVpt(b);return fabric.util.transformPoint(f,c)},isTargetTransparent:function(a,b,c){var f=a.hasBorders,d=a.transparentCorners,g=this.contextCache,h=a.selectionBackgroundColor;a.hasBorders=a.transparentCorners=!1;a.selectionBackgroundColor= +"";g.save();g.transform.apply(g,this.viewportTransform);a.render(g);g.restore();a.active&&a._renderControls(g);a.hasBorders=f;a.transparentCorners=d;a.selectionBackgroundColor=h;a=fabric.util.isTransparent(g,b,c,this.targetFindTolerance);this.clearContext(g);return a},_shouldClearSelection:function(a,b){var c=this.getActiveGroup(),f=this.getActiveObject();return!b||b&&c&&!c.contains(b)&&c!==b&&!a[this.selectionKey]||b&&!b.evented||b&&!b.selectable&&f&&f!==b},_shouldCenterTransform:function(a){if(a){var b= +this._currentTransform,c;"scale"===b.action||"scaleX"===b.action||"scaleY"===b.action?c=this.centeredScaling||a.centeredScaling:"rotate"===b.action&&(c=this.centeredRotation||a.centeredRotation);return c?!b.altKey:b.altKey}},_getOriginFromCorner:function(a,b){var c={x:a.originX,y:a.originY};if("ml"===b||"tl"===b||"bl"===b)c.x="right";else if("mr"===b||"tr"===b||"br"===b)c.x="left";if("tl"===b||"mt"===b||"tr"===b)c.y="bottom";else if("bl"===b||"mb"===b||"br"===b)c.y="top";return c},_getActionFromCorner:function(a, +b,c){if(!b)return"drag";switch(b){case "mtr":return"rotate";case "ml":case "mr":return c[this.altActionKey]?"skewY":"scaleX";case "mt":case "mb":return c[this.altActionKey]?"skewX":"scaleY";default:return"scale"}},_setupCurrentTransform:function(a,c){if(c){var f=this.getPointer(a),d=c._findTargetCorner(this.getPointer(a,!0)),g=this._getActionFromCorner(c,d,a),h=this._getOriginFromCorner(c,d);this._currentTransform={target:c,action:g,corner:d,scaleX:c.scaleX,scaleY:c.scaleY,skewX:c.skewX,skewY:c.skewY, +offsetX:f.x-c.left,offsetY:f.y-c.top,originX:h.x,originY:h.y,ex:f.x,ey:f.y,lastX:f.x,lastY:f.y,left:c.left,top:c.top,theta:b(c.angle),width:c.width*c.scaleX,mouseXSign:1,mouseYSign:1,shiftKey:a.shiftKey,altKey:a[this.centeredKey]};this._currentTransform.original={left:c.left,top:c.top,scaleX:c.scaleX,scaleY:c.scaleY,skewX:c.skewX,skewY:c.skewY,originX:h.x,originY:h.y};this._resetCurrentTransform()}},_translateObject:function(a,b){var c=this._currentTransform,f=c.target,d=a-c.offsetX,c=b-c.offsetY, +g=!f.get("lockMovementX")&&f.left!==d,h=!f.get("lockMovementY")&&f.top!==c;g&&f.set("left",d);h&&f.set("top",c);return g||h},_changeSkewTransformOrigin:function(a,b,c){var f="originX",d={0:"center"},g=b.target.skewX,h="left",e="right",l="mt"===b.corner||"ml"===b.corner?1:-1,k=1;a=0<a?1:-1;"y"===c&&(g=b.target.skewY,h="top",e="bottom",f="originY");d[-1]=h;d[1]=e;b.target.flipX&&(k*=-1);b.target.flipY&&(k*=-1);0===g?(b.skewSign=-l*a*k,b[f]=d[-a]):(g=0<g?1:-1,b.skewSign=g,b[f]=d[g*l*k])},_skewObject:function(a, +b,c){var f=this._currentTransform,d=f.target,g=d.get("lockSkewingX"),h=d.get("lockSkewingY");if(g&&"x"===c||h&&"y"===c)return!1;var h=d.getCenterPoint(),e=d.toLocalPoint(new fabric.Point(a,b),"center","center")[c],l=d.toLocalPoint(new fabric.Point(f.lastX,f.lastY),"center","center")[c],g=d._getTransformedDimensions();this._changeSkewTransformOrigin(e-l,f,c);e=d.toLocalPoint(new fabric.Point(a,b),f.originX,f.originY)[c];h=d.translateToOriginPoint(h,f.originX,f.originY);c=this._setObjectSkew(e,f,c, +g);f.lastX=a;f.lastY=b;d.setPositionByOrigin(h,f.originX,f.originY);return c},_setObjectSkew:function(a,b,c,d){var f=b.target,g=b.skewSign,h,e,l,k;"x"===c?(b="y",l="Y",h="X",e=0,k=f.skewY):(b="x",l="X",h="Y",e=f.skewX,k=0);e=f._getTransformedDimensions(e,k);a=2*Math.abs(a)-e[c];2>=a?c=0:(c=g*Math.atan(a/f["scale"+h]/(e[b]/f["scale"+l])),c=fabric.util.radiansToDegrees(c));a=f["skew"+h]!==c;f.set("skew"+h,c);0!==f["skew"+l]&&(h=f._getTransformedDimensions(),c=d[b]/h[b]*f["scale"+l],f.set("scale"+l, +c));return a},_scaleObject:function(a,b,c){var f=this._currentTransform,d=f.target,g=d.get("lockScalingX"),h=d.get("lockScalingY"),e=d.get("lockScalingFlip");if(g&&h)return!1;var l=d.translateToOriginPoint(d.getCenterPoint(),f.originX,f.originY);a=d.toLocalPoint(new fabric.Point(a,b),f.originX,f.originY);b=d._getTransformedDimensions();this._setLocalMouse(a,f);c=this._setObjectScale(a,f,g,h,c,e,b);d.setPositionByOrigin(l,f.originX,f.originY);return c},_setObjectScale:function(a,b,c,d,g,h,e){var f= +b.target,l=!1,k=!1,m=!1,n,p,q,u;q=a.x*f.scaleX/e.x;u=a.y*f.scaleY/e.y;n=f.scaleX!==q;p=f.scaleY!==u;h&&0>=q&&q<f.scaleX&&(l=!0);h&&0>=u&&u<f.scaleY&&(k=!0);"equally"!==g||c||d?g?"x"!==g||f.get("lockUniScaling")?"y"!==g||f.get("lockUniScaling")||k||d||f.set("scaleY",u)&&(m=m||p):l||c||f.set("scaleX",q)&&(m=m||n):(l||c||f.set("scaleX",q)&&(m=m||n),k||d||f.set("scaleY",u)&&(m=m||p)):l||k||(m=this._scaleObjectEqually(a,f,b,e));b.newScaleX=q;b.newScaleY=u;l||k||this._flipObject(b,g);return m},_scaleObjectEqually:function(a, +b,c,d){var f=a.y+a.x;d=d.y*c.original.scaleY/b.scaleY+d.x*c.original.scaleX/b.scaleX;var g=a.y/Math.abs(a.y);c.newScaleX=a.x/Math.abs(a.x)*Math.abs(c.original.scaleX*f/d);c.newScaleY=g*Math.abs(c.original.scaleY*f/d);a=c.newScaleX!==b.scaleX||c.newScaleY!==b.scaleY;b.set("scaleX",c.newScaleX);b.set("scaleY",c.newScaleY);return a},_flipObject:function(a,b){0>a.newScaleX&&"y"!==b&&("left"===a.originX?a.originX="right":"right"===a.originX&&(a.originX="left"));0>a.newScaleY&&"x"!==b&&("top"===a.originY? +a.originY="bottom":"bottom"===a.originY&&(a.originY="top"))},_setLocalMouse:function(b,c){var d=c.target,f=this.getZoom(),d=d.padding/f;"right"===c.originX?b.x*=-1:"center"===c.originX&&(b.x=2*b.x*c.mouseXSign,0>b.x&&(c.mouseXSign=-c.mouseXSign));"bottom"===c.originY?b.y*=-1:"center"===c.originY&&(b.y=2*b.y*c.mouseYSign,0>b.y&&(c.mouseYSign=-c.mouseYSign));a(b.x)>d?b.x=0>b.x?b.x+d:b.x-d:b.x=0;a(b.y)>d?b.y=0>b.y?b.y+d:b.y-d:b.y=0},_rotateObject:function(a,b){var f=this._currentTransform;if(f.target.get("lockRotation"))return!1; +var g=c(f.ey-f.top,f.ex-f.left),h=c(b-f.top,a-f.left),g=d(h-g+f.theta),h=!0;if(0<f.target.snapAngle){var e=f.target.snapAngle,l=f.target.snapThreshold||e,t=Math.ceil(g/e)*e,e=Math.floor(g/e)*e;Math.abs(g-e)<l?g=e:Math.abs(g-t)<l&&(g=t)}0>g&&(g=360+g);g%=360;f.target.angle===g?h=!1:f.target.angle=g;return h},setCursor:function(a){this.upperCanvasEl.style.cursor=a},_resetObjectTransform:function(a){a.scaleX=1;a.scaleY=1;a.skewX=0;a.skewY=0;a.setAngle(0)},_drawSelection:function(b){var c=this._groupSelector, +d=c.left,f=c.top,h=a(d),e=a(f);this.selectionColor&&(b.fillStyle=this.selectionColor,b.fillRect(c.ex-(0<d?0:-d),c.ey-(0<f?0:-f),h,e));this.selectionLineWidth&&this.selectionBorderColor&&(b.lineWidth=this.selectionLineWidth,b.strokeStyle=this.selectionBorderColor,1<this.selectionDashArray.length&&!g?(d=c.ex+.5-(0<d?0:h),c=c.ey+.5-(0<f?0:e),b.beginPath(),fabric.util.drawDashedLine(b,d,c,d+h,c,this.selectionDashArray),fabric.util.drawDashedLine(b,d,c+e-1,d+h,c+e-1,this.selectionDashArray),fabric.util.drawDashedLine(b, +d,c,d,c+e,this.selectionDashArray),fabric.util.drawDashedLine(b,d+h-1,c,d+h-1,c+e,this.selectionDashArray),b.closePath(),b.stroke()):(fabric.Object.prototype._setLineDash.call(this,b,this.selectionDashArray),b.strokeRect(c.ex+.5-(0<d?0:h),c.ey+.5-(0<f?0:e),h,e)))},findTarget:function(a,b){if(!this.skipTargetFind){var c=this.getPointer(a,!0),d=this.getActiveGroup(),f=this.getActiveObject(),g,h;this.targets=[];if(d&&!b&&d===this._searchPossibleTargets([d],c))return this._fireOverOutEvents(d,a),d;if(f&& +f._findTargetCorner(c))return this._fireOverOutEvents(f,a),f;if(f&&f===this._searchPossibleTargets([f],c))if(this.preserveObjectStacking)g=f,h=this.targets,this.targets=[];else return this._fireOverOutEvents(f,a),f;c=this._searchPossibleTargets(this._objects,c);a[this.altSelectionKey]&&c&&g&&c!==g&&(c=g,this.targets=h);this._fireOverOutEvents(c,a);return c}},_fireOverOutEvents:function(a,b){var c,d,f=this._hoveredTarget;f!==a&&(c={e:b,target:a,previousTarget:this._hoveredTarget},d={e:b,target:this._hoveredTarget, +nextTarget:a},this._hoveredTarget=a);a?f!==a&&(f&&(this.fire("mouse:out",d),f.fire("mouseout",d)),this.fire("mouse:over",c),a.fire("mouseover",c)):f&&(this.fire("mouse:out",d),f.fire("mouseout",d))},_checkTarget:function(a,b){if(b&&b.visible&&b.evented&&this.containsPoint(null,b,a)&&(!this.perPixelTargetFind&&!b.perPixelTargetFind||b.isEditing||!this.isTargetTransparent(b,a.x,a.y)))return!0},_searchPossibleTargets:function(a,b){for(var c,d=a.length;d--;)if(this._checkTarget(b,a[d])){c=a[d];"group"=== +c.type&&c.subTargetCheck&&(d=this._normalizePointer(c,b),(d=this._searchPossibleTargets(c._objects,d))&&this.targets.push(d));break}return c},restorePointerVpt:function(a){return fabric.util.transformPoint(a,fabric.util.invertTransform(this.viewportTransform))},getPointer:function(a,b,c){c||(c=this.upperCanvasEl);a=e(a);var d=c.getBoundingClientRect(),f=d.width||0,g=d.height||0;f&&g||("top"in d&&"bottom"in d&&(g=Math.abs(d.top-d.bottom)),"right"in d&&"left"in d&&(f=Math.abs(d.right-d.left)));this.calcOffset(); +a.x-=this._offset.left;a.y-=this._offset.top;b||(a=this.restorePointerVpt(a));0===f||0===g?c=b=1:(b=c.width/f,c=c.height/g);return{x:a.x*b,y:a.y*c}},_createUpperCanvas:function(){var a=this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/,"");this.upperCanvasEl?this.upperCanvasEl.className="":this.upperCanvasEl=this._createCanvasElement();fabric.util.addClass(this.upperCanvasEl,"upper-canvas "+a);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(a){var b=this.getWidth()||a.width,c=this.getHeight()||a.height;fabric.util.setStyle(a,{position:"absolute",width:b+"px",height:c+"px",left:0,top:0,"touch-action":"none"});a.width=b;a.height=c;fabric.util.makeElementUnselectable(a)},_copyCanvasStyle:function(a,b){b.style.cssText=a.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl}, +_setActiveObject:function(a){var b=this._activeObject;if(b&&(b.set("active",!1),a!==b&&b.onDeselect&&"function"===typeof b.onDeselect))b.onDeselect();this._activeObject=a;a.set("active",!0)},setActiveObject:function(a,b){var c=this.getActiveObject();c&&c!==a&&c.fire("deselected",{e:b});this._setActiveObject(a);this.fire("object:selected",{target:a,e:b});a.fire("selected",{e:b});this.renderAll();return this},getActiveObject:function(){return this._activeObject},_onObjectRemoved:function(a){this.getActiveObject()=== +a&&(this.fire("before:selection:cleared",{target:a}),this._discardActiveObject(),this.fire("selection:cleared",{target:a}),a.fire("deselected"));this._hoveredTarget===a&&(this._hoveredTarget=null);this.callSuper("_onObjectRemoved",a)},_discardActiveObject:function(){var a=this._activeObject;if(a&&(a.set("active",!1),a.onDeselect&&"function"===typeof a.onDeselect))a.onDeselect();this._activeObject=null},discardActiveObject:function(a){var b=this._activeObject;b&&(this.fire("before:selection:cleared", +{target:b,e:a}),this._discardActiveObject(),this.fire("selection:cleared",{e:a}),b.fire("deselected",{e:a}));return this},_setActiveGroup:function(a){(this._activeGroup=a)&&a.set("active",!0)},setActiveGroup:function(a,b){this._setActiveGroup(a);a&&(this.fire("object:selected",{target:a,e:b}),a.fire("selected",{e:b}));return this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var a=this.getActiveGroup();a&&a.destroy();this.setActiveGroup(null)},discardActiveGroup:function(a){var b= +this.getActiveGroup();b&&(this.fire("before:selection:cleared",{e:a,target:b}),this._discardActiveGroup(),this.fire("selection:cleared",{e:a}));return this},deactivateAll:function(){for(var a=this.getObjects(),b=0,c=a.length,d;b<c;b++)(d=a[b])&&d.set("active",!1);this._discardActiveGroup();this._discardActiveObject();return this},deactivateAllWithDispatch:function(a){for(var b=this.getObjects(),c=0,d=b.length,f;c<d;c++)(f=b[c])&&f.set("active",!1);this.discardActiveGroup(a);this.discardActiveObject(a); +return this},dispose:function(){fabric.StaticCanvas.prototype.dispose.call(this);var a=this.wrapperEl;this.removeListeners();a.removeChild(this.upperCanvasEl);a.removeChild(this.lowerCanvasEl);delete this.upperCanvasEl;a.parentNode&&a.parentNode.replaceChild(this.lowerCanvasEl,this.wrapperEl);delete this.wrapperEl;return this},clear:function(){this.discardActiveGroup();this.discardActiveObject();this.clearContext(this.contextTop);return this.callSuper("clear")},drawControls:function(a){var b=this.getActiveGroup(); +b?b._renderControls(a):this._drawObjectsControls(a)},_drawObjectsControls:function(a){for(var b=0,c=this._objects.length;b<c;++b)this._objects[b]&&this._objects[b].active&&this._objects[b]._renderControls(a)},_toObject:function(a,b,c){var d=this._realizeGroupTransformOnObject(a);b=this.callSuper("_toObject",a,b,c);this._unwindGroupTransformOnObject(a,d);return b},_realizeGroupTransformOnObject:function(a){if(a.group&&a.group===this.getActiveGroup()){var b={};"angle flipX flipY left scaleX scaleY skewX skewY top".split(" ").forEach(function(c){b[c]= +a[c]});this.getActiveGroup().realizeTransform(a);return b}return null},_unwindGroupTransformOnObject:function(a,b){b&&a.set(b)},_setSVGObject:function(a,b,c){var d;d=this._realizeGroupTransformOnObject(b);this.callSuper("_setSVGObject",a,b,c);this._unwindGroupTransformOnObject(b,d)}});for(var h in fabric.StaticCanvas)"prototype"!==h&&(fabric.Canvas[h]=fabric.StaticCanvas[h]);fabric.isTouchSupported&&(fabric.Canvas.prototype._setCursorFromEvent=function(){});fabric.Element=fabric.Canvas})(); +(function(){function e(a,b){return"which"in a?a.which===b:a.button===b-1}var b={mt:0,tr:1,mr:2,br:3,mb:4,bl:5,ml:6,tl:7},d=fabric.util.addListener,c=fabric.util.removeListener;fabric.util.object.extend(fabric.Canvas.prototype,{cursorMap:"n-resize ne-resize e-resize se-resize s-resize sw-resize w-resize nw-resize".split(" "),_initEventListeners:function(){this.removeListeners();this._bindEvents();d(fabric.window,"resize",this._onResize);d(this.upperCanvasEl,"mousedown",this._onMouseDown);d(this.upperCanvasEl, +"mousemove",this._onMouseMove);d(this.upperCanvasEl,"mouseout",this._onMouseOut);d(this.upperCanvasEl,"mouseenter",this._onMouseEnter);d(this.upperCanvasEl,"wheel",this._onMouseWheel);d(this.upperCanvasEl,"contextmenu",this._onContextMenu);d(this.upperCanvasEl,"touchstart",this._onMouseDown,{passive:!1});d(this.upperCanvasEl,"touchmove",this._onMouseMove,{passive:!1});"undefined"!==typeof eventjs&&"add"in eventjs&&(eventjs.add(this.upperCanvasEl,"gesture",this._onGesture),eventjs.add(this.upperCanvasEl, +"drag",this._onDrag),eventjs.add(this.upperCanvasEl,"orientation",this._onOrientationChange),eventjs.add(this.upperCanvasEl,"shake",this._onShake),eventjs.add(this.upperCanvasEl,"longpress",this._onLongPress))},_bindEvents:function(){this.eventsBinded||(this._onMouseDown=this._onMouseDown.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseUp=this._onMouseUp.bind(this),this._onResize=this._onResize.bind(this),this._onGesture=this._onGesture.bind(this),this._onDrag=this._onDrag.bind(this), +this._onShake=this._onShake.bind(this),this._onLongPress=this._onLongPress.bind(this),this._onOrientationChange=this._onOrientationChange.bind(this),this._onMouseWheel=this._onMouseWheel.bind(this),this._onMouseOut=this._onMouseOut.bind(this),this._onMouseEnter=this._onMouseEnter.bind(this),this._onContextMenu=this._onContextMenu.bind(this),this.eventsBinded=!0)},removeListeners:function(){c(fabric.window,"resize",this._onResize);c(this.upperCanvasEl,"mousedown",this._onMouseDown);c(this.upperCanvasEl, +"mousemove",this._onMouseMove);c(this.upperCanvasEl,"mouseout",this._onMouseOut);c(this.upperCanvasEl,"mouseenter",this._onMouseEnter);c(this.upperCanvasEl,"wheel",this._onMouseWheel);c(this.upperCanvasEl,"contextmenu",this._onContextMenu);c(this.upperCanvasEl,"touchstart",this._onMouseDown);c(this.upperCanvasEl,"touchmove",this._onMouseMove);"undefined"!==typeof eventjs&&"remove"in eventjs&&(eventjs.remove(this.upperCanvasEl,"gesture",this._onGesture),eventjs.remove(this.upperCanvasEl,"drag",this._onDrag), +eventjs.remove(this.upperCanvasEl,"orientation",this._onOrientationChange),eventjs.remove(this.upperCanvasEl,"shake",this._onShake),eventjs.remove(this.upperCanvasEl,"longpress",this._onLongPress))},_onGesture:function(a,b){this.__onTransformGesture&&this.__onTransformGesture(a,b)},_onDrag:function(a,b){this.__onDrag&&this.__onDrag(a,b)},_onMouseWheel:function(a){this.__onMouseWheel(a)},_onMouseOut:function(a){var b=this._hoveredTarget;this.fire("mouse:out",{target:b,e:a});this._hoveredTarget=null; +b&&b.fire("mouseout",{e:a});this._iTextInstances&&this._iTextInstances.forEach(function(a){a.isEditing&&a.hiddenTextarea.focus()})},_onMouseEnter:function(a){this.findTarget(a)||(this.fire("mouse:over",{target:null,e:a}),this._hoveredTarget=null)},_onOrientationChange:function(a,b){this.__onOrientationChange&&this.__onOrientationChange(a,b)},_onShake:function(a,b){this.__onShake&&this.__onShake(a,b)},_onLongPress:function(a,b){this.__onLongPress&&this.__onLongPress(a,b)},_onContextMenu:function(a){this.stopContextMenu&& +(a.stopPropagation(),a.preventDefault());return!1},_onMouseDown:function(a){this.__onMouseDown(a);d(fabric.document,"touchend",this._onMouseUp,{passive:!1});d(fabric.document,"touchmove",this._onMouseMove,{passive:!1});c(this.upperCanvasEl,"mousemove",this._onMouseMove);c(this.upperCanvasEl,"touchmove",this._onMouseMove);"touchstart"===a.type?c(this.upperCanvasEl,"mousedown",this._onMouseDown):(d(fabric.document,"mouseup",this._onMouseUp),d(fabric.document,"mousemove",this._onMouseMove))},_onMouseUp:function(a){this.__onMouseUp(a); +c(fabric.document,"mouseup",this._onMouseUp);c(fabric.document,"touchend",this._onMouseUp);c(fabric.document,"mousemove",this._onMouseMove);c(fabric.document,"touchmove",this._onMouseMove);d(this.upperCanvasEl,"mousemove",this._onMouseMove);d(this.upperCanvasEl,"touchmove",this._onMouseMove,{passive:!1});if("touchend"===a.type){var b=this;setTimeout(function(){d(b.upperCanvasEl,"mousedown",b._onMouseDown)},400)}},_onMouseMove:function(a){!this.allowTouchScrolling&&a.preventDefault&&a.preventDefault(); +this.__onMouseMove(a)},_onResize:function(){this.calcOffset()},_shouldRender:function(a,b){var c=this.getActiveGroup()||this.getActiveObject();return c&&c.isEditing&&a===c?!1:!!(a&&(a.isMoving||a!==c)||!a&&c||!a&&!c&&!this._groupSelector||b&&this._previousPointer&&this.selection&&(b.x!==this._previousPointer.x||b.y!==this._previousPointer.y))},__onMouseUp:function(a){var b;if(e(a,3))this.fireRightClick&&this._handleEvent(a,"up",b,3);else if(e(a,2))this.fireMiddleClick&&this._handleEvent(a,"up",b, +2);else if(this.isDrawingMode&&this._isCurrentlyDrawing)this._onMouseUpInDrawingMode(a);else{b=!0;var c=this._currentTransform,d=this._groupSelector,d=!d||0===d.left&&0===d.top;c&&(this._finalizeCurrentTransform(a),b=!c.actionPerformed);b=b?this.findTarget(a,!0):c.target;c=this._shouldRender(b,this.getPointer(a));b||!d?this._maybeGroupObjects(a):this._currentTransform=this._groupSelector=null;b&&(b.isMoving=!1);this._setCursorFromEvent(a,b);this._handleEvent(a,"up",b?b:null,1,d);b&&(b.__corner=0); +c&&this.renderAll()}},_handleEvent:function(a,b,c,d,e){var f="undefined"===typeof c?this.findTarget(a):c;c=this.targets||[];a={e:a,target:f,subTargets:c,button:d||1,isClick:e||!1};this.fire("mouse:"+b,a);f&&f.fire("mouse"+b,a);for(d=0;d<c.length;d++)c[d].fire("mouse"+b,a)},_finalizeCurrentTransform:function(a){var b=this._currentTransform,c=b.target;c._scaling&&(c._scaling=!1);c.setCoords();this._restoreOriginXY(c);if(b.actionPerformed||this.stateful&&c.hasStateChanged())this.fire("object:modified", +{target:c,e:a}),c.fire("modified",{e:a})},_restoreOriginXY:function(a){if(this._previousOriginX&&this._previousOriginY){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX;a.originY=this._previousOriginY;a.left=b.x;a.top=b.y;this._previousOriginY=this._previousOriginX=null}},_onMouseDownInDrawingMode:function(a){this._isCurrentlyDrawing=!0;this.discardActiveObject(a).renderAll();this.clipTo&&fabric.util.clipContext(this,this.contextTop); +var b=this.getPointer(a);this.freeDrawingBrush.onMouseDown(b);this._handleEvent(a,"down")},_onMouseMoveInDrawingMode:function(a){if(this._isCurrentlyDrawing){var b=this.getPointer(a);this.freeDrawingBrush.onMouseMove(b)}this.setCursor(this.freeDrawingCursor);this._handleEvent(a,"move")},_onMouseUpInDrawingMode:function(a){this._isCurrentlyDrawing=!1;this.clipTo&&this.contextTop.restore();this.freeDrawingBrush.onMouseUp();this._handleEvent(a,"up")},__onMouseDown:function(a){var b=this.findTarget(a); +if(e(a,3))this.fireRightClick&&this._handleEvent(a,"down",b?b:null,3);else if(e(a,2))this.fireMiddleClick&&this._handleEvent(a,"down",b?b:null,2);else if(this.isDrawingMode)this._onMouseDownInDrawingMode(a);else if(!this._currentTransform){var c=this.getPointer(a,!0);this._previousPointer=c;var d=this._shouldRender(b,c),l=this._shouldGroup(a,b);this._shouldClearSelection(a,b)?this.deactivateAllWithDispatch(a):l&&(this._handleGrouping(a,b),b=this.getActiveGroup());!this.selection||b&&(b.selectable|| +b.isEditing)||(this._groupSelector={ex:c.x,ey:c.y,top:0,left:0});b&&(!b.selectable||!b.__corner&&l||(this._beforeTransform(a,b),this._setupCurrentTransform(a,b)),c=this.getActiveObject(),b!==this.getActiveGroup()&&b!==c&&(this.deactivateAll(),b.selectable&&(c&&c.fire("deselected",{e:a}),this.setActiveObject(b,a))));this._handleEvent(a,"down",b?b:null);d&&this.renderAll()}},_beforeTransform:function(a,b){this.stateful&&b.saveState();if(b._findTargetCorner(this.getPointer(a)))this.onBeforeScaleRotate(b)}, +_setOriginToCenter:function(a){this._previousOriginX=this._currentTransform.target.originX;this._previousOriginY=this._currentTransform.target.originY;var b=a.getCenterPoint();a.originX="center";a.originY="center";a.left=b.x;a.top=b.y;this._currentTransform.left=a.left;this._currentTransform.top=a.top},_setCenterToOrigin:function(a){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX;a.originY=this._previousOriginY;a.left= +b.x;a.top=b.y;this._previousOriginY=this._previousOriginX=null},__onMouseMove:function(a){var b,c;if(this.isDrawingMode)this._onMouseMoveInDrawingMode(a);else if(!("undefined"!==typeof a.touches&&1<a.touches.length)){var d=this._groupSelector;d?(c=this.getPointer(a,!0),d.left=c.x-d.ex,d.top=c.y-d.ey,this.renderTop()):this._currentTransform?this._transformObject(a):(b=this.findTarget(a),this._setCursorFromEvent(a,b));this._handleEvent(a,"move",b?b:null)}},__onMouseWheel:function(a){this._handleEvent(a, +"wheel")},_transformObject:function(a){var b=this.getPointer(a),c=this._currentTransform;c.reset=!1;c.target.isMoving=!0;c.shiftKey=a.shiftKey;c.altKey=a[this.centeredKey];this._beforeScaleTransform(a,c);this._performTransformAction(a,c,b);c.actionPerformed&&this.renderAll()},_performTransformAction:function(a,b,c){var d=c.x,g=c.y;c=b.target;var e=b.action;if("rotate"===e)(d=this._rotateObject(d,g))&&this._fire("rotating",c,a);else if("scale"===e)(d=this._onScale(a,b,d,g))&&this._fire("scaling",c, +a);else if("scaleX"===e)(d=this._scaleObject(d,g,"x"))&&this._fire("scaling",c,a);else if("scaleY"===e)(d=this._scaleObject(d,g,"y"))&&this._fire("scaling",c,a);else if("skewX"===e)(d=this._skewObject(d,g,"x"))&&this._fire("skewing",c,a);else if("skewY"===e)(d=this._skewObject(d,g,"y"))&&this._fire("skewing",c,a);else if(d=this._translateObject(d,g))this._fire("moving",c,a),this.setCursor(c.moveCursor||this.moveCursor);b.actionPerformed=b.actionPerformed||d},_fire:function(a,b,c){this.fire("object:"+ +a,{target:b,e:c});b.fire(a,{e:c})},_beforeScaleTransform:function(a,b){if("scale"===b.action||"scaleX"===b.action||"scaleY"===b.action){var c=this._shouldCenterTransform(b.target);if(c&&("center"!==b.originX||"center"!==b.originY)||!c&&"center"===b.originX&&"center"===b.originY)this._resetCurrentTransform(),b.reset=!0}},_onScale:function(a,b,c,d){if(!a[this.uniScaleKey]&&!this.uniScaleTransform||b.target.get("lockUniScaling"))return b.reset||"scale"!==b.currentAction||this._resetCurrentTransform(), +b.currentAction="scaleEqually",this._scaleObject(c,d,"equally");b.currentAction="scale";return this._scaleObject(c,d)},_setCursorFromEvent:function(a,b){if(!b)return this.setCursor(this.defaultCursor),!1;var c=b.hoverCursor||this.hoverCursor,d=this.getActiveGroup();(d=b._findTargetCorner&&(!d||!d.contains(b))&&b._findTargetCorner(this.getPointer(a,!0)))?this._setCornerCursor(d,b,a):this.setCursor(c);return!0},_setCornerCursor:function(a,c,d){if(a in b)this.setCursor(this._getRotatedCornerCursor(a, +c,d));else if("mtr"===a&&c.hasRotatingPoint)this.setCursor(this.rotationCursor);else return this.setCursor(this.defaultCursor),!1},_getRotatedCornerCursor:function(a,c,d){c=Math.round(c.getAngle()%360/45);0>c&&(c+=8);c+=b[a];d[this.altActionKey]&&0===b[a]%2&&(c+=2);return this.cursorMap[c%8]}})})(); +(function(){var e=Math.min,b=Math.max;fabric.util.object.extend(fabric.Canvas.prototype,{_shouldGroup:function(b,c){var a=this.getActiveObject();return b[this.selectionKey]&&c&&c.selectable&&(this.getActiveGroup()||a&&a!==c)&&this.selection},_handleGrouping:function(b,c){var a=this.getActiveGroup();if(c===a&&(c=this.findTarget(b,!0),!c))return;a?this._updateActiveGroup(c,b):this._createActiveGroup(c,b);this._activeGroup&&this._activeGroup.saveCoords()},_updateActiveGroup:function(b,c){var a=this.getActiveGroup(); +if(a.contains(b)){if(a.removeWithUpdate(b),b.set("active",!1),1===a.size()){this.discardActiveGroup(c);this.setActiveObject(a.item(0),c);return}}else a.addWithUpdate(b);this.fire("selection:created",{target:a,e:c});a.set("active",!0)},_createActiveGroup:function(b,c){if(this._activeObject&&b!==this._activeObject){var a=this._createGroup(b);a.addWithUpdate();this.setActiveGroup(a,c);this._activeObject=null;this.fire("selection:created",{target:a,e:c})}b.set("active",!0)},_createGroup:function(b){var c= +this.getObjects();b=c.indexOf(this._activeObject)<c.indexOf(b)?[this._activeObject,b]:[b,this._activeObject];this._activeObject.isEditing&&this._activeObject.exitEditing();return new fabric.Group(b,{canvas:this})},_groupSelectedObjects:function(b){var c=this._collectObjects();1===c.length?this.setActiveObject(c[0],b):1<c.length&&(c=new fabric.Group(c.reverse(),{canvas:this}),c.addWithUpdate(),this.setActiveGroup(c,b),c.saveCoords(),this.fire("selection:created",{target:c,e:b}),this.renderAll())}, +_collectObjects:function(){var d=[],c;c=this._groupSelector.ex;for(var a=this._groupSelector.ey,g=c+this._groupSelector.left,h=a+this._groupSelector.top,f=new fabric.Point(e(c,g),e(a,h)),l=new fabric.Point(b(c,g),b(a,h)),a=c===g&&a===h,g=this._objects.length;g--&&!((c=this._objects[g])&&c.selectable&&c.visible&&(c.intersectsWithRect(f,l)||c.isContainedWithinRect(f,l)||c.containsPoint(f)||c.containsPoint(l))&&(c.set("active",!0),d.push(c),a)););return d},_maybeGroupObjects:function(b){this.selection&& +this._groupSelector&&this._groupSelectedObjects(b);if(b=this.getActiveGroup())b.setObjectsCoords().setCoords(),b.isMoving=!1,this.setCursor(this.defaultCursor);this._currentTransform=this._groupSelector=null}})})(); +(function(){var e=fabric.StaticCanvas.supports("toDataURLWithQuality");fabric.util.object.extend(fabric.StaticCanvas.prototype,{toDataURL:function(b){b||(b={});return this.__toDataURLWithMultiplier(b.format||"png",b.quality||1,{left:b.left||0,top:b.top||0,width:b.width||0,height:b.height||0},b.multiplier||1)},__toDataURLWithMultiplier:function(b,d,c,a){var g=this.getWidth(),e=this.getHeight(),f=(c.width||this.getWidth())*a,l=(c.height||this.getHeight())*a,k=this.getZoom()*a,m=this.viewportTransform, +n=this.interactive;this.viewportTransform=[k,0,0,k,(m[4]-c.left)*a,(m[5]-c.top)*a];this.interactive&&(this.interactive=!1);g!==f||e!==l?this.setDimensions({width:f,height:l},{backstoreOnly:!0}):this.renderAll();b=this.__toDataURL(b,d,c);n&&(this.interactive=n);this.viewportTransform=m;this.setDimensions({width:g,height:e},{backstoreOnly:!0});return b},__toDataURL:function(b,d){var c=this.contextContainer.canvas;"jpg"===b&&(b="jpeg");return e?c.toDataURL("image/"+b,d):c.toDataURL("image/"+b)},toDataURLWithMultiplier:function(b, +d,c){return this.toDataURL({format:b,multiplier:d,quality:c})}})})(); +fabric.util.object.extend(fabric.StaticCanvas.prototype,{loadFromDatalessJSON:function(e,b,d){return this.loadFromJSON(e,b,d)},loadFromJSON:function(e,b,d){if(e){var c="string"===typeof e?JSON.parse(e):fabric.util.object.clone(e),a=this,g=this.renderOnAddRemove;this.renderOnAddRemove=!1;this._enlivenObjects(c.objects,function(d){a.clear();a._setBgOverlay(c,function(){d.forEach(function(b,c){a.insertAt(b,c)});a.renderOnAddRemove=g;delete c.objects;delete c.backgroundImage;delete c.overlayImage;delete c.background; +delete c.overlay;a._setOptions(c);a.renderAll();b&&b()})},d);return this}},_setBgOverlay:function(e,b){var d={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(e.backgroundImage||e.overlayImage||e.background||e.overlay){var c=function(){d.backgroundImage&&d.overlayImage&&d.backgroundColor&&d.overlayColor&&b&&b()};this.__setBgOverlay("backgroundImage",e.backgroundImage,d,c);this.__setBgOverlay("overlayImage",e.overlayImage,d,c);this.__setBgOverlay("backgroundColor",e.background, +d,c);this.__setBgOverlay("overlayColor",e.overlay,d,c)}else b&&b()},__setBgOverlay:function(e,b,d,c){var a=this;if(b)if("backgroundImage"===e||"overlayImage"===e)fabric.util.enlivenObjects([b],function(b){a[e]=b[0];d[e]=!0;c&&c()});else this["set"+fabric.util.string.capitalize(e,!0)](b,function(){d[e]=!0;c&&c()});else d[e]=!0,c&&c()},_enlivenObjects:function(e,b,d){e&&0!==e.length?fabric.util.enlivenObjects(e,function(c){b&&b(c)},null,d):b&&b([])},_toDataURL:function(e,b){this.clone(function(d){b(d.toDataURL(e))})}, +_toDataURLWithMultiplier:function(e,b,d){this.clone(function(c){d(c.toDataURLWithMultiplier(e,b))})},clone:function(e,b){var d=JSON.stringify(this.toJSON(b));this.cloneWithoutData(function(b){b.loadFromJSON(d,function(){e&&e(b)})})},cloneWithoutData:function(e){var b=fabric.document.createElement("canvas");b.width=this.getWidth();b.height=this.getHeight();var d=new fabric.Canvas(b);d.clipTo=this.clipTo;this.backgroundImage?(d.setBackgroundImage(this.backgroundImage.src,function(){d.renderAll();e&& +e(d)}),d.backgroundImageOpacity=this.backgroundImageOpacity,d.backgroundImageStretch=this.backgroundImageStretch):e&&e(d)}}); +(function(e){var b=e.fabric||(e.fabric={});e=b.util.object.extend;var d=b.util.object.clone,c=b.util.toFixed,a=b.util.string.capitalize,g=b.util.degreesToRadians,h=b.StaticCanvas.supports("setLineDash");b.Object||(b.Object=b.util.createClass(b.CommonMethods,{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,objectCaching:!b.isLikelyNode,statefullCache:!1,noScaleCache:!0,dirty:!0,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor skewX skewY fillRule".split(" "), +cacheProperties:"fill stroke strokeWidth strokeDashArray width height strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor".split(" "),initialize:function(a){a=a||{};this.setOptions(a)},_createCacheCanvas:function(){this._cacheProperties={};this._cacheCanvas=b.document.createElement("canvas");this._cacheContext=this._cacheCanvas.getContext("2d");this._updateCacheCanvas()},_limitCacheSize:function(a){var c=b.perfLimitSizeTotal,d=a.width,f=a.height,g=b.maxCacheSideLimit,e=b.minCacheSideLimit; +if(d<=g&&f<=g&&d*f<=c)return d<e&&(a.width=e),f<e&&(a.height=e),a;var h=b.util.limitDimsByArea(d/f,c),t=b.util.capValue,c=t(e,h.x,g),g=t(e,h.y,g);d>c&&(a.zoomX/=d/c,a.width=c,a.capped=!0);f>g&&(a.zoomY/=f/g,a.height=g,a.capped=!0);return a},_getCacheCanvasDimensions:function(){var a=this.canvas&&this.canvas.getZoom()||1,c=this.getObjectScaling(),d=this.canvas&&this.canvas._isRetinaScaling()?b.devicePixelRatio:1,g=this._getNonTransformedDimensions(),e=c.scaleX*a*d,a=c.scaleY*a*d;return{width:g.x*e+ +2,height:g.y*a+2,zoomX:e,zoomY:a,x:g.x,y:g.y}},_updateCacheCanvas:function(){if(this.noScaleCache&&this.canvas&&this.canvas._currentTransform){var a=this.canvas._currentTransform.action;if(this===this.canvas._currentTransform.target&&a.slice&&"scale"===a.slice(0,5))return!1}var a=this._cacheCanvas,c=this._limitCacheSize(this._getCacheCanvasDimensions()),d=b.minCacheSideLimit,g=c.width,e=c.height,h=c.zoomX,q=c.zoomY,t=g!==this.cacheWidth||e!==this.cacheHeight,r=this.zoomX!==h||this.zoomY!==q,v=0,A= +0,w=!1;if(t){var w=this._cacheCanvas.width,y=this._cacheCanvas.height,x=g>w||e>y,w=x||(g<.9*w||e<.9*y)&&w>d&&y>d;x&&!c.capped&&(g>d||e>d)&&(v=.1*g,A=.1*e)}return t||r?(w?(a.width=Math.ceil(g+v),a.height=Math.ceil(e+A)):(this._cacheContext.setTransform(1,0,0,1,0,0),this._cacheContext.clearRect(0,0,a.width,a.height)),d=c.x*h/2,c=c.y*q/2,this.cacheTranslationX=Math.round(a.width/2-d)+d,this.cacheTranslationY=Math.round(a.height/2-c)+c,this.cacheWidth=g,this.cacheHeight=e,this._cacheContext.translate(this.cacheTranslationX, +this.cacheTranslationY),this._cacheContext.scale(h,q),this.zoomX=h,this.zoomY=q,!0):!1},setOptions:function(a){this._setOptions(a);this._initGradient(a.fill,"fill");this._initGradient(a.stroke,"stroke");this._initClipping(a);this._initPattern(a.fill,"fill");this._initPattern(a.stroke,"stroke")},transform:function(a,b){this.group&&!this.group._transformDone&&this.group===this.canvas._activeGroup&&this.group.transform(a);var c=b?this._getLeftTopCoords():this.getCenterPoint();a.translate(c.x,c.y);this.angle&& +a.rotate(g(this.angle));a.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1));this.skewX&&a.transform(1,0,Math.tan(g(this.skewX)),1,0,0);this.skewY&&a.transform(1,Math.tan(g(this.skewY)),0,1,0,0)},toObject:function(a){var d=b.Object.NUM_FRACTION_DIGITS,d={type:this.type,originX:this.originX,originY:this.originY,left:c(this.left,d),top:c(this.top,d),width:c(this.width,d),height:c(this.height,d),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject? +this.stroke.toObject():this.stroke,strokeWidth:c(this.strokeWidth,d),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:c(this.strokeMiterLimit,d),scaleX:c(this.scaleX,d),scaleY:c(this.scaleY,d),angle:c(this.getAngle(),d),flipX:this.flipX,flipY:this.flipY,opacity:c(this.opacity,d),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():null,skewX:c(this.skewX,d),skewY:c(this.skewY,d)};b.util.populateWithProperties(this,d,a);this.includeDefaultValues||(d=this._removeDefaultValues(d));return d},toDatalessObject:function(a){return this.toObject(a)},_removeDefaultValues:function(a){var c=b.util.getKlass(a.type).prototype; +c.stateProperties.forEach(function(b){a[b]===c[b]&&delete a[b];"[object Array]"===Object.prototype.toString.call(a[b])&&"[object Array]"===Object.prototype.toString.call(c[b])&&0===a[b].length&&0===c[b].length&&delete a[b]});return a},toString:function(){return"#<fabric."+a(this.type)+">"},getObjectScaling:function(){var a=this.scaleX,b=this.scaleY;if(this.group)var c=this.group.getObjectScaling(),a=a*c.scaleX,b=b*c.scaleY;return{scaleX:a,scaleY:b}},_set:function(a,c){var d=this[a]!==c;if("scaleX"=== +a||"scaleY"===a)c=this._constrainScale(c);"scaleX"===a&&0>c?(this.flipX=!this.flipX,c*=-1):"scaleY"===a&&0>c?(this.flipY=!this.flipY,c*=-1):"shadow"!==a||!c||c instanceof b.Shadow?"dirty"===a&&this.group&&this.group.set("dirty",c):c=new b.Shadow(c);this[a]=c;d&&-1<this.cacheProperties.indexOf(a)&&(this.group&&this.group.set("dirty",!0),this.dirty=!0);d&&this.group&&-1<this.stateProperties.indexOf(a)&&this.group.set("dirty",!0);if("width"===a||"height"===a)this.minScaleLimit=Math.min(.1,1/Math.max(this.width, +this.height));return this},setOnGroup:function(){},setSourcePath:function(a){this.sourcePath=a;return this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:b.iMatrix.concat()},isNotVisible:function(){return 0===this.opacity||0===this.width&&0===this.height||!this.visible},render:function(a,c){this.isNotVisible()||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(a.save(),this._setupCompositeOperation(a),this.drawSelectionBackground(a), +c||this.transform(a),this._setOpacity(a),this._setShadow(a),this.transformMatrix&&a.transform.apply(a,this.transformMatrix),this.clipTo&&b.util.clipContext(this,a),this.shouldCache(c)?(this._cacheCanvas||this._createCacheCanvas(),this.isCacheDirty(c)&&(this.statefullCache&&this.saveState({propertySet:"cacheProperties"}),this.drawObject(this._cacheContext,c),this.dirty=!1),this.drawCacheOnCanvas(a)):(this._removeCacheCanvas(),this.dirty=!1,this.drawObject(a,c),c&&this.objectCaching&&this.statefullCache&& +this.saveState({propertySet:"cacheProperties"})),this.clipTo&&a.restore(),a.restore())},_removeCacheCanvas:function(){this._cacheCanvas=null;this.cacheHeight=this.cacheWidth=0},needsItsOwnCache:function(){return!1},shouldCache:function(a){return!a&&this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching())},willDrawShadow:function(){return!!this.shadow&&(0!==this.shadow.offsetX||0!==this.shadow.offsetY)},drawObject:function(a,b){this._renderBackground(a);this._setStrokeStyles(a); +this._setFillStyles(a);this._render(a,b)},drawCacheOnCanvas:function(a){a.scale(1/this.zoomX,1/this.zoomY);a.drawImage(this._cacheCanvas,-this.cacheTranslationX,-this.cacheTranslationY)},isCacheDirty:function(a){if(this.isNotVisible())return!1;if(this._cacheCanvas&&!a&&this._updateCacheCanvas())return!0;if(this.dirty||this.statefullCache&&this.hasStateChanged("cacheProperties")){if(this._cacheCanvas&&!a){a=this.cacheWidth/this.zoomX;var b=this.cacheHeight/this.zoomY;this._cacheContext.clearRect(-a/ +2,-b/2,a,b)}return!0}return!1},_renderBackground:function(a){if(this.backgroundColor){var b=this._getNonTransformedDimensions();a.fillStyle=this.backgroundColor;a.fillRect(-b.x/2,-b.y/2,b.x,b.y);this._removeShadow(a)}},_setOpacity:function(a){a.globalAlpha*=this.opacity},_setStrokeStyles:function(a){this.stroke&&(a.lineWidth=this.strokeWidth,a.lineCap=this.strokeLineCap,a.lineJoin=this.strokeLineJoin,a.miterLimit=this.strokeMiterLimit,a.strokeStyle=this.stroke.toLive?this.stroke.toLive(a,this):this.stroke)}, +_setFillStyles:function(a){this.fill&&(a.fillStyle=this.fill.toLive?this.fill.toLive(a,this):this.fill)},_setLineDash:function(a,b,c){b&&(1&b.length&&b.push.apply(b,b),h?a.setLineDash(b):c&&c(a))},_renderControls:function(a){if(this.active&&(!this.group||this.group===this.canvas.getActiveGroup())){var c=this.getViewportTransform(),d=this.calcTransformMatrix(),d=b.util.multiplyTransformMatrices(c,d),c=b.util.qrDecompose(d);a.save();a.translate(c.translateX,c.translateY);a.lineWidth=1*this.borderScaleFactor; +this.group||(a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1);this.group&&this.group===this.canvas.getActiveGroup()?(a.rotate(g(c.angle)),this.drawBordersInGroup(a,c)):(a.rotate(g(this.angle)),this.drawBorders(a));this.drawControls(a);a.restore()}},_setShadow:function(a){if(this.shadow){var c=this.canvas&&this.canvas.viewportTransform[0]||1,d=this.canvas&&this.canvas.viewportTransform[3]||1,f=this.getObjectScaling();this.canvas&&this.canvas._isRetinaScaling()&&(c*=b.devicePixelRatio,d*= +b.devicePixelRatio);a.shadowColor=this.shadow.color;a.shadowBlur=this.shadow.blur*(c+d)*(f.scaleX+f.scaleY)/4;a.shadowOffsetX=this.shadow.offsetX*c*f.scaleX;a.shadowOffsetY=this.shadow.offsetY*d*f.scaleY}},_removeShadow:function(a){this.shadow&&(a.shadowColor="",a.shadowBlur=a.shadowOffsetX=a.shadowOffsetY=0)},_applyPatternGradientTransform:function(a,b){if(b.toLive){var c=b.gradientTransform||b.patternTransform;c&&a.transform.apply(a,c);a.translate(-this.width/2+b.offsetX||0,-this.height/2+b.offsetY|| +0)}},_renderFill:function(a){this.fill&&(a.save(),this._applyPatternGradientTransform(a,this.fill),"evenodd"===this.fillRule?a.fill("evenodd"):a.fill(),a.restore())},_renderStroke:function(a){this.stroke&&0!==this.strokeWidth&&(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(a),a.save(),this._setLineDash(a,this.strokeDashArray,this._renderDashedStroke),this._applyPatternGradientTransform(a,this.stroke),a.stroke(),a.restore())},clone:function(a,c){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(c), +a):new b.Object(this.toObject(c))},cloneAsImage:function(a,c){var d=this.toDataURL(c);b.util.loadImage(d,function(c){a&&a(new b.Image(c))});return this},toDataURL:function(a){a||(a={});var c=b.util.createCanvasElement(),d=this.getBoundingRect();c.width=d.width;c.height=d.height;b.util.wrapElement(c,"div");c=new b.StaticCanvas(c,{enableRetinaScaling:a.enableRetinaScaling});"jpg"===a.format&&(a.format="jpeg");"jpeg"===a.format&&(c.backgroundColor="#fff");d={active:this.get("active"),left:this.getLeft(), +top:this.getTop()};this.set("active",!1);this.setPositionByOrigin(new b.Point(c.getWidth()/2,c.getHeight()/2),"center","center");var f=this.canvas;c.add(this);a=c.toDataURL(a);this.set(d).setCoords();this.canvas=f;c.dispose();return a},isType:function(a){return this.type===a},complexity:function(){return 1},toJSON:function(a){return this.toObject(a)},setGradient:function(a,c){c||(c={});var d={colorStops:[]};d.type=c.type||(c.r1||c.r2?"radial":"linear");d.coords={x1:c.x1,y1:c.y1,x2:c.x2,y2:c.y2};if(c.r1|| +c.r2)d.coords.r1=c.r1,d.coords.r2=c.r2;d.gradientTransform=c.gradientTransform;b.Gradient.prototype.addColorStop.call(d,c.colorStops);return this.set(a,b.Gradient.forObject(this,d))},setPatternFill:function(a){return this.set("fill",new b.Pattern(a))},setShadow:function(a){return this.set("shadow",a?new b.Shadow(a):null)},setColor:function(a){this.set("fill",a);return this},setAngle:function(a){var b=("center"!==this.originX||"center"!==this.originY)&&this.centeredRotation;b&&this._setOriginToCenter(); +this.set("angle",a);b&&this._resetOrigin();return this},centerH:function(){this.canvas&&this.canvas.centerObjectH(this);return this},viewportCenterH:function(){this.canvas&&this.canvas.viewportCenterObjectH(this);return this},centerV:function(){this.canvas&&this.canvas.centerObjectV(this);return this},viewportCenterV:function(){this.canvas&&this.canvas.viewportCenterObjectV(this);return this},center:function(){this.canvas&&this.canvas.centerObject(this);return this},viewportCenter:function(){this.canvas&& +this.canvas.viewportCenterObject(this);return this},remove:function(){this.canvas&&(this.group&&this.group===this.canvas._activeGroup&&this.group.remove(this),this.canvas.remove(this));return this},getLocalPointer:function(a,c){c=c||this.canvas.getPointer(a);var d=new b.Point(c.x,c.y),f=this._getLeftTopCoords();this.angle&&(d=b.util.rotatePoint(d,f,g(-this.angle)));return{x:d.x-f.x,y:d.y-f.y}},_setupCompositeOperation:function(a){this.globalCompositeOperation&&(a.globalCompositeOperation=this.globalCompositeOperation)}}), +b.util.createAccessors(b.Object),b.Object.prototype.rotate=b.Object.prototype.setAngle,e(b.Object.prototype,b.Observable),b.Object.NUM_FRACTION_DIGITS=2,b.Object._fromObject=function(a,c,g,e,h){var f=b[a];c=d(c,!0);if(e)b.util.enlivenPatterns([c.fill,c.stroke],function(a){"undefined"!==typeof a[0]&&(c.fill=a[0]);"undefined"!==typeof a[1]&&(c.stroke=a[1]);a=h?new f(c[h],c):new f(c);g&&g(a)});else return a=h?new f(c[h],c):new f(c),g&&g(a),a},b.Object.__uid=0)})("undefined"!==typeof exports?exports: +this); +(function(){var e=fabric.util.degreesToRadians,b={left:-.5,center:0,right:.5},d={top:-.5,center:0,bottom:.5};fabric.util.object.extend(fabric.Object.prototype,{translateToGivenOrigin:function(c,a,g,e,f){var h=c.x,k=c.y;a="string"===typeof a?b[a]:a-.5;e="string"===typeof e?b[e]:e-.5;a=e-a;g="string"===typeof g?d[g]:g-.5;f="string"===typeof f?d[f]:f-.5;g=f-g;if(a||g)k=this._getTransformedDimensions(),h=c.x+a*k.x,k=c.y+g*k.y;return new fabric.Point(h,k)},translateToCenterPoint:function(b,a,d){a=this.translateToGivenOrigin(b, +a,d,"center","center");return this.angle?fabric.util.rotatePoint(a,b,e(this.angle)):a},translateToOriginPoint:function(b,a,d){a=this.translateToGivenOrigin(b,"center","center",a,d);return this.angle?fabric.util.rotatePoint(a,b,e(this.angle)):a},getCenterPoint:function(){var b=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(b,this.originX,this.originY)},getPointByOrigin:function(b,a){var c=this.getCenterPoint();return this.translateToOriginPoint(c,b,a)},toLocalPoint:function(b, +a,d){var c=this.getCenterPoint();a="undefined"!==typeof a&&"undefined"!==typeof d?this.translateToGivenOrigin(c,"center","center",a,d):new fabric.Point(this.left,this.top);b=new fabric.Point(b.x,b.y);this.angle&&(b=fabric.util.rotatePoint(b,c,-e(this.angle)));return b.subtractEquals(a)},setPositionByOrigin:function(b,a,d){b=this.translateToCenterPoint(b,a,d);b=this.translateToOriginPoint(b,this.originX,this.originY);this.set("left",b.x);this.set("top",b.y)},adjustPosition:function(c){var a=e(this.angle), +d=this.getWidth(),h=Math.cos(a)*d,a=Math.sin(a)*d,f,d="string"===typeof this.originX?b[this.originX]:this.originX-.5;f="string"===typeof c?b[c]:c-.5;this.left+=h*(f-d);this.top+=a*(f-d);this.setCoords();this.originX=c},_setOriginToCenter:function(){this._originalOriginX=this.originX;this._originalOriginY=this.originY;var b=this.getCenterPoint();this.originY=this.originX="center";this.left=b.x;this.top=b.y},_resetOrigin:function(){var b=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX, +this._originalOriginY);this.originX=this._originalOriginX;this.originY=this._originalOriginY;this.left=b.x;this.top=b.y;this._originalOriginY=this._originalOriginX=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),"left","top")},onDeselect:function(){}})})(); +(function(){var e=fabric.util.degreesToRadians,b=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,aCoords:null,getCoords:function(b,c){this.oCoords||this.setCoords();var a=b?this.aCoords:this.oCoords,a=c?this.calcCoords(b):a;return[new fabric.Point(a.tl.x,a.tl.y),new fabric.Point(a.tr.x,a.tr.y),new fabric.Point(a.br.x,a.br.y),new fabric.Point(a.bl.x,a.bl.y)]},intersectsWithRect:function(b,c,a,e){a=this.getCoords(a,e);return"Intersection"===fabric.Intersection.intersectPolygonRectangle(a, +b,c).status},intersectsWithObject:function(b,c,a){return"Intersection"===fabric.Intersection.intersectPolygonPolygon(this.getCoords(c,a),b.getCoords(c,a)).status||b.isContainedWithinObject(this,c,a)||this.isContainedWithinObject(b,c,a)},isContainedWithinObject:function(b,c,a){var d=this.getCoords(c,a),e=0;for(c=b._getImageLines(a?b.calcCoords(c):c?b.aCoords:b.oCoords);4>e;e++)if(!b.containsPoint(d[e],c))return!1;return!0},isContainedWithinRect:function(b,c,a,e){a=this.getBoundingRect(a,e);return a.left>= +b.x&&a.left+a.width<=c.x&&a.top>=b.y&&a.top+a.height<=c.y},containsPoint:function(b,c,a,e){c=c||this._getImageLines(e?this.calcCoords(a):a?this.aCoords:this.oCoords);b=this._findCrossPoints(b,c);return 0!==b&&1===b%2},isOnScreen:function(b){if(!this.canvas)return!1;var c=this.canvas.vptCoords.tl,a=this.canvas.vptCoords.br;b=this.getCoords(!0,b);for(var d,e=0;4>e;e++)if(d=b[e],d.x<=a.x&&d.x>=c.x&&d.y<=a.y&&d.y>=c.y)return!0;return this.intersectsWithRect(c,a,!0)||this.containsPoint({x:(c.x+a.x)/2, +y:(c.y+a.y)/2},null,!0)?!0:!1},_getImageLines:function(b){return{topline:{o:b.tl,d:b.tr},rightline:{o:b.tr,d:b.br},bottomline:{o:b.br,d:b.bl},leftline:{o:b.bl,d:b.tl}}},_findCrossPoints:function(b,c){var a,d,e,f=0,l;for(l in c)if(e=c[l],!(e.o.y<b.y&&e.d.y<b.y||e.o.y>=b.y&&e.d.y>=b.y)&&(e.o.x===e.d.x&&e.o.x>=b.x?a=e.o.x:(a=(e.d.y-e.o.y)/(e.d.x-e.o.x),d=b.y-0*b.x,e=e.o.y-a*e.o.x,a=-(d-e)/(0-a)),a>=b.x&&(f+=1),2===f))break;return f},getBoundingRectWidth:function(){return this.getBoundingRect().width}, +getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(b,c){var a=this.getCoords(b,c);return fabric.util.makeBoundingBoxFromPoints(a)},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(b){return Math.abs(b)<this.minScaleLimit?0>b?-this.minScaleLimit:this.minScaleLimit:b!==b?this.minScaleLimit:0===b?1E-4:b},scale:function(b){b=this._constrainScale(b);0>b&&(this.flipX= +!this.flipX,this.flipY=!this.flipY,b*=-1);this.scaleY=this.scaleX=b;return this.setCoords()},scaleToWidth:function(b){var c=this.getBoundingRect().width/this.getWidth();return this.scale(b/this.width/c)},scaleToHeight:function(b){var c=this.getBoundingRect().height/this.getHeight();return this.scale(b/this.height/c)},calcCoords:function(b){var c=e(this.angle),a=this.getViewportTransform(),d=b?this._getTransformedDimensions():this._calculateCurrentDimensions(),h=d.x,f=d.y,d=Math.sin(c),l=Math.cos(c), +k=0<h?Math.atan(f/h):0,m=h/Math.cos(k)/2,n=Math.cos(k+c)*m,c=Math.sin(k+c)*m,k=this.getCenterPoint(),k=b?k:fabric.util.transformPoint(k,a),a=new fabric.Point(k.x-n,k.y-c),h=new fabric.Point(a.x+h*l,a.y+h*d),f=new fabric.Point(a.x-f*d,a.y+f*l),n=new fabric.Point(k.x+n,k.y+c);if(!b)var p=new fabric.Point((a.x+f.x)/2,(a.y+f.y)/2),q=new fabric.Point((h.x+a.x)/2,(h.y+a.y)/2),t=new fabric.Point((n.x+h.x)/2,(n.y+h.y)/2),r=new fabric.Point((n.x+f.x)/2,(n.y+f.y)/2),v=new fabric.Point(q.x+d*this.rotatingPointOffset, +q.y-l*this.rotatingPointOffset);k={tl:a,tr:h,br:n,bl:f};b||(k.ml=p,k.mt=q,k.mr=t,k.mb=r,k.mtr=v);return k},setCoords:function(b,c){this.oCoords=this.calcCoords(b);c||(this.aCoords=this.calcCoords(!0));b||this._setCornerCoords&&this._setCornerCoords();return this},_calcRotateMatrix:function(){if(this.angle){var b=e(this.angle),c=Math.cos(b),b=Math.sin(b);if(6.123233995736766E-17===c||-1.8369701987210297E-16===c)c=0;return[c,b,-b,c,0,0]}return fabric.iMatrix.concat()},calcTransformMatrix:function(d){var c= +this.getCenterPoint(),a=[1,0,0,1,c.x,c.y],c=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0),a=this.group&&!d?b(this.group.calcTransformMatrix(),a):a;this.angle&&(d=this._calcRotateMatrix(),a=b(a,d));return a=b(a,c)},_calcDimensionsTransformMatrix:function(d,c,a){a=[this.scaleX*(a&&this.flipX?-1:1),0,0,this.scaleY*(a&&this.flipY?-1:1),0,0];d&&(d=[1,0,Math.tan(e(d)),1],a=b(a,d,!0));c&&(d=[1,Math.tan(e(c)),0,1],a=b(a,d,!0));return a},_getNonTransformedDimensions:function(){var b=this.strokeWidth; +return{x:this.width+b,y:this.height+b}},_getTransformedDimensions:function(b,c){"undefined"===typeof b&&(b=this.skewX);"undefined"===typeof c&&(c=this.skewY);for(var a=this._getNonTransformedDimensions(),d=a.x/2,a=a.y/2,d=[{x:-d,y:-a},{x:d,y:-a},{x:-d,y:a},{x:d,y:a}],e=this._calcDimensionsTransformMatrix(b,c,!1),a=0;a<d.length;a++)d[a]=fabric.util.transformPoint(d[a],e);d=fabric.util.makeBoundingBoxFromPoints(d);return{x:d.width,y:d.height}},_calculateCurrentDimensions:function(){var b=this.getViewportTransform(), +c=this._getTransformedDimensions();return fabric.util.transformPoint(c,b,!0).scalarAdd(2*this.padding)}})})(); +fabric.util.object.extend(fabric.Object.prototype,{sendToBack:function(){this.group?fabric.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this);return this},bringToFront:function(){this.group?fabric.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this);return this},sendBackwards:function(e){this.group?fabric.StaticCanvas.prototype.sendBackwards.call(this.group,this,e):this.canvas.sendBackwards(this,e);return this},bringForward:function(e){this.group? +fabric.StaticCanvas.prototype.bringForward.call(this.group,this,e):this.canvas.bringForward(this,e);return this},moveTo:function(e){this.group?fabric.StaticCanvas.prototype.moveTo.call(this.group,this,e):this.canvas.moveTo(this,e);return this}}); +(function(){function e(b,d){if(d){if(d.toLive)return b+": url(#SVGID_"+d.id+"); ";var c=new fabric.Color(d),a=b+": "+c.toRgb()+"; ",c=c.getAlpha();1!==c&&(a+=b+"-opacity: "+c.toString()+"; ");return a}return b+": none; "}fabric.util.object.extend(fabric.Object.prototype,{getSvgStyles:function(b){var d=this.fillRule,c=this.strokeWidth?this.strokeWidth:"0",a=this.strokeDashArray?this.strokeDashArray.join(" "):"none",g=this.strokeLineCap?this.strokeLineCap:"butt",h=this.strokeLineJoin?this.strokeLineJoin: +"miter",f=this.strokeMiterLimit?this.strokeMiterLimit:"4",l="undefined"!==typeof this.opacity?this.opacity:"1",k=this.visible?"":" visibility: hidden;";b=b?"":this.getSvgFilter();var m=e("fill",this.fill);return[e("stroke",this.stroke),"stroke-width: ",c,"; stroke-dasharray: ",a,"; stroke-linecap: ",g,"; stroke-linejoin: ",h,"; stroke-miterlimit: ",f,"; ",m,"fill-rule: ",d,"; opacity: ",l,";",b,k].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 b=fabric.util.toFixed,d=this.getAngle(),c=this.getSkewX()%360,a=this.getSkewY()%360,e=this.getCenterPoint(),h=fabric.Object.NUM_FRACTION_DIGITS,e="path-group"===this.type?"":"translate("+b(e.x,h)+" "+b(e.y,h)+")",d=0!==d?" rotate("+b(d,h)+")":"",f=1===this.scaleX&&1===this.scaleY?"":" scale("+b(this.scaleX,h)+" "+b(this.scaleY,h)+")",c=0!==c?" skewX("+b(c,h)+")":"",b=0!==a?" skewY("+b(a,h)+ +")":"",a="path-group"===this.type?this.width:0,h="path-group"===this.type?this.height:0;return[e,d,f,this.flipX?" matrix(-1 0 0 1 "+a+" 0) ":"",this.flipY?" matrix(1 0 0 -1 0 "+h+")":"",c,b].join("")},getSvgTransformMatrix:function(){return this.transformMatrix?" matrix("+this.transformMatrix.join(" ")+") ":""},_createBaseSVGMarkup:function(){var b=[];this.fill&&this.fill.toLive&&b.push(this.fill.toSVG(this,!1));this.stroke&&this.stroke.toLive&&b.push(this.stroke.toSVG(this,!1));this.shadow&&b.push(this.shadow.toSVG(this)); +return b}})})(); +(function(){function e(b,a,e){var c={};e.forEach(function(a){c[a]=b[a]});d(b[a],c,!0)}function b(c,a,d){if(c===a)return!0;if(Array.isArray(c)){if(c.length!==a.length)return!1;d=0;for(var e=c.length;d<e;d++)if(!b(c[d],a[d]))return!1;return!0}if(c&&"object"===typeof c){var f=Object.keys(c),g;if(!d&&f.length!==Object.keys(a).length)return!1;d=0;for(e=f.length;d<e;d++)if(g=f[d],!b(c[g],a[g]))return!1;return!0}}var d=fabric.util.object.extend;fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(c){c= +c||"stateProperties";var a="_"+c;return Object.keys(this[a]).length<this[c].length?!0:!b(this[a],this,!0)},saveState:function(b){var a=b&&b.propertySet||"stateProperties",c="_"+a;if(!this[c])return this.setupState(b);e(this,c,this[a]);b&&b.stateProperties&&e(this,c,b.stateProperties);return this},setupState:function(b){b=b||{};var a=b.propertySet||"stateProperties";b.propertySet=a;this["_"+a]={};this.saveState(b);return this}})})(); +(function(){var e=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(b){if(!this.hasControls||!this.active)return!1;var d=b.x;b=b.y;var c;this.__corner=0;for(var a in this.oCoords)if(this.isControlVisible(a)&&("mtr"!==a||this.hasRotatingPoint)&&(!this.get("lockUniScaling")||"mt"!==a&&"mr"!==a&&"mb"!==a&&"ml"!==a)&&(c=this._getImageLines(this.oCoords[a].corner),c=this._findCrossPoints({x:d,y:b},c),0!==c&&1===c%2))return this.__corner= +a;return!1},_setCornerCoords:function(){var b=this.oCoords,d=e(45-this.angle),c=.707106*this.cornerSize,a=c*Math.cos(d),d=c*Math.sin(d),g,h;for(h in b)c=b[h].x,g=b[h].y,b[h].corner={tl:{x:c-d,y:g-a},tr:{x:c+a,y:g-d},bl:{x:c-a,y:g+d},br:{x:c+d,y:g+a}}},drawSelectionBackground:function(b){if(!this.selectionBackgroundColor||this.group||!this.active||this.canvas&&!this.canvas.interactive)return this;b.save();var d=this.getCenterPoint(),c=this._calculateCurrentDimensions(),a=this.canvas.viewportTransform; +b.translate(d.x,d.y);b.scale(1/a[0],1/a[3]);b.rotate(e(this.angle));b.fillStyle=this.selectionBackgroundColor;b.fillRect(-c.x/2,-c.y/2,c.x,c.y);b.restore();return this},drawBorders:function(b){if(!this.hasBorders)return this;var d=this._calculateCurrentDimensions(),c=1/this.borderScaleFactor,a=d.x+c,d=d.y+c;b.save();b.strokeStyle=this.borderColor;this._setLineDash(b,this.borderDashArray,null);b.strokeRect(-a/2,-d/2,a,d);this.hasRotatingPoint&&this.isControlVisible("mtr")&&!this.get("lockRotation")&& +this.hasControls&&(a=-d/2,b.beginPath(),b.moveTo(0,a),b.lineTo(0,a-this.rotatingPointOffset),b.closePath(),b.stroke());b.restore();return this},drawBordersInGroup:function(b,d){if(!this.hasBorders)return this;var c=this._getNonTransformedDimensions(),a=fabric.util.customTransformMatrix(d.scaleX,d.scaleY,d.skewX),a=fabric.util.transformPoint(c,a),e=1/this.borderScaleFactor,c=a.x+e,a=a.y+e;b.save();this._setLineDash(b,this.borderDashArray,null);b.strokeStyle=this.borderColor;b.strokeRect(-c/2,-a/2, +c,a);b.restore();return this},drawControls:function(b){if(!this.hasControls)return this;var d=this._calculateCurrentDimensions(),c=d.x,d=d.y,a=this.cornerSize,e=-(c+a)/2,a=-(d+a)/2,h=this.transparentCorners?"stroke":"fill";b.save();b.strokeStyle=b.fillStyle=this.cornerColor;this.transparentCorners||(b.strokeStyle=this.cornerStrokeColor);this._setLineDash(b,this.cornerDashArray,null);this._drawControl("tl",b,h,e,a);this._drawControl("tr",b,h,e+c,a);this._drawControl("bl",b,h,e,a+d);this._drawControl("br", +b,h,e+c,a+d);this.get("lockUniScaling")||(this._drawControl("mt",b,h,e+c/2,a),this._drawControl("mb",b,h,e+c/2,a+d),this._drawControl("mr",b,h,e+c,a+d/2),this._drawControl("ml",b,h,e,a+d/2));this.hasRotatingPoint&&this._drawControl("mtr",b,h,e+c/2,a-this.rotatingPointOffset);b.restore();return this},_drawControl:function(b,d,c,a,e){if(this.isControlVisible(b)){b=this.cornerSize;var g=!this.transparentCorners&&this.cornerStrokeColor;switch(this.cornerStyle){case "circle":d.beginPath();d.arc(a+b/2, +e+b/2,b/2,0,2*Math.PI,!1);d[c]();g&&d.stroke();break;default:"undefined"!==typeof G_vmlCanvasManager||this.transparentCorners||d.clearRect(a,e,b,b),d[c+"Rect"](a,e,b,b),g&&d.strokeRect(a,e,b,b)}}},isControlVisible:function(b){return this._getControlsVisibility()[b]},setControlVisible:function(b,d){this._getControlsVisibility()[b]=d;return this},setControlsVisibility:function(b){b||(b={});for(var d in b)this.setControlVisible(d,b[d]);return this},_getControlsVisibility:function(){this._controlsVisibility|| +(this._controlsVisibility={tl:!0,tr:!0,br:!0,bl:!0,ml:!0,mt:!0,mr:!0,mb:!0,mtr:!0});return this._controlsVisibility}})})(); +fabric.util.object.extend(fabric.StaticCanvas.prototype,{FX_DURATION:500,fxCenterObjectH:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("left"),endValue:this.getCenter().left,duration:this.FX_DURATION,onChange:function(b){e.set("left",b);g.renderAll();a()},onComplete:function(){e.setCoords();c()}});return this},fxCenterObjectV:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("top"), +endValue:this.getCenter().top,duration:this.FX_DURATION,onChange:function(b){e.set("top",b);g.renderAll();a()},onComplete:function(){e.setCoords();c()}});return this},fxRemove:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("opacity"),endValue:0,duration:this.FX_DURATION,onStart:function(){e.set("active",!1)},onChange:function(b){e.set("opacity",b);g.renderAll();a()},onComplete:function(){g.remove(e);c()}});return this}}); +fabric.util.object.extend(fabric.Object.prototype,{animate:function(){if(arguments[0]&&"object"===typeof arguments[0]){var e=[],b,d;for(b in arguments[0])e.push(b);for(var c=0,a=e.length;c<a;c++)b=e[c],d=c!==a-1,this._animate(b,arguments[0][b],arguments[1],d)}else this._animate.apply(this,arguments);return this},_animate:function(e,b,d,c){var a=this,g;b=b.toString();d=d?fabric.util.object.clone(d):{};~e.indexOf(".")&&(g=e.split("."));var h=g?this.get(g[0])[g[1]]:this.get(e);"from"in d||(d.from=h); +b=~b.indexOf("=")?h+parseFloat(b.replace("=","")):parseFloat(b);fabric.util.animate({startValue:d.from,endValue:b,byValue:d.by,easing:d.easing,duration:d.duration,abort:d.abort&&function(){return d.abort.call(a)},onChange:function(b,h,k){g?a[g[0]][g[1]]=b:a.set(e,b);c||d.onChange&&d.onChange(b,h,k)},onComplete:function(b,e,g){c||(a.setCoords(),d.onComplete&&d.onComplete(b,e,g))}})}}); +(function(e){function b(a,b){var c=a.origin,d=a.axis1,f=a.axis2,e=a.dimension,g=b.nearest,h=b.center,l=b.farthest;return function(){switch(this.get(c)){case g:return Math.min(this.get(d),this.get(f));case h:return Math.min(this.get(d),this.get(f))+.5*this.get(e);case l:return Math.max(this.get(d),this.get(f))}}}var d=e.fabric||(e.fabric={}),c=d.util.object.extend,a=d.util.object.clone,g={x1:1,x2:1,y1:1,y2:1},h=d.StaticCanvas.supports("setLineDash");d.Line?d.warn("fabric.Line is already defined"): +(d.Line=d.util.createClass(d.Object,{type:"line",x1:0,y1:0,x2:0,y2:0,cacheProperties:d.Object.prototype.cacheProperties.concat("x1","x2","y1","y2"),initialize:function(a,b){a||(a=[0,0,0,0]);this.callSuper("initialize",b);this.set("x1",a[0]);this.set("y1",a[1]);this.set("x2",a[2]);this.set("y2",a[3]);this._setWidthHeight(b)},_setWidthHeight:function(a){a||(a={});this.width=Math.abs(this.x2-this.x1);this.height=Math.abs(this.y2-this.y1);this.left="left"in a?a.left:this._getLeftToOriginX();this.top= +"top"in a?a.top:this._getTopToOriginY()},_set:function(a,b){this.callSuper("_set",a,b);"undefined"!==typeof g[a]&&this._setWidthHeight();return this},_getLeftToOriginX:b({origin:"originX",axis1:"x1",axis2:"x2",dimension:"width"},{nearest:"left",center:"center",farthest:"right"}),_getTopToOriginY:b({origin:"originY",axis1:"y1",axis2:"y2",dimension:"height"},{nearest:"top",center:"center",farthest:"bottom"}),_render:function(a,b){a.beginPath();if(b){var c=this.getCenterPoint(),d=this.strokeWidth/2; +a.translate(c.x-("butt"===this.strokeLineCap&&0===this.height?0:d),c.y-("butt"===this.strokeLineCap&&0===this.width?0:d))}if(!this.strokeDashArray||this.strokeDashArray&&h)c=this.calcLinePoints(),a.moveTo(c.x1,c.y1),a.lineTo(c.x2,c.y2);a.lineWidth=this.strokeWidth;c=a.strokeStyle;a.strokeStyle=this.stroke||a.fillStyle;this.stroke&&this._renderStroke(a);a.strokeStyle=c},_renderDashedStroke:function(a){var b=this.calcLinePoints();a.beginPath();d.util.drawDashedLine(a,b.x1,b.y1,b.x2,b.y2,this.strokeDashArray); +a.closePath()},toObject:function(a){return c(this.callSuper("toObject",a),this.calcLinePoints())},_getNonTransformedDimensions:function(){var a=this.callSuper("_getNonTransformedDimensions");"butt"===this.strokeLineCap&&(0===this.width&&(a.y-=this.strokeWidth),0===this.height&&(a.x-=this.strokeWidth));return a},calcLinePoints:function(){var a=this.x1<=this.x2?-1:1,b=this.y1<=this.y2?-1:1;return{x1:a*this.width*.5,x2:a*this.width*-.5,y1:b*this.height*.5,y2:b*this.height*-.5}},toSVG:function(a){var b= +this._createBaseSVGMarkup(),c={x1:this.x1,x2:this.x2,y1:this.y1,y2:this.y2};this.group&&"path-group"===this.group.type||(c=this.calcLinePoints());b.push("<line ",this.getSvgId(),'x1="',c.x1,'" y1="',c.y1,'" x2="',c.x2,'" y2="',c.y2,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")}}),d.Line.ATTRIBUTE_NAMES=d.SHARED_ATTRIBUTES.concat(["x1","y1","x2","y2"]),d.Line.fromElement=function(a,b){b=b||{};var f=d.parseAttributes(a, +d.Line.ATTRIBUTE_NAMES),e=[f.x1||0,f.y1||0,f.x2||0,f.y2||0];b.originX="left";b.originY="top";return new d.Line(e,c(f,b))},d.Line.fromObject=function(b,c,e){var f=a(b,!0);f.points=[b.x1,b.y1,b.x2,b.y2];(b=d.Object._fromObject("Line",f,function(a){delete a.points;c&&c(a)},e,"points"))&&delete b.points;return b})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=Math.PI,c=b.util.object.extend;b.Circle?b.warn("fabric.Circle is already defined."):(b.Circle=b.util.createClass(b.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*d,cacheProperties:b.Object.prototype.cacheProperties.concat("radius"),initialize:function(a){this.callSuper("initialize",a);this.set("radius",a&&a.radius||0)},_set:function(a,b){this.callSuper("_set",a,b);"radius"===a&&this.setRadius(b);return this},toObject:function(a){return this.callSuper("toObject", +["radius","startAngle","endAngle"].concat(a))},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=0,f=0,e=(this.endAngle-this.startAngle)%(2*d);0===e?(this.group&&"path-group"===this.group.type&&(c=this.left+this.radius,f=this.top+this.radius),b.push("<circle ",this.getSvgId(),'cx="'+c+'" cy="'+f+'" ','r="',this.radius,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n')):b.push('<path d="M '+Math.cos(this.startAngle)*this.radius+" "+ +Math.sin(this.startAngle)*this.radius," A "+this.radius+" "+this.radius," 0 ",+(e>d?1:0)+" 1"," "+Math.cos(this.endAngle)*this.radius+" "+Math.sin(this.endAngle)*this.radius,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")},_render:function(a,b){a.beginPath();a.arc(b?this.left+this.radius:0,b?this.top+this.radius:0,this.radius,this.startAngle,this.endAngle,!1);this._renderFill(a);this._renderStroke(a)}, +getRadiusX:function(){return this.get("radius")*this.get("scaleX")},getRadiusY:function(){return this.get("radius")*this.get("scaleY")},setRadius:function(a){this.radius=a;return this.set("width",2*a).set("height",2*a)}}),b.Circle.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["cx","cy","r"]),b.Circle.fromElement=function(a,d){d||(d={});var e=b.parseAttributes(a,b.Circle.ATTRIBUTE_NAMES);if(!("radius"in e&&0<=e.radius))throw Error("value of `r` attribute is required and can not be negative");e.left= +e.left||0;e.top=e.top||0;e=new b.Circle(c(e,d));e.left-=e.radius;e.top-=e.radius;return e},b.Circle.fromObject=function(a,c,d){return b.Object._fromObject("Circle",a,c,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});b.Triangle?b.warn("fabric.Triangle is already defined"):(b.Triangle=b.util.createClass(b.Object,{type:"triangle",initialize:function(b){this.callSuper("initialize",b);this.set("width",b&&b.width||100).set("height",b&&b.height||100)},_render:function(b){var c=this.width/2,a=this.height/2;b.beginPath();b.moveTo(-c,a);b.lineTo(0,-a);b.lineTo(c,a);b.closePath();this._renderFill(b);this._renderStroke(b)},_renderDashedStroke:function(d){var c=this.width/2,a=this.height/ +2;d.beginPath();b.util.drawDashedLine(d,-c,a,0,-a,this.strokeDashArray);b.util.drawDashedLine(d,0,-a,c,a,this.strokeDashArray);b.util.drawDashedLine(d,c,a,-c,a,this.strokeDashArray);d.closePath()},toSVG:function(b){var c=this._createBaseSVGMarkup(),a=this.width/2,d=this.height/2,a=[-a+" "+d,"0 "+-d,a+" "+d].join();c.push("<polygon ",this.getSvgId(),'points="',a,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),'"/>');return b?b(c.join("")):c.join("")}}),b.Triangle.fromObject= +function(d,c,a){return b.Object._fromObject("Triangle",d,c,a)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=2*Math.PI,c=b.util.object.extend;b.Ellipse?b.warn("fabric.Ellipse is already defined."):(b.Ellipse=b.util.createClass(b.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:b.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(a){this.callSuper("initialize",a);this.set("rx",a&&a.rx||0);this.set("ry",a&&a.ry||0)},_set:function(a,b){this.callSuper("_set",a,b);switch(a){case "rx":this.rx=b;this.set("width",2*b);break;case "ry":this.ry=b,this.set("height", +2*b)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(a){return this.callSuper("toObject",["rx","ry"].concat(a))},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=0,d=0;this.group&&"path-group"===this.group.type&&(c=this.left+this.rx,d=this.top+this.ry);b.push("<ellipse ",this.getSvgId(),'cx="',c,'" cy="',d,'" ','rx="',this.rx,'" ry="',this.ry,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(), +this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")},_render:function(a,b){a.beginPath();a.save();a.transform(1,0,0,this.ry/this.rx,0,0);a.arc(b?this.left+this.rx:0,b?(this.top+this.ry)*this.rx/this.ry:0,this.rx,0,d,!1);a.restore();this._renderFill(a);this._renderStroke(a)}}),b.Ellipse.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["cx","cy","rx","ry"]),b.Ellipse.fromElement=function(a,d){d||(d={});var e=b.parseAttributes(a,b.Ellipse.ATTRIBUTE_NAMES);e.left=e.left||0;e.top=e.top|| +0;e=new b.Ellipse(c(e,d));e.top-=e.ry;e.left-=e.rx;return e},b.Ellipse.fromObject=function(a,c,d){return b.Object._fromObject("Ellipse",a,c,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.Rect?b.warn("fabric.Rect is already defined"):(b.Rect=b.util.createClass(b.Object,{stateProperties:b.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:b.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(b){this.callSuper("initialize",b);this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(b,a){if(1=== +this.width&&1===this.height)b.fillRect(-.5,-.5,1,1);else{var c=this.rx?Math.min(this.rx,this.width/2):0,d=this.ry?Math.min(this.ry,this.height/2):0,f=this.width,e=this.height,k=a?this.left:-this.width/2,m=a?this.top:-this.height/2,n=0!==c||0!==d;b.beginPath();b.moveTo(k+c,m);b.lineTo(k+f-c,m);n&&b.bezierCurveTo(k+f-.4477152502*c,m,k+f,m+.4477152502*d,k+f,m+d);b.lineTo(k+f,m+e-d);n&&b.bezierCurveTo(k+f,m+e-.4477152502*d,k+f-.4477152502*c,m+e,k+f-c,m+e);b.lineTo(k+c,m+e);n&&b.bezierCurveTo(k+.4477152502* +c,m+e,k,m+e-.4477152502*d,k,m+e-d);b.lineTo(k,m+d);n&&b.bezierCurveTo(k,m+.4477152502*d,k+.4477152502*c,m,k+c,m);b.closePath();this._renderFill(b);this._renderStroke(b)}},_renderDashedStroke:function(c){var a=-this.width/2,d=-this.height/2,e=this.width,f=this.height;c.beginPath();b.util.drawDashedLine(c,a,d,a+e,d,this.strokeDashArray);b.util.drawDashedLine(c,a+e,d,a+e,d+f,this.strokeDashArray);b.util.drawDashedLine(c,a+e,d+f,a,d+f,this.strokeDashArray);b.util.drawDashedLine(c,a,d+f,a,d,this.strokeDashArray); +c.closePath()},toObject:function(b){return this.callSuper("toObject",["rx","ry"].concat(b))},toSVG:function(b){var a=this._createBaseSVGMarkup(),c=this.left,d=this.top;this.group&&"path-group"===this.group.type||(c=-this.width/2,d=-this.height/2);a.push("<rect ",this.getSvgId(),'x="',c,'" y="',d,'" rx="',this.get("rx"),'" ry="',this.get("ry"),'" width="',this.width,'" height="',this.height,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'"/>\n'); +return b?b(a.join("")):a.join("")}}),b.Rect.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),b.Rect.fromElement=function(c,a){if(!c)return null;a=a||{};var e=b.parseAttributes(c,b.Rect.ATTRIBUTE_NAMES);e.left=e.left||0;e.top=e.top||0;e=new b.Rect(d(a?b.util.object.clone(a):{},e));e.visible=e.visible&&0<e.width&&0<e.height;return e},b.Rect.fromObject=function(c,a,d){return b.Object._fromObject("Rect",c,a,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend,c=b.util.array.min,a=b.util.array.max,g=b.util.toFixed,h=b.Object.NUM_FRACTION_DIGITS;b.Polyline?b.warn("fabric.Polyline is already defined"):(b.Polyline=b.util.createClass(b.Object,{type:"polyline",points:null,minX:0,minY:0,cacheProperties:b.Object.prototype.cacheProperties.concat("points"),initialize:function(a,b){b=b||{};this.points=a||[];this.callSuper("initialize",b);this._calcDimensions();"top"in b||(this.top=this.minY);"left"in +b||(this.left=this.minX);this.pathOffset={x:this.minX+this.width/2,y:this.minY+this.height/2}},_calcDimensions:function(){var b=this.points,d=c(b,"x"),e=c(b,"y"),g=a(b,"x"),b=a(b,"y");this.width=g-d||0;this.height=b-e||0;this.minX=d||0;this.minY=e||0},toObject:function(a){return d(this.callSuper("toObject",a),{points:this.points.concat()})},toSVG:function(a){var b=[],c=0,d=0,f=this._createBaseSVGMarkup();this.group&&"path-group"===this.group.type||(c=this.pathOffset.x,d=this.pathOffset.y);for(var e= +0,q=this.points.length;e<q;e++)b.push(g(this.points[e].x-c,h),",",g(this.points[e].y-d,h)," ");f.push("<",this.type," ",this.getSvgId(),'points="',b.join(""),'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n');return a?a(f.join("")):f.join("")},commonRender:function(a,b){var c,d=this.points.length,f=b?0:this.pathOffset.x,e=b?0:this.pathOffset.y;if(!d||isNaN(this.points[d-1].y))return!1;a.beginPath();a.moveTo(this.points[0].x-f,this.points[0].y- +e);for(var g=0;g<d;g++)c=this.points[g],a.lineTo(c.x-f,c.y-e);return!0},_render:function(a,b){this.commonRender(a,b)&&(this._renderFill(a),this._renderStroke(a))},_renderDashedStroke:function(a){var c,d;a.beginPath();for(var f=0,e=this.points.length;f<e;f++)c=this.points[f],d=this.points[f+1]||c,b.util.drawDashedLine(a,c.x,c.y,d.x,d.y,this.strokeDashArray)},complexity:function(){return this.get("points").length}}),b.Polyline.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polyline.fromElement=function(a, +c){if(!a)return null;c||(c={});var d=b.parsePointsAttribute(a.getAttribute("points")),f=b.parseAttributes(a,b.Polyline.ATTRIBUTE_NAMES);return new b.Polyline(d,b.util.object.extend(f,c))},b.Polyline.fromObject=function(a,c,d){return b.Object._fromObject("Polyline",a,c,d,"points")})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.Polygon?b.warn("fabric.Polygon is already defined"):(b.Polygon=b.util.createClass(b.Polyline,{type:"polygon",_render:function(b,a){this.commonRender(b,a)&&(b.closePath(),this._renderFill(b),this._renderStroke(b))},_renderDashedStroke:function(b){this.callSuper("_renderDashedStroke",b);b.closePath()}}),b.Polygon.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polygon.fromElement=function(c,a){if(!c)return null;a||(a={});var e=b.parsePointsAttribute(c.getAttribute("points")), +h=b.parseAttributes(c,b.Polygon.ATTRIBUTE_NAMES);return new b.Polygon(e,d(h,a))},b.Polygon.fromObject=function(c,a,d){return b.Object._fromObject("Polygon",c,a,d,"points")})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.array.min,c=b.util.array.max,a=b.util.object.extend,g=Object.prototype.toString,h=b.util.drawArc,f={m:2,l:2,h:1,v:1,c:6,s:4,q:4,t:2,a:7},l={m:"l",M:"L"};b.Path?b.warn("fabric.Path is already defined"):(b.Path=b.util.createClass(b.Object,{type:"path",path:null,minX:0,minY:0,cacheProperties:b.Object.prototype.cacheProperties.concat("path","fillRule"),stateProperties:b.Object.prototype.stateProperties.concat("path"),initialize:function(a,b){b=b||{}; +this.callSuper("initialize",b);a||(a=[]);var c="[object Array]"===g.call(a);if(this.path=c?a:a.match&&a.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi))c||(this.path=this._parsePath()),this._setPositionDimensions(b)},_setPositionDimensions:function(a){var b=this._parseDimensions();this.minX=b.left;this.minY=b.top;this.width=b.width;this.height=b.height;"undefined"===typeof a.left&&(this.left=b.left+("center"===this.originX?this.width/2:"right"===this.originX?this.width:0));"undefined"===typeof a.top&&(this.top= +b.top+("center"===this.originY?this.height/2:"bottom"===this.originY?this.height:0));this.pathOffset=this.pathOffset||{x:this.minX+this.width/2,y:this.minY+this.height/2}},_renderPathCommands:function(a){var b,c=null,d=0,f=0,e=0,g=0,l=0,k=0,w,y,x=-this.pathOffset.x,u=-this.pathOffset.y;this.group&&"path-group"===this.group.type&&(u=x=0);a.beginPath();for(var C=0,D=this.path.length;C<D;++C){b=this.path[C];switch(b[0]){case "l":e+=b[1];g+=b[2];a.lineTo(e+x,g+u);break;case "L":e=b[1];g=b[2];a.lineTo(e+ +x,g+u);break;case "h":e+=b[1];a.lineTo(e+x,g+u);break;case "H":e=b[1];a.lineTo(e+x,g+u);break;case "v":g+=b[1];a.lineTo(e+x,g+u);break;case "V":g=b[1];a.lineTo(e+x,g+u);break;case "m":e+=b[1];g+=b[2];d=e;f=g;a.moveTo(e+x,g+u);break;case "M":e=b[1];g=b[2];d=e;f=g;a.moveTo(e+x,g+u);break;case "c":w=e+b[5];y=g+b[6];l=e+b[3];k=g+b[4];a.bezierCurveTo(e+b[1]+x,g+b[2]+u,l+x,k+u,w+x,y+u);e=w;g=y;break;case "C":e=b[5];g=b[6];l=b[3];k=b[4];a.bezierCurveTo(b[1]+x,b[2]+u,l+x,k+u,e+x,g+u);break;case "s":w=e+b[3]; +y=g+b[4];null===c[0].match(/[CcSs]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.bezierCurveTo(l+x,k+u,e+b[1]+x,g+b[2]+u,w+x,y+u);l=e+b[1];k=g+b[2];e=w;g=y;break;case "S":w=b[3];y=b[4];null===c[0].match(/[CcSs]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.bezierCurveTo(l+x,k+u,b[1]+x,b[2]+u,w+x,y+u);e=w;g=y;l=b[1];k=b[2];break;case "q":w=e+b[3];y=g+b[4];l=e+b[1];k=g+b[2];a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "Q":w=b[3];y=b[4];a.quadraticCurveTo(b[1]+x,b[2]+u,w+x,y+u);e=w;g=y;l=b[1];k=b[2];break;case "t":w= +e+b[1];y=g+b[2];null===c[0].match(/[QqTt]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "T":w=b[1];y=b[2];null===c[0].match(/[QqTt]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "a":h(a,e+x,g+u,[b[1],b[2],b[3],b[4],b[5],b[6]+e+x,b[7]+g+u]);e+=b[6];g+=b[7];break;case "A":h(a,e+x,g+u,[b[1],b[2],b[3],b[4],b[5],b[6]+x,b[7]+u]);e=b[6];g=b[7];break;case "z":case "Z":e=d,g=f,a.closePath()}c=b}},_render:function(a){this._renderPathCommands(a); +this._renderFill(a);this._renderStroke(a)},toString:function(){return"#<fabric.Path ("+this.complexity()+'): { "top": '+this.top+', "left": '+this.left+" }>"},toObject:function(b){return a(this.callSuper("toObject",["sourcePath","pathOffset"].concat(b)),{path:this.path.map(function(a){return a.slice()}),top:this.top,left:this.left})},toDatalessObject:function(a){a=this.toObject(a);this.sourcePath&&(a.path=this.sourcePath);delete a.sourcePath;return a},toSVG:function(a){for(var b=[],c=this._createBaseSVGMarkup(), +d="",f=0,e=this.path.length;f<e;f++)b.push(this.path[f].join(" "));b=b.join(" ");this.group&&"path-group"===this.group.type||(d=" translate("+-this.pathOffset.x+", "+-this.pathOffset.y+") ");c.push("<path ",this.getSvgId(),'d="',b,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),d,this.getSvgTransformMatrix(),'" stroke-linecap="round" ',"/>\n");return a?a(c.join("")):c.join("")},complexity:function(){return this.path.length},_parsePath:function(){for(var a=[],b=[],c,d,e=/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig, +g,h=0,v=this.path.length;h<v;h++){c=this.path[h];g=c.slice(1).trim();for(b.length=0;d=e.exec(g);)b.push(d[0]);c=[c.charAt(0)];g=0;for(var A=b.length;g<A;g++)d=parseFloat(b[g]),isNaN(d)||c.push(d);d=c[0];g=f[d.toLowerCase()];A=l[d]||d;if(c.length-1>g)for(var w=1,y=c.length;w<y;w+=g)a.push([d].concat(c.slice(w,w+g))),d=A;else a.push(c)}return a},_parseDimensions:function(){for(var a=[],f=[],e,g=null,h=0,l=0,r=0,v=0,A=0,w=0,y,x,u,C=0,D=this.path.length;C<D;++C){e=this.path[C];switch(e[0]){case "l":r+= +e[1];v+=e[2];u=[];break;case "L":r=e[1];v=e[2];u=[];break;case "h":r+=e[1];u=[];break;case "H":r=e[1];u=[];break;case "v":v+=e[1];u=[];break;case "V":v=e[1];u=[];break;case "m":r+=e[1];v+=e[2];h=r;l=v;u=[];break;case "M":r=e[1];v=e[2];h=r;l=v;u=[];break;case "c":y=r+e[5];x=v+e[6];A=r+e[3];w=v+e[4];u=b.util.getBoundsOfCurve(r,v,r+e[1],v+e[2],A,w,y,x);r=y;v=x;break;case "C":A=e[3];w=e[4];u=b.util.getBoundsOfCurve(r,v,e[1],e[2],A,w,e[5],e[6]);r=e[5];v=e[6];break;case "s":y=r+e[3];x=v+e[4];null===g[0].match(/[CcSs]/)? +(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,r+e[1],v+e[2],y,x);A=r+e[1];w=v+e[2];r=y;v=x;break;case "S":y=e[3];x=e[4];null===g[0].match(/[CcSs]/)?(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,e[1],e[2],y,x);r=y;v=x;A=e[1];w=e[2];break;case "q":y=r+e[3];x=v+e[4];A=r+e[1];w=v+e[2];u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "Q":A=e[1];w=e[2];u=b.util.getBoundsOfCurve(r,v,A,w,A,w,e[3],e[4]);r=e[3];v=e[4];break;case "t":y=r+e[1];x=v+e[2];null===g[0].match(/[QqTt]/)? +(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "T":y=e[1];x=e[2];null===g[0].match(/[QqTt]/)?(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "a":u=b.util.getBoundsOfArc(r,v,e[1],e[2],e[3],e[4],e[5],e[6]+r,e[7]+v);r+=e[6];v+=e[7];break;case "A":u=b.util.getBoundsOfArc(r,v,e[1],e[2],e[3],e[4],e[5],e[6],e[7]);r=e[6];v=e[7];break;case "z":case "Z":r=h,v=l}g=e;u.forEach(function(b){a.push(b.x);f.push(b.y)});a.push(r); +f.push(v)}e=d(a)||0;g=d(f)||0;h=c(a)||0;l=c(f)||0;return{left:e,top:g,width:h-e,height:l-g}}}),b.Path.fromObject=function(a,c,d){var e;if("string"===typeof a.path)b.loadSVGFromURL(a.path,function(b){var d=a.path;e=b[0];delete a.path;e.setOptions(a);e.setSourcePath(d);c&&c(e)});else return b.Object._fromObject("Path",a,c,d,"path")},b.Path.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["d"]),b.Path.fromElement=function(c,d,e){c=b.parseAttributes(c,b.Path.ATTRIBUTE_NAMES);d&&d(new b.Path(c.d,a(c,e)))}, +b.Path.async=!0)})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.PathGroup?b.warn("fabric.PathGroup is already defined"):(b.PathGroup=b.util.createClass(b.Object,{type:"path-group",fill:"",cacheProperties:[],initialize:function(b,a){a=a||{};this.paths=b||[];for(var c=this.paths.length;c--;)this.paths[c].group=this;a.toBeParsed&&(this.parseDimensionsFromPaths(a),delete a.toBeParsed);this.setOptions(a);this.setCoords()},parseDimensionsFromPaths:function(c){for(var a,d,e=[],f=[],l,k=this.paths.length;k--;){a= +this.paths[k];d=a.height+a.strokeWidth;l=a.width+a.strokeWidth;a=[{x:a.left,y:a.top},{x:a.left+l,y:a.top},{x:a.left,y:a.top+d},{x:a.left+l,y:a.top+d}];l=this.paths[k].transformMatrix;for(var m=0;m<a.length;m++)d=a[m],l&&(d=b.util.transformPoint(d,l,!1)),e.push(d.x),f.push(d.y)}c.width=Math.max.apply(null,e);c.height=Math.max.apply(null,f)},drawObject:function(b){b.save();b.translate(-this.width/2,-this.height/2);for(var a=0,c=this.paths.length;a<c;++a)this.paths[a].render(b,!0);b.restore()},shouldCache:function(){var b= +this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching());if(this.caching=b)for(var a=0,d=this.paths.length;a<d;a++)if(this.paths[a].willDrawShadow())return this.caching=!1;return b},willDrawShadow:function(){if(this.shadow)return!0;for(var b=0,a=this.paths.length;b<a;b++)if(this.paths[b].willDrawShadow())return!0;return!1},isCaching:function(){return this.caching||this.group&&this.group.isCaching()},isCacheDirty:function(){if(this.callSuper("isCacheDirty"))return!0;if(!this.statefullCache)return!1; +for(var b=0,a=this.paths.length;b<a;b++)if(this.paths[b].isCacheDirty(!0))return this._cacheCanvas&&(b=this.cacheWidth/this.zoomX,a=this.cacheHeight/this.zoomY,this._cacheContext.clearRect(-b/2,-a/2,b,a)),!0;return!1},_set:function(b,a){if("fill"===b&&a&&this.isSameColor())for(var c=this.paths.length;c--;)this.paths[c]._set(b,a);return this.callSuper("_set",b,a)},toObject:function(b){var a=this.paths.map(function(a){var c=a.includeDefaultValues;a.includeDefaultValues=a.group.includeDefaultValues; +var d=a.toObject(b);a.includeDefaultValues=c;return d});return d(this.callSuper("toObject",["sourcePath"].concat(b)),{paths:a})},toDatalessObject:function(b){b=this.toObject(b);this.sourcePath&&(b.paths=this.sourcePath);return b},toSVG:function(b){var a=this.getObjects(),c=this.getPointByOrigin("left","top"),d="translate("+c.x+" "+c.y+")",c=this._createBaseSVGMarkup();c.push("<g ",this.getSvgId(),'style="',this.getSvgStyles(),'" ','transform="',this.getSvgTransformMatrix(),d,this.getSvgTransform(), +'" ',">\n");for(var d=0,e=a.length;d<e;d++)c.push("\t",a[d].toSVG(b));c.push("</g>\n");return b?b(c.join("")):c.join("")},toString:function(){return"#<fabric.PathGroup ("+this.complexity()+"): { top: "+this.top+", left: "+this.left+" }>"},isSameColor:function(){var b=this.getObjects()[0].get("fill")||"";if("string"!==typeof b)return!1;b=b.toLowerCase();return this.getObjects().every(function(a){a=a.get("fill")||"";return"string"===typeof a&&a.toLowerCase()===b})},complexity:function(){return this.paths.reduce(function(b, +a){return b+(a&&a.complexity?a.complexity():0)},0)},getObjects:function(){return this.paths}}),b.PathGroup.fromObject=function(c,a){var d=c.paths;delete c.paths;"string"===typeof d?b.loadSVGFromURL(d,function(e){e=b.util.groupSVGElements(e,c,d);c.paths=d;a(e)}):b.util.enlivenObjects(d,function(e){e=new b.PathGroup(e,c);c.paths=d;a(e)})},b.PathGroup.async=!0)})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend,c=b.util.array.min,a=b.util.array.max;if(!b.Group){var g={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};b.Group=b.util.createClass(b.Object,b.Collection,{type:"group",strokeWidth:0,subTargetCheck:!1,cacheProperties:[],initialize:function(a,b,c){b=b||{};this._objects=[];c&&this.callSuper("initialize",b);this._objects=a||[];for(a=this._objects.length;a--;)this._objects[a].group=this; +b.originX&&(this.originX=b.originX);b.originY&&(this.originY=b.originY);c?(this._updateObjectsCoords(!0),this._updateObjectsACoords()):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",b));this.setCoords();this.saveCoords()},_updateObjectsACoords:function(){for(var a=this._objects.length;a--;)this._objects[a].setCoords(!0,!0)},_updateObjectsCoords:function(a){for(var b=this.getCenterPoint(),c=this._objects.length;c--;)this._updateObjectCoords(this._objects[c],b,a)},_updateObjectCoords:function(a, +b,c){a.__origHasControls=a.hasControls;a.hasControls=!1;if(!c){c=a.getLeft();var d=a.getTop();a.set({left:c-b.x,top:d-b.y});a.setCoords(!0,!0)}},toString:function(){return"#<fabric.Group: ("+this.complexity()+")>"},addWithUpdate:function(a){this._restoreObjectsState();b.util.resetObjectTransform(this);a&&(this._objects.push(a),a.group=this,a._set("canvas",this.canvas));this.forEachObject(this._setObjectActive,this);this._calcBounds();this._updateObjectsCoords();this.setCoords();this.dirty=!0;return this}, +_setObjectActive:function(a){a.set("active",!0);a.group=this},removeWithUpdate:function(a){this._restoreObjectsState();b.util.resetObjectTransform(this);this.forEachObject(this._setObjectActive,this);this.remove(a);this._calcBounds();this._updateObjectsCoords();this.setCoords();this.dirty=!0;return this},_onObjectAdded:function(a){this.dirty=!0;a.group=this;a._set("canvas",this.canvas)},_onObjectRemoved:function(a){this.dirty=!0;delete a.group;a.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(a,b){var c=this._objects.length;if(this.delegatedProperties[a]||"canvas"===a)for(;c--;)this._objects[c].set(a,b);else for(;c--;)this._objects[c].setOnGroup(a,b);this.callSuper("_set",a,b)},toObject:function(a){var b=this.getObjects().map(function(b){var c=b.includeDefaultValues;b.includeDefaultValues=b.group.includeDefaultValues;var d=b.toObject(a);b.includeDefaultValues= +c;return d});return d(this.callSuper("toObject",a),{objects:b})},toDatalessObject:function(a){var b=this.getObjects().map(function(b){var c=b.includeDefaultValues;b.includeDefaultValues=b.group.includeDefaultValues;var d=b.toDatalessObject(a);b.includeDefaultValues=c;return d});return d(this.callSuper("toDatalessObject",a),{objects:b})},render:function(a){this._transformDone=!0;this.callSuper("render",a);this._transformDone=!1},shouldCache:function(){var a=this.objectCaching&&(!this.group||this.needsItsOwnCache()|| +!this.group.isCaching());if(this.caching=a)for(var b=0,c=this._objects.length;b<c;b++)if(this._objects[b].willDrawShadow())return this.caching=!1;return a},willDrawShadow:function(){if(this.callSuper("willDrawShadow"))return!0;for(var a=0,b=this._objects.length;a<b;a++)if(this._objects[a].willDrawShadow())return!0;return!1},isCaching:function(){return this.caching||this.group&&this.group.isCaching()},drawObject:function(a){for(var b=0,c=this._objects.length;b<c;b++)this._renderObject(this._objects[b], +a)},isCacheDirty:function(){if(this.callSuper("isCacheDirty"))return!0;if(!this.statefullCache)return!1;for(var a=0,b=this._objects.length;a<b;a++)if(this._objects[a].isCacheDirty(!0))return this._cacheCanvas&&(a=this.cacheWidth/this.zoomX,b=this.cacheHeight/this.zoomY,this._cacheContext.clearRect(-a/2,-b/2,a,b)),!0;return!1},_renderControls:function(a,b){a.save();a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1;this.callSuper("_renderControls",a,b);for(var c=0,d=this._objects.length;c< +d;c++)this._objects[c]._renderControls(a);a.restore()},_renderObject:function(a,b){if(a.visible){var c=a.hasRotatingPoint;a.hasRotatingPoint=!1;a.render(b);a.hasRotatingPoint=c}},_restoreObjectsState:function(){this._objects.forEach(this._restoreObjectState,this);return this},realizeTransform:function(a){var c=a.calcTransformMatrix(),c=b.util.qrDecompose(c),d=new b.Point(c.translateX,c.translateY);a.flipX=!1;a.flipY=!1;a.set("scaleX",c.scaleX);a.set("scaleY",c.scaleY);a.skewX=c.skewX;a.skewY=c.skewY; +a.angle=c.angle;a.setPositionByOrigin(d,"center","center");return a},_restoreObjectState:function(a){this.realizeTransform(a);a.setCoords();a.hasControls=a.__origHasControls;delete a.__origHasControls;a.set("active",!1);delete a.group;return this},destroy:function(){this._objects.forEach(function(a){a.set("dirty",!0)});return this._restoreObjectsState()},saveCoords:function(){this._originalLeft=this.get("left");this._originalTop=this.get("top");return this},hasMoved:function(){return this._originalLeft!== +this.get("left")||this._originalTop!==this.get("top")},setObjectsCoords:function(){this.forEachObject(function(a){a.setCoords(!0,!0)});return this},_calcBounds:function(a){for(var b=[],c=[],d,e,g=["tr","br","bl","tl"],h=0,q=this._objects.length,t,r=g.length;h<q;++h)for(d=this._objects[h],d.setCoords(!0),t=0;t<r;t++)e=g[t],b.push(d.oCoords[e].x),c.push(d.oCoords[e].y);this.set(this._getBounds(b,c,a))},_getBounds:function(d,e,g){var f=new b.Point(c(d),c(e));d=new b.Point(a(d),a(e));d={width:d.x-f.x|| +0,height:d.y-f.y||0};g||(d.left=f.x||0,d.top=f.y||0,"center"===this.originX&&(d.left+=d.width/2),"right"===this.originX&&(d.left+=d.width),"center"===this.originY&&(d.top+=d.height/2),"bottom"===this.originY&&(d.top+=d.height));return d},toSVG:function(a){var b=this._createBaseSVGMarkup();b.push("<g ",this.getSvgId(),'transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'" style="',this.getSvgFilter(),'">\n');for(var c=0,d=this._objects.length;c<d;c++)b.push("\t",this._objects[c].toSVG(a)); +b.push("</g>\n");return a?a(b.join("")):b.join("")},get:function(a){if(a in g){if(this[a])return this[a];for(var b=0,c=this._objects.length;b<c;b++)if(this._objects[b][a])return!0;return!1}return a in this.delegatedProperties?this._objects[0]&&this._objects[0].get(a):this[a]}});b.Group.fromObject=function(a,c){b.util.enlivenObjects(a.objects,function(d){var e=b.util.object.clone(a,!0);delete e.objects;c&&c(new b.Group(d,e,!0))})};b.Group.async=!0}})("undefined"!==typeof exports?exports:this); +(function(e){var b=fabric.util.object.extend;e.fabric||(e.fabric={});e.fabric.Image?fabric.warn("fabric.Image is already defined."):(fabric.Image=fabric.util.createClass(fabric.Object,{type:"image",crossOrigin:"",alignX:"none",alignY:"none",meetOrSlice:"meet",strokeWidth:0,_lastScaleX:1,_lastScaleY:1,minimumScaleTrigger:.5,stateProperties:fabric.Object.prototype.stateProperties.concat("alignX","alignY","meetOrSlice"),objectCaching:!1,initialize:function(b,c,a){c||(c={});this.filters=[];this.resizeFilters= +[];this.callSuper("initialize",c);this._initElement(b,c,a)},getElement:function(){return this._element},setElement:function(b,c,a){var d;this._originalElement=this._element=b;this._initConfig(a);0===this.resizeFilters.length?b=c:(d=this,b=function(){d.applyFilters(c,d.resizeFilters,d._filteredEl||d._originalElement,!0)});0!==this.filters.length?this.applyFilters(b):b&&b(this);return this},setCrossOrigin:function(b){this.crossOrigin=b;this._element.crossOrigin=b;return this},getOriginalSize:function(){var b= +this.getElement();return{width:b.width,height:b.height}},_stroke:function(b){if(this.stroke&&0!==this.strokeWidth){var c=this.width/2,a=this.height/2;b.beginPath();b.moveTo(-c,-a);b.lineTo(c,-a);b.lineTo(c,a);b.lineTo(-c,a);b.lineTo(-c,-a);b.closePath()}},_renderDashedStroke:function(b){var c=-this.width/2,a=-this.height/2,d=this.width,e=this.height;b.save();this._setStrokeStyles(b);b.beginPath();fabric.util.drawDashedLine(b,c,a,c+d,a,this.strokeDashArray);fabric.util.drawDashedLine(b,c+d,a,c+d,a+ +e,this.strokeDashArray);fabric.util.drawDashedLine(b,c+d,a+e,c,a+e,this.strokeDashArray);fabric.util.drawDashedLine(b,c,a+e,c,a,this.strokeDashArray);b.closePath();b.restore()},toObject:function(d){var c=[],a=[],e=1,h=1;this.filters.forEach(function(a){a&&("Resize"===a.type&&(e*=a.scaleX,h*=a.scaleY),c.push(a.toObject()))});this.resizeFilters.forEach(function(b){b&&a.push(b.toObject())});d=b(this.callSuper("toObject",["crossOrigin","alignX","alignY","meetOrSlice"].concat(d)),{src:this.getSrc(),filters:c, +resizeFilters:a});d.width/=e;d.height/=h;return d},toSVG:function(b){var c=this._createBaseSVGMarkup(),a=-this.width/2,d=-this.height/2,e="none";this.group&&"path-group"===this.group.type&&(a=this.left,d=this.top);"none"!==this.alignX&&"none"!==this.alignY&&(e="x"+this.alignX+"Y"+this.alignY+" "+this.meetOrSlice);c.push('<g transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'">\n',"<image ",this.getSvgId(),'xlink:href="',this.getSvgSrc(!0),'" x="',a,'" y="',d,'" style="',this.getSvgStyles(), +'" width="',this.width,'" height="',this.height,'" preserveAspectRatio="',e,'"',"></image>\n");if(this.stroke||this.strokeDashArray)e=this.fill,this.fill=null,c.push("<rect ",'x="',a,'" y="',d,'" width="',this.width,'" height="',this.height,'" style="',this.getSvgStyles(),'"/>\n'),this.fill=e;c.push("</g>\n");return b?b(c.join("")):c.join("")},getSrc:function(b){return(b=b?this._element:this._originalElement)?fabric.isLikelyNode?b._src:b.src:this.src||""},setSrc:function(b,c,a){fabric.util.loadImage(b, +function(b){return this.setElement(b,c,a)},this,a&&a.crossOrigin)},toString:function(){return'#<fabric.Image: { src: "'+this.getSrc()+'" }>'},applyFilters:function(b,c,a,e){c=c||this.filters;if(a=a||this._originalElement){var d=fabric.util.createImage(),f=this.canvas?this.canvas.getRetinaScaling():fabric.devicePixelRatio,g=this.minimumScaleTrigger/f,k=this,m,n;if(0===c.length)return this._element=a,b&&b(this),a;var p=fabric.util.createCanvasElement();p.width=a.width;p.height=a.height;p.getContext("2d").drawImage(a, +0,0,a.width,a.height);c.forEach(function(a){a&&(e?(m=k.scaleX<g?k.scaleX:1,n=k.scaleY<g?k.scaleY:1,1>m*f&&(m*=f),1>n*f&&(n*=f)):(m=a.scaleX,n=a.scaleY),a.applyTo(p,m,n),e||"Resize"!==a.type||(k.width*=a.scaleX,k.height*=a.scaleY))});d.width=p.width;d.height=p.height;fabric.isLikelyNode?(d.src=p.toBuffer(void 0,fabric.Image.pngCompression),k._element=d,!e&&(k._filteredEl=d),b&&b(k)):(d.onload=function(){k._element=d;!e&&(k._filteredEl=d);b&&b(k);d.onload=p=null},d.src=p.toDataURL("image/png"));return p}}, +_render:function(b,c){var a,d,e=this._findMargins(),f;a=c?this.left:-this.width/2;d=c?this.top:-this.height/2;"slice"===this.meetOrSlice&&(b.beginPath(),b.rect(a,d,this.width,this.height),b.clip());!1===this.isMoving&&this.resizeFilters.length&&this._needsResize()?(this._lastScaleX=this.scaleX,this._lastScaleY=this.scaleY,f=this.applyFilters(null,this.resizeFilters,this._filteredEl||this._originalElement,!0)):f=this._element;f&&b.drawImage(f,a+e.marginX,d+e.marginY,e.width,e.height);this._stroke(b); +this._renderStroke(b)},_needsResize:function(){return this.scaleX!==this._lastScaleX||this.scaleY!==this._lastScaleY},_findMargins:function(){var b=this.width,c=this.height,a=0,e=0;if("none"!==this.alignX||"none"!==this.alignY)b=[this.width/this._element.width,this.height/this._element.height],c="meet"===this.meetOrSlice?Math.min.apply(null,b):Math.max.apply(null,b),b=this._element.width*c,c*=this._element.height,"Mid"===this.alignX&&(a=(this.width-b)/2),"Max"===this.alignX&&(a=this.width-b),"Mid"=== +this.alignY&&(e=(this.height-c)/2),"Max"===this.alignY&&(e=this.height-c);return{width:b,height:c,marginX:a,marginY:e}},_resetWidthHeight:function(){var b=this.getElement();this.set("width",b.width);this.set("height",b.height)},_initElement:function(b,c,a){this.setElement(fabric.util.getById(b),a,c);fabric.util.addClass(this.getElement(),fabric.Image.CSS_CANVAS)},_initConfig:function(b){b||(b={});this.setOptions(b);this._setWidthHeight(b);this._element&&this.crossOrigin&&(this._element.crossOrigin= +this.crossOrigin)},_initFilters:function(b,c){b&&b.length?fabric.util.enlivenObjects(b,function(a){c&&c(a)},"fabric.Image.filters"):c&&c()},_setWidthHeight:function(b){this.width="width"in b?b.width:this.getElement()?this.getElement().width||0:0;this.height="height"in b?b.height:this.getElement()?this.getElement().height||0:0}}),fabric.Image.CSS_CANVAS="canvas-img",fabric.Image.prototype.getSvgSrc=fabric.Image.prototype.getSrc,fabric.Image.fromObject=function(b,c){fabric.util.loadImage(b.src,function(a, +d){d?c&&c(null,d):fabric.Image.prototype._initFilters.call(b,b.filters,function(d){b.filters=d||[];fabric.Image.prototype._initFilters.call(b,b.resizeFilters,function(d){b.resizeFilters=d||[];return new fabric.Image(a,b,c)})})},null,b.crossOrigin)},fabric.Image.fromURL=function(b,c,a){fabric.util.loadImage(b,function(b){c&&c(new fabric.Image(b,a))},null,a&&a.crossOrigin)},fabric.Image.ATTRIBUTE_NAMES=fabric.SHARED_ATTRIBUTES.concat("x y width height preserveAspectRatio xlink:href crossOrigin".split(" ")), +fabric.Image.fromElement=function(d,c,a){d=fabric.parseAttributes(d,fabric.Image.ATTRIBUTE_NAMES);var e;d.preserveAspectRatio&&(e=fabric.util.parsePreserveAspectRatioAttribute(d.preserveAspectRatio),b(d,e));fabric.Image.fromURL(d["xlink:href"],c,b(a?fabric.util.object.clone(a):{},d))},fabric.Image.async=!0,fabric.Image.pngCompression=1)})("undefined"!==typeof exports?exports:this); +fabric.util.object.extend(fabric.Object.prototype,{_getAngleValueForStraighten:function(){var e=this.getAngle()%360;return 0<e?90*Math.round((e-1)/90):90*Math.round(e/90)},straighten:function(){this.setAngle(this._getAngleValueForStraighten());return this},fxStraighten:function(e){e=e||{};var b=function(){},d=e.onComplete||b,c=e.onChange||b,a=this;fabric.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(b){a.setAngle(b); +c()},onComplete:function(){a.setCoords();d()},onStart:function(){a.set("active",!1)}});return this}});fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(e){e.straighten();this.renderAll();return this},fxStraightenObject:function(e){e.fxStraighten({onChange:this.renderAll.bind(this)});return this}});fabric.Image.filters=fabric.Image.filters||{}; +fabric.Image.filters.BaseFilter=fabric.util.createClass({type:"BaseFilter",initialize:function(e){e&&this.setOptions(e)},setOptions:function(e){for(var b in e)this[b]=e[b]},toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}});fabric.Image.filters.BaseFilter.fromObject=function(e,b){var d=new fabric.Image.filters[e.type](e);b&&b(d);return d}; +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Brightness=c(d.BaseFilter,{type:"Brightness",initialize:function(a){a=a||{};this.brightness=a.brightness||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.brightness,e=0,k=c.length;e<k;e+=4)c[e]+=d,c[e+1]+=d,c[e+2]+=d;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{brightness:this.brightness})}});e.Image.filters.Brightness.fromObject= +e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Convolute=c(d.BaseFilter,{type:"Convolute",initialize:function(a){a=a||{};this.opaque=a.opaque;this.matrix=a.matrix||[0,0,0,0,1,0,0,0,0]},applyTo:function(a){var b=this.matrix,c=a.getContext("2d"),d=c.getImageData(0,0,a.width,a.height);a=Math.round(Math.sqrt(b.length));for(var e=Math.floor(a/2),k=d.data,m=d.width,d=d.height,n=c.createImageData(m,d),p=n.data,q=this.opaque?1:0,t,r,v,A,w,y,x,u= +0;u<d;u++)for(var C=0;C<m;C++){w=4*(u*m+C);for(var D=A=v=r=t=0;D<a;D++)for(var z=0;z<a;z++)x=u+D-e,y=C+z-e,0>x||x>d||0>y||y>m||(y=4*(x*m+y),x=b[D*a+z],t+=k[y]*x,r+=k[y+1]*x,v+=k[y+2]*x,A+=k[y+3]*x);p[w]=t;p[w+1]=r;p[w+2]=v;p[w+3]=A+q*(255-A)}c.putImageData(n,0,0)},toObject:function(){return b(this.callSuper("toObject"),{opaque:this.opaque,matrix:this.matrix})}});e.Image.filters.Convolute.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.GradientTransparency=c(d.BaseFilter,{type:"GradientTransparency",initialize:function(a){a=a||{};this.threshold=a.threshold||100},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.threshold,e=c.length,k=0,m=c.length;k<m;k+=4)c[k+3]=d+255*(e-k)/e;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{threshold:this.threshold})}}); +e.Image.filters.GradientTransparency.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Grayscale=d(e.BaseFilter,{type:"Grayscale",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);for(var c=b.data,d=b.width*b.height*4,e=0,l;e<d;)l=(c[e]+c[e+1]+c[e+2])/3,c[e]=l,c[e+1]=l,c[e+2]=l,e+=4;a.putImageData(b,0,0)}});b.Image.filters.Grayscale.fromObject=function(c,a){c=c||{};c.type="Grayscale";return b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports? +exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Invert=d(e.BaseFilter,{type:"Invert",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e;for(e=0;e<d;e+=4)c[e]=255-c[e],c[e+1]=255-c[e+1],c[e+2]=255-c[e+2];a.putImageData(b,0,0)}});b.Image.filters.Invert.fromObject=function(c,a){c=c||{};c.type="Invert";return b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Mask=c(e.BaseFilter,{type:"Mask",initialize:function(a){a=a||{};this.mask=a.mask;this.channel=-1<[0,1,2,3].indexOf(a.channel)?a.channel:0},applyTo:function(a){if(this.mask){var c=a.getContext("2d"),d=c.getImageData(0,0,a.width,a.height),e=d.data,l=this.mask.getElement(),k=b.util.createCanvasElement(),m=this.channel,n=d.width*d.height*4;k.width=a.width;k.height=a.height;k.getContext("2d").drawImage(l, +0,0,a.width,a.height);l=k.getContext("2d").getImageData(0,0,a.width,a.height).data;for(a=0;a<n;a+=4)e[a+3]=l[a+m];c.putImageData(d,0,0)}},toObject:function(){return d(this.callSuper("toObject"),{mask:this.mask.toObject(),channel:this.channel})}});b.Image.filters.Mask.fromObject=function(a,c){b.util.loadImage(a.mask.src,function(d){a.mask=new b.Image(d,a.mask);return b.Image.filters.BaseFilter.fromObject(a,c)})};b.Image.filters.Mask.async=!0})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Noise=c(d.BaseFilter,{type:"Noise",initialize:function(a){a=a||{};this.noise=a.noise||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.noise,e,k=0,m=c.length;k<m;k+=4)e=(.5-Math.random())*d,c[k]+=e,c[k+1]+=e,c[k+2]+=e;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{noise:this.noise})}});e.Image.filters.Noise.fromObject= +e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Pixelate=c(d.BaseFilter,{type:"Pixelate",initialize:function(a){a=a||{};this.blocksize=a.blocksize||4},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);var c=a.data,d=a.height,e=a.width,k,m,n,p,q,t,r;for(m=0;m<d;m+=this.blocksize)for(n=0;n<e;n+=this.blocksize){k=4*m*e+4*n;p=c[k];q=c[k+1];t=c[k+2];r=c[k+3];for(var v=m,A=m+this.blocksize;v<A;v++)for(var w=n,y= +n+this.blocksize;w<y;w++)k=4*v*e+4*w,c[k]=p,c[k+1]=q,c[k+2]=t,c[k+3]=r}b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{blocksize:this.blocksize})}});e.Image.filters.Pixelate.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.RemoveWhite=c(d.BaseFilter,{type:"RemoveWhite",initialize:function(a){a=a||{};this.threshold=a.threshold||30;this.distance=a.distance||20},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.distance,e=255-this.threshold,k=Math.abs,m,n,p,q=0,t=c.length;q<t;q+=4)m=c[q],n=c[q+1],p=c[q+2],m>e&&n>e&&p>e&&k(m-n)<d&&k(m-p)<d&&k(n-p)<d&&(c[q+3]= +0);b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{threshold:this.threshold,distance:this.distance})}});e.Image.filters.RemoveWhite.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Sepia=d(e.BaseFilter,{type:"Sepia",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e,l;for(e=0;e<d;e+=4)l=.3*c[e]+.59*c[e+1]+.11*c[e+2],c[e]=l+100,c[e+1]=l+50,c[e+2]=l+255;a.putImageData(b,0,0)}});b.Image.filters.Sepia.fromObject=function(c,a){c=c||{};c.type="Sepia";return new b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports? +exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Sepia2=d(e.BaseFilter,{type:"Sepia2",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e,l,k,m;for(e=0;e<d;e+=4)l=c[e],k=c[e+1],m=c[e+2],c[e]=(.393*l+.769*k+.189*m)/1.351,c[e+1]=(.349*l+.686*k+.168*m)/1.203,c[e+2]=(.272*l+.534*k+.131*m)/2.14;a.putImageData(b,0,0)}});b.Image.filters.Sepia2.fromObject=function(c,a){c=c||{};c.type="Sepia2";return new b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!== +typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Tint=c(e.BaseFilter,{type:"Tint",initialize:function(a){a=a||{};this.color=a.color||"#000000";this.opacity="undefined"!==typeof a.opacity?a.opacity:(new b.Color(this.color)).getAlpha()},applyTo:function(a){var c=a.getContext("2d");a=c.getImageData(0,0,a.width,a.height);var d=a.data,e=d.length,l,k,m,n,p,q,t,r;l=(new b.Color(this.color)).getSource();k=l[0]*this.opacity;m=l[1]*this.opacity; +n=l[2]*this.opacity;r=1-this.opacity;for(l=0;l<e;l+=4)p=d[l],q=d[l+1],t=d[l+2],d[l]=k+p*r,d[l+1]=m+q*r,d[l+2]=n+t*r;c.putImageData(a,0,0)},toObject:function(){return d(this.callSuper("toObject"),{color:this.color,opacity:this.opacity})}});b.Image.filters.Tint.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Multiply=c(e.BaseFilter,{type:"Multiply",initialize:function(a){a=a||{};this.color=a.color||"#000000"},applyTo:function(a){var c=a.getContext("2d");a=c.getImageData(0,0,a.width,a.height);var d=a.data,e=d.length,l,k;k=(new b.Color(this.color)).getSource();for(l=0;l<e;l+=4)d[l]*=k[0]/255,d[l+1]*=k[1]/255,d[l+2]*=k[2]/255;c.putImageData(a,0,0)},toObject:function(){return d(this.callSuper("toObject"), +{color:this.color})}});b.Image.filters.Multiply.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric;e=b.Image.filters;var d=b.util.createClass;e.Blend=d(e.BaseFilter,{type:"Blend",initialize:function(b){b=b||{};this.color=b.color||"#000";this.image=b.image||!1;this.mode=b.mode||"multiply";this.alpha=b.alpha||1},applyTo:function(c){var a=c.getContext("2d");c=a.getImageData(0,0,c.width,c.height);var d=c.data,e,f,l,k,m,n,p,q=!1;this.image?(q=!0,p=b.util.createCanvasElement(),p.width=this.image.width,p.height=this.image.height,p=new b.StaticCanvas(p),p.add(this.image),p= +p.getContext("2d").getImageData(0,0,p.width,p.height).data):(p=(new b.Color(this.color)).getSource(),e=p[0]*this.alpha,f=p[1]*this.alpha,l=p[2]*this.alpha);for(var t=0,r=d.length;t<r;t+=4)switch(k=d[t],m=d[t+1],n=d[t+2],q&&(e=p[t]*this.alpha,f=p[t+1]*this.alpha,l=p[t+2]*this.alpha),this.mode){case "multiply":d[t]=k*e/255;d[t+1]=m*f/255;d[t+2]=n*l/255;break;case "screen":d[t]=1-(1-k)*(1-e);d[t+1]=1-(1-m)*(1-f);d[t+2]=1-(1-n)*(1-l);break;case "add":d[t]=Math.min(255,k+e);d[t+1]=Math.min(255,m+f);d[t+ +2]=Math.min(255,n+l);break;case "diff":case "difference":d[t]=Math.abs(k-e);d[t+1]=Math.abs(m-f);d[t+2]=Math.abs(n-l);break;case "subtract":k-=e;m-=f;n-=l;d[t]=0>k?0:k;d[t+1]=0>m?0:m;d[t+2]=0>n?0:n;break;case "darken":d[t]=Math.min(k,e);d[t+1]=Math.min(m,f);d[t+2]=Math.min(n,l);break;case "lighten":d[t]=Math.max(k,e),d[t+1]=Math.max(m,f),d[t+2]=Math.max(n,l)}a.putImageData(c,0,0)},toObject:function(){return{color:this.color,image:this.image,mode:this.mode,alpha:this.alpha}}});b.Image.filters.Blend.fromObject= +b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=Math.pow,c=Math.floor,a=Math.sqrt,g=Math.abs,h=Math.max,f=Math.round,l=Math.sin,k=Math.ceil;e=b.Image.filters;var m=b.util.createClass;e.Resize=m(e.BaseFilter,{type:"Resize",resizeType:"hermite",scaleX:0,scaleY:0,lanczosLobes:3,applyTo:function(a,b,c){if(1!==b||1!==c){this.rcpScaleX=1/b;this.rcpScaleY=1/c;var d=a.width,e=a.height;b=f(d*b);c=f(e*c);var g;"sliceHack"===this.resizeType&&(g=this.sliceByTwo(a,d,e,b,c));"hermite"===this.resizeType&&(g=this.hermiteFastResize(a, +d,e,b,c));"bilinear"===this.resizeType&&(g=this.bilinearFiltering(a,d,e,b,c));"lanczos"===this.resizeType&&(g=this.lanczosResize(a,d,e,b,c));a.width=b;a.height=c;a.getContext("2d").putImageData(g,0,0)}},sliceByTwo:function(a,d,e,f,g){var k=a.getContext("2d"),l,m=.5,n=.5,p=1,q=1,t=!1,r=!1,z=d,E=e,B=b.util.createCanvasElement(),F=B.getContext("2d");f=c(f);g=c(g);B.width=h(f,d);B.height=h(g,e);f>d&&(m=2,p=-1);g>e&&(n=2,q=-1);l=k.getImageData(0,0,d,e);a.width=h(f,d);a.height=h(g,e);for(k.putImageData(l, +0,0);!t||!r;)d=z,e=E,f*p<c(z*m*p)?z=c(z*m):(z=f,t=!0),g*q<c(E*n*q)?E=c(E*n):(E=g,r=!0),l=k.getImageData(0,0,d,e),F.putImageData(l,0,0),k.clearRect(0,0,z,E),k.drawImage(B,0,0,d,e,0,0,z,E);return k.getImageData(0,0,f,g)},lanczosResize:function(b,e,f,h,m){var n,p,q,t;function r(b){var k,l,u,v,w,x,A,y,J,M;q=(b+.5)*B;n=c(q);for(k=0;k<m;k++){t=(k+.5)*F;p=c(t);J=y=A=x=w=0;for(l=n-L;l<=n+L;l++)if(!(0>l||l>=e)){M=c(1E3*g(l-q));H[M]||(H[M]={});for(var N=p-O;N<=p+O;N++)0>N||N>=f||(u=c(1E3*g(N-t)),H[M][u]||(H[M][u]= +E(a(d(M*G,2)+d(u*K,2))/1E3)),u=H[M][u],0<u&&(v=4*(N*e+l),w+=u,x+=u*D[v],A+=u*D[v+1],y+=u*D[v+2],J+=u*D[v+3]))}v=4*(k*h+b);z[v]=x/w;z[v+1]=A/w;z[v+2]=y/w;z[v+3]=J/w}return++b<h?r(b):C}b=b.getContext("2d");var u=b.getImageData(0,0,e,f),C=b.getImageData(0,0,h,m),D=u.data,z=C.data,E=function(a){return function(b){if(b>a)return 0;b*=Math.PI;if(1E-16>g(b))return 1;var c=b/a;return l(b)*l(c)/b/c}}(this.lanczosLobes),B=this.rcpScaleX,F=this.rcpScaleY,G=2/this.rcpScaleX,K=2/this.rcpScaleY,L=k(B*this.lanczosLobes/ +2),O=k(F*this.lanczosLobes/2),H={};p=n=t=q=void 0;return r(0)},bilinearFiltering:function(a,b,d,e,f){var g,h,k,l,m,n,p,q,t,r,B=0,F=this.rcpScaleX,G=this.rcpScaleY;p=a.getContext("2d");a=4*(b-1);d=p.getImageData(0,0,b,d).data;var K=p.getImageData(0,0,e,f),L=K.data;for(p=0;p<f;p++)for(q=0;q<e;q++)for(m=c(F*q),n=c(G*p),t=F*q-m,r=G*p-n,n=4*(n*b+m),m=0;4>m;m++)g=d[n+m],h=d[n+4+m],k=d[n+a+m],l=d[n+a+4+m],g=g*(1-t)*(1-r)+h*t*(1-r)+k*r*(1-t)+l*t*r,L[B++]=g;return K},hermiteFastResize:function(b,d,e,f,h){var l= +this.rcpScaleX,m=this.rcpScaleY,n=k(l/2),p=k(m/2);b=b.getContext("2d");e=b.getImageData(0,0,d,e).data;b=b.getImageData(0,0,f,h);for(var q=b.data,t=0;t<h;t++)for(var r=0;r<f;r++){for(var D=4*(r+t*f),z,E=0,B=0,F=0,G=0,K=0,L=0,O=(t+.5)*m,H=c(t*m);H<(t+1)*m;H++)for(var J=g(O-(H+.5))/p,Q=(r+.5)*l,J=J*J,P=c(r*l);P<(r+1)*l;P++){var I=g(Q-(P+.5))/n;z=a(J+I*I);1<z&&-1>z||(z=2*z*z*z-3*z*z+1,0<z&&(I=4*(P+H*d),L+=z*e[I+3],B+=z,255>e[I+3]&&(z=z*e[I+3]/250),F+=z*e[I],G+=z*e[I+1],K+=z*e[I+2],E+=z))}q[D]=F/E;q[D+ +1]=G/E;q[D+2]=K/E;q[D+3]=L/B}return b},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}});b.Image.filters.Resize.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.ColorMatrix=c(d.BaseFilter,{type:"ColorMatrix",initialize:function(a){a||(a={});this.matrix=a.matrix||[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0]},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);var c=a.data,d=c.length,e,k,m,n,p,q=this.matrix;for(e=0;e<d;e+=4)k=c[e],m=c[e+1],n=c[e+2],p=c[e+3],c[e]=k*q[0]+m*q[1]+n*q[2]+p*q[3]+q[4],c[e+1]=k*q[5]+m*q[6]+n*q[7]+ +p*q[8]+q[9],c[e+2]=k*q[10]+m*q[11]+n*q[12]+p*q[13]+q[14],c[e+3]=k*q[15]+m*q[16]+n*q[17]+p*q[18]+q[19];b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{type:this.type,matrix:this.matrix})}});e.Image.filters.ColorMatrix.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Contrast=c(d.BaseFilter,{type:"Contrast",initialize:function(a){a=a||{};this.contrast=a.contrast||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=259*(this.contrast+255)/(255*(259-this.contrast)),e=0,k=c.length;e<k;e+=4)c[e]=d*(c[e]-128)+128,c[e+1]=d*(c[e+1]-128)+128,c[e+2]=d*(c[e+2]-128)+128;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"), +{contrast:this.contrast})}});e.Image.filters.Contrast.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Saturate=c(d.BaseFilter,{type:"Saturate",initialize:function(a){a=a||{};this.saturate=a.saturate||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d,e=.01*-this.saturate,k=0,m=c.length;k<m;k+=4)d=Math.max(c[k],c[k+1],c[k+2]),c[k]+=d!==c[k]?(d-c[k])*e:0,c[k+1]+=d!==c[k+1]?(d-c[k+1])*e:0,c[k+2]+=d!==c[k+2]?(d-c[k+2])*e:0;b.putImageData(a,0, +0)},toObject:function(){return b(this.callSuper("toObject"),{saturate:this.saturate})}});e.Image.filters.Saturate.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.toFixed,c=b.Object.NUM_FRACTION_DIGITS;b.Text?b.warn("fabric.Text is already defined"):(b.Text=b.util.createClass(b.Object,{_dimensionAffectingProps:"fontSize fontWeight fontFamily fontStyle lineHeight text charSpacing textAlign".split(" "),_reNewline:/\r?\n/,_reSpacesAndTabs:/[ \t\r]+/g,type:"text",fontSize:40,fontWeight:"normal",fontFamily:"Times New Roman",textDecoration:"",textAlign:"left",fontStyle:"",lineHeight:1.16,textBackgroundColor:"", +stateProperties:b.Object.prototype.stateProperties.concat("fontFamily","fontWeight","fontSize","text","textDecoration","textAlign","fontStyle","lineHeight","textBackgroundColor","charSpacing"),cacheProperties:b.Object.prototype.cacheProperties.concat("fontFamily","fontWeight","fontSize","text","textDecoration","textAlign","fontStyle","lineHeight","textBackgroundColor","charSpacing","styles"),stroke:null,shadow:null,_fontSizeFraction:.25,_fontSizeMult:1.13,charSpacing:0,initialize:function(a,b){b= +b||{};this.text=a;this.__skipDimension=!0;this.callSuper("initialize",b);this.__skipDimension=!1;this._initDimensions();this.setCoords();this.setupState({propertySet:"_dimensionAffectingProps"})},_initDimensions:function(a){this.__skipDimension||(a||(a=b.util.createCanvasElement().getContext("2d"),this._setTextStyles(a)),this._textLines=this._splitTextIntoLines(),this._clearCache(),this.width=this._getTextWidth(a)||this.cursorWidth||2,this.height=this._getTextHeight(a),this.setCoords())},toString:function(){return"#<fabric.Text ("+ +this.complexity()+'): { "text": "'+this.text+'", "fontFamily": "'+this.fontFamily+'" }>'},_getCacheCanvasDimensions:function(){var a=this.callSuper("_getCacheCanvasDimensions"),b=this.fontSize;a.width+=b*a.zoomX;a.height+=b*a.zoomY;return a},_render:function(a){this._setTextStyles(a);this.group&&"path-group"===this.group.type&&a.translate(this.left,this.top);this._renderTextLinesBackground(a);this._renderText(a);this._renderTextDecoration(a)},_renderText:function(a){this._renderTextFill(a);this._renderTextStroke(a)}, +_setTextStyles:function(a){a.textBaseline="alphabetic";a.font=this._getFontDeclaration()},_getTextHeight:function(){return this._getHeightOfSingleLine()+(this._textLines.length-1)*this._getHeightOfLine()},_getTextWidth:function(a){for(var b=this._getLineWidth(a,0),c=1,d=this._textLines.length;c<d;c++){var e=this._getLineWidth(a,c);e>b&&(b=e)}return b},_renderChars:function(a,b,c,d,e){var f=a.slice(0,-4),g,h;this[f].toLive&&(g=-this.width/2+this[f].offsetX||0,h=-this.height/2+this[f].offsetY||0,b.save(), +b.translate(g,h),d-=g,e-=h);if(0!==this.charSpacing){var l=this._getWidthOfCharSpacing();c=c.split("");for(var q=0,t=c.length;q<t;q++)g=c[q],h=b.measureText(g).width+l,b[a](g,d,e),d+=0<h?h:0}else b[a](c,d,e);this[f].toLive&&b.restore()},_renderTextLine:function(a,b,c,d,e,k){e-=this.fontSize*this._fontSizeFraction;var f=this._getLineWidth(b,k);if("justify"!==this.textAlign||this.width<f)this._renderChars(a,b,c,d,e,k);else for(var f=c.split(/\s+/),g=0,h=this._getWidthOfWords(b,f.join(" "),k,0),h=this.width- +h,l=f.length-1,h=0<l?h/l:0,l=0,t,r=0,v=f.length;r<v;r++){for(;" "===c[g]&&g<c.length;)g++;t=f[r];this._renderChars(a,b,t,d+l,e,k,g);l+=this._getWidthOfWords(b,t,k,g)+h;g+=t.length}},_getWidthOfWords:function(a,b){var c=a.measureText(b).width,d;0!==this.charSpacing&&(d=b.split("").length,d*=this._getWidthOfCharSpacing(),c+=d);return 0<c?c:0},_getLeftOffset:function(){return-this.width/2},_getTopOffset:function(){return-this.height/2},isEmptyStyles:function(){return!0},_renderTextCommon:function(a, +b){for(var c=0,d=this._getLeftOffset(),e=this._getTopOffset(),g=0,m=this._textLines.length;g<m;g++){var n=this._getHeightOfLine(a,g),p=n/this.lineHeight,q=this._getLineWidth(a,g),q=this._getLineLeftOffset(q);this._renderTextLine(b,a,this._textLines[g],d+q,e+c+p,g);c+=n}},_renderTextFill:function(a){!this.fill&&this.isEmptyStyles()||this._renderTextCommon(a,"fillText")},_renderTextStroke:function(a){if(this.stroke&&0!==this.strokeWidth||!this.isEmptyStyles())this.shadow&&!this.shadow.affectStroke&& +this._removeShadow(a),a.save(),this._setLineDash(a,this.strokeDashArray),a.beginPath(),this._renderTextCommon(a,"strokeText"),a.closePath(),a.restore()},_getHeightOfLine:function(){return this._getHeightOfSingleLine()*this.lineHeight},_getHeightOfSingleLine:function(){return this.fontSize*this._fontSizeMult},_renderTextLinesBackground:function(a){if(this.textBackgroundColor){var b=0,c,d,e,k=a.fillStyle;a.fillStyle=this.textBackgroundColor;for(var m=0,n=this._textLines.length;m<n;m++)c=this._getHeightOfLine(a, +m),d=this._getLineWidth(a,m),0<d&&(e=this._getLineLeftOffset(d),a.fillRect(this._getLeftOffset()+e,this._getTopOffset()+b,d,c/this.lineHeight)),b+=c;a.fillStyle=k;this._removeShadow(a)}},_getLineLeftOffset:function(a){return"center"===this.textAlign?(this.width-a)/2:"right"===this.textAlign?this.width-a:0},_clearCache:function(){this.__lineWidths=[];this.__lineHeights=[]},_shouldClearDimensionCache:function(){var a=this._forceClearCache;a||(a=this.hasStateChanged("_dimensionAffectingProps"));a&&(this.saveState({propertySet:"_dimensionAffectingProps"}), +this.dirty=!0);return a},_getLineWidth:function(a,b){if(this.__lineWidths[b])return-1===this.__lineWidths[b]?this.width:this.__lineWidths[b];var c,d;d=this._textLines[b];c=""===d?0:this._measureLine(a,b);(this.__lineWidths[b]=c)&&"justify"===this.textAlign&&(d=d.split(/\s+/),1<d.length&&(this.__lineWidths[b]=-1));return c},_getWidthOfCharSpacing:function(){return 0!==this.charSpacing?this.fontSize*this.charSpacing/1E3:0},_measureLine:function(a,b){var c=this._textLines[b],d=a.measureText(c).width, +e=0;0!==this.charSpacing&&(c=c.split("").length,e=(c-1)*this._getWidthOfCharSpacing());d+=e;return 0<d?d:0},_renderTextDecoration:function(a){if(this.textDecoration){var b=this.height/2,c=[];-1<this.textDecoration.indexOf("underline")&&c.push(.85);-1<this.textDecoration.indexOf("line-through")&&c.push(.43);-1<this.textDecoration.indexOf("overline")&&c.push(-.12);if(0<c.length){var d,e=0,k,m,n,p,q,t;d=0;for(k=this._textLines.length;d<k;d++){p=this._getLineWidth(a,d);q=this._getLineLeftOffset(p);t= +this._getHeightOfLine(a,d);m=0;for(n=c.length;m<n;m++)a.fillRect(this._getLeftOffset()+q,e+(this._fontSizeMult-1+c[m])*this.fontSize-b,p,this.fontSize/15);e+=t}}}},_getFontDeclaration:function(){return[b.isLikelyNode?this.fontWeight:this.fontStyle,b.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+"px",b.isLikelyNode?'"'+this.fontFamily+'"':this.fontFamily].join(" ")},render:function(a,b){!this.visible||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(this._shouldClearDimensionCache()&& +(this._setTextStyles(a),this._initDimensions(a)),this.callSuper("render",a,b))},_splitTextIntoLines:function(){return this.text.split(this._reNewline)},toObject:function(a){a="text fontSize fontWeight fontFamily fontStyle lineHeight textDecoration textAlign textBackgroundColor charSpacing".split(" ").concat(a);return this.callSuper("toObject",a)},toSVG:function(a){this.ctx||(this.ctx=b.util.createCanvasElement().getContext("2d"));var c=this._createBaseSVGMarkup(),d=this._getSVGLeftTopOffsets(this.ctx), +d=this._getSVGTextAndBg(d.textTop,d.textLeft);this._wrapSVGTextAndBg(c,d);return a?a(c.join("")):c.join("")},_getSVGLeftTopOffsets:function(a){a=this._getHeightOfLine(a,0);return{textLeft:-this.width/2+(this.group&&"path-group"===this.group.type?this.left:0),textTop:0+(this.group&&"path-group"===this.group.type?-this.top:0),lineTop:a}},_wrapSVGTextAndBg:function(a,b){var c=this.getSvgFilter(),c=""===c?"":' style="'+c+'"';a.push("\t<g ",this.getSvgId(),'transform="',this.getSvgTransform(),this.getSvgTransformMatrix(), +'"',c,">\n",b.textBgRects.join(""),'\t\t<text xml:space="preserve" ',this.fontFamily?'font-family="'+this.fontFamily.replace(/"/g,"'")+'" ':"",this.fontSize?'font-size="'+this.fontSize+'" ':"",this.fontStyle?'font-style="'+this.fontStyle+'" ':"",this.fontWeight?'font-weight="'+this.fontWeight+'" ':"",this.textDecoration?'text-decoration="'+this.textDecoration+'" ':"",'style="',this.getSvgStyles(!0),'" >\n',b.textSpans.join(""),"\t\t</text>\n","\t</g>\n")},getSvgStyles:function(a){return b.Object.prototype.getSvgStyles.call(this, +a)+" white-space: pre;"},_getSVGTextAndBg:function(a,b){var c=[],d=[],e=0;this._setSVGBg(d);for(var g=0,m=this._textLines.length;g<m;g++)this.textBackgroundColor&&this._setSVGTextLineBg(d,g,b,a,e),this._setSVGTextLineText(g,c,e,b,a,d),e+=this._getHeightOfLine(this.ctx,g);return{textSpans:c,textBgRects:d}},_setSVGTextLineText:function(a,e,h,f,l){h=this.fontSize*(this._fontSizeMult-this._fontSizeFraction)-l+h-this.height/2;"justify"===this.textAlign?this._setSVGTextLineJustifed(a,e,h,f):e.push('\t\t\t<tspan x="', +d(f+this._getLineLeftOffset(this._getLineWidth(this.ctx,a)),c),'" ','y="',d(h,c),'" ',this._getFillAttributes(this.fill),">",b.util.string.escapeXml(this._textLines[a]),"</tspan>\n")},_setSVGTextLineJustifed:function(a,e,h,f){var g=b.util.createCanvasElement().getContext("2d");this._setTextStyles(g);var k=this._textLines[a].split(/\s+/),m=this._getWidthOfWords(g,k.join("")),m=this.width-m,n=k.length-1,m=0<n?m/n:0,p=this._getFillAttributes(this.fill),q;f+=this._getLineLeftOffset(this._getLineWidth(g, +a));a=0;for(q=k.length;a<q;a++)n=k[a],e.push('\t\t\t<tspan x="',d(f,c),'" ','y="',d(h,c),'" ',p,">",b.util.string.escapeXml(n),"</tspan>\n"),f+=this._getWidthOfWords(g,n)+m},_setSVGTextLineBg:function(a,b,e,f,l){a.push("\t\t<rect ",this._getFillAttributes(this.textBackgroundColor),' x="',d(e+this._getLineLeftOffset(this._getLineWidth(this.ctx,b)),c),'" y="',d(l-this.height/2,c),'" width="',d(this._getLineWidth(this.ctx,b),c),'" height="',d(this._getHeightOfLine(this.ctx,b)/this.lineHeight,c),'"></rect>\n')}, +_setSVGBg:function(a){this.backgroundColor&&a.push("\t\t<rect ",this._getFillAttributes(this.backgroundColor),' x="',d(-this.width/2,c),'" y="',d(-this.height/2,c),'" width="',d(this.width,c),'" height="',d(this.height,c),'"></rect>\n')},_getFillAttributes:function(a){var c=a&&"string"===typeof a?new b.Color(a):"";return c&&c.getSource()&&1!==c.getAlpha()?'opacity="'+c.getAlpha()+'" fill="'+c.setAlpha(1).toRgb()+'"':'fill="'+a+'"'},_set:function(a,b){this.callSuper("_set",a,b);-1<this._dimensionAffectingProps.indexOf(a)&& +(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),b.Text.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat("x y dx dy font-family font-style font-weight font-size text-decoration text-anchor".split(" ")),b.Text.DEFAULT_SVG_FONT_SIZE=16,b.Text.fromElement=function(a,c){if(!a)return null;var d=b.parseAttributes(a,b.Text.ATTRIBUTE_NAMES);c=b.util.object.extend(c?b.util.object.clone(c):{},d);c.top=c.top||0;c.left=c.left||0;"dx"in d&&(c.left+=d.dx);"dy"in d&&(c.top+=d.dy);"fontSize"in +c||(c.fontSize=b.Text.DEFAULT_SVG_FONT_SIZE);c.originX||(c.originX="left");d="";"textContent"in a?d=a.textContent:"firstChild"in a&&null!==a.firstChild&&"data"in a.firstChild&&null!==a.firstChild.data&&(d=a.firstChild.data);var d=d.replace(/^\s+|\s+$|\n+/g,"").replace(/\s+/g," "),d=new b.Text(d,c),e=d.getHeight()/d.height,e=((d.height+d.strokeWidth)*d.lineHeight-d.height)*e,e=d.getHeight()+e,g=0;"left"===d.originX&&(g=d.getWidth()/2);"right"===d.originX&&(g=-d.getWidth()/2);d.set({left:d.getLeft()+ +g,top:d.getTop()-e/2+d.fontSize*(.18+d._fontSizeFraction)/d.lineHeight});return d},b.Text.fromObject=function(a,c,d){return b.Object._fromObject("Text",a,c,d,"text")},b.util.createAccessors(b.Text))})("undefined"!==typeof exports?exports:this); +(function(){var e=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(b,d){this.styles= +d?d.styles||{}:{};this.callSuper("initialize",b,d);this.initBehavior()},_clearCache:function(){this.callSuper("_clearCache");this.__widthOfSpace=[]},isEmptyStyles:function(){if(!this.styles)return!0;var b=this.styles,d;for(d in b)for(var c in b[d])for(var a in b[d][c])return!1;return!0},setSelectionStart:function(b){b=Math.max(b,0);this._updateAndFire("selectionStart",b)},setSelectionEnd:function(b){b=Math.min(b,this.text.length);this._updateAndFire("selectionEnd",b)},_updateAndFire:function(b,d){this[b]!== +d&&(this._fireSelectionChanged(),this[b]=d);this._updateTextarea()},_fireSelectionChanged:function(){this.fire("selection:changed");this.canvas&&this.canvas.fire("text:selection:changed",{target:this})},getSelectionStyles:function(b,d){if(2===arguments.length){for(var c=[],a=b;a<d;a++)c.push(this.getSelectionStyles(a));return c}c=this.get2DCursorLocation(b);return this._getStyleDeclaration(c.lineIndex,c.charIndex)||{}},setSelectionStyles:function(b){if(this.selectionStart===this.selectionEnd)this._extendStyles(this.selectionStart, +b);else for(var d=this.selectionStart;d<this.selectionEnd;d++)this._extendStyles(d,b);this._forceClearCache=!0;return this},_extendStyles:function(b,d){var c=this.get2DCursorLocation(b);this._getLineStyle(c.lineIndex)||this._setLineStyle(c.lineIndex,{});this._getStyleDeclaration(c.lineIndex,c.charIndex)||this._setStyleDeclaration(c.lineIndex,c.charIndex,{});fabric.util.object.extend(this._getStyleDeclaration(c.lineIndex,c.charIndex),d)},_initDimensions:function(b){b||this.clearContextTop();this.callSuper("_initDimensions", +b)},render:function(b,d){this.clearContextTop();this.callSuper("render",b,d);this.cursorOffsetCache={};this.renderCursorOrSelection()},_render:function(b){this.callSuper("_render",b);this.ctx=b},clearContextTop:function(){if(this.active&&this.isEditing&&this.canvas&&this.canvas.contextTop){var b=this.canvas.contextTop;b.save();b.transform.apply(b,this.canvas.viewportTransform);this.transform(b);this.transformMatrix&&b.transform.apply(b,this.transformMatrix);this._clearTextArea(b);b.restore()}},renderCursorOrSelection:function(){if(this.active&& +this.isEditing){var b=this.text.split(""),d,c;this.canvas&&this.canvas.contextTop?(c=this.canvas.contextTop,c.save(),c.transform.apply(c,this.canvas.viewportTransform),this.transform(c),this.transformMatrix&&c.transform.apply(c,this.transformMatrix),this._clearTextArea(c)):(c=this.ctx,c.save());this.selectionStart===this.selectionEnd?(d=this._getCursorBoundaries(b,"cursor"),this.renderCursor(d,c)):(d=this._getCursorBoundaries(b,"selection"),this.renderSelection(b,d,c));c.restore()}},_clearTextArea:function(b){var d= +this.width+4,c=this.height+4;b.clearRect(-d/2,-c/2,d,c)},get2DCursorLocation:function(b){"undefined"===typeof b&&(b=this.selectionStart);for(var d=this._textLines.length,c=0;c<d;c++){if(b<=this._textLines[c].length)return{lineIndex:c,charIndex:b};b-=this._textLines[c].length+1}return{lineIndex:c-1,charIndex:this._textLines[c-1].length<b?this._textLines[c-1].length:b}},getCurrentCharStyle:function(b,d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return{fontSize:c&&c.fontSize||this.fontSize,fill:c&& +c.fill||this.fill,textBackgroundColor:c&&c.textBackgroundColor||this.textBackgroundColor,textDecoration:c&&c.textDecoration||this.textDecoration,fontFamily:c&&c.fontFamily||this.fontFamily,fontWeight:c&&c.fontWeight||this.fontWeight,fontStyle:c&&c.fontStyle||this.fontStyle,stroke:c&&c.stroke||this.stroke,strokeWidth:c&&c.strokeWidth||this.strokeWidth}},getCurrentCharFontSize:function(b,d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return c&&c.fontSize?c.fontSize:this.fontSize},getCurrentCharColor:function(b, +d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return c&&c.fill?c.fill:this.cursorColor},_getCursorBoundaries:function(b,d){var c=Math.round(this._getLeftOffset()),a=this._getTopOffset(),e=this._getCursorBoundariesOffsets(b,d);return{left:c,top:a,leftOffset:e.left+e.lineLeft,topOffset:e.top}},_getCursorBoundariesOffsets:function(b,d){if(this.cursorOffsetCache&&"top"in this.cursorOffsetCache)return this.cursorOffsetCache;for(var c=0,a=0,e=0,h=0,f=0,l=0;l<this.selectionStart;l++)"\n"===b[l]?(f=0, +h+=this._getHeightOfLine(this.ctx,a),a++,e=0):(f+=this._getWidthOfChar(this.ctx,b[l],a,e),e++),c=this._getLineLeftOffset(this._getLineWidth(this.ctx,a));"cursor"===d&&(h+=(1-this._fontSizeFraction)*this._getHeightOfLine(this.ctx,a)/this.lineHeight-this.getCurrentCharFontSize(a,e)*(1-this._fontSizeFraction));0!==this.charSpacing&&e===this._textLines[a].length&&(f-=this._getWidthOfCharSpacing());return this.cursorOffsetCache={top:h,left:0<f?f:0,lineLeft:c}},renderCursor:function(b,d){var c=this.get2DCursorLocation(), +a=c.lineIndex,c=c.charIndex,e=this.getCurrentCharFontSize(a,c),h=b.leftOffset,f=this.scaleX*this.canvas.getZoom(),f=this.cursorWidth/f;d.fillStyle=this.getCurrentCharColor(a,c);d.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity;d.fillRect(b.left+h-f/2,b.top+b.topOffset,f,e)},renderSelection:function(b,d,c){c.fillStyle=this.selectionColor;b=this.get2DCursorLocation(this.selectionStart);for(var a=this.get2DCursorLocation(this.selectionEnd),e=b.lineIndex,h=a.lineIndex,f=e;f<=h;f++){var l= +this._getLineLeftOffset(this._getLineWidth(c,f))||0,k=this._getHeightOfLine(this.ctx,f),m,n=0;m=this._textLines[f];if(f===e){for(var p=0,q=m.length;p<q;p++)p>=b.charIndex&&(f!==h||p<a.charIndex)&&(n+=this._getWidthOfChar(c,m[p],f,p)),p<b.charIndex&&(l+=this._getWidthOfChar(c,m[p],f,p));p===m.length&&(n-=this._getWidthOfCharSpacing())}else if(f>e&&f<h)n+=this._getLineWidth(c,f)||5;else if(f===h){p=0;for(q=a.charIndex;p<q;p++)n+=this._getWidthOfChar(c,m[p],f,p);a.charIndex===m.length&&(n-=this._getWidthOfCharSpacing())}m= +k;if(1>this.lineHeight||f===h&&1<this.lineHeight)k/=this.lineHeight;c.fillRect(d.left+l,d.top+d.topOffset,0<n?n:0,k);d.topOffset+=m}},_renderChars:function(b,d,c,a,e,h,f){if(this.isEmptyStyles())return this._renderCharsFast(b,d,c,a,e);f=f||0;var g=this._getHeightOfLine(d,h),k,m,n="";d.save();e-=g/this.lineHeight*this._fontSizeFraction;for(var p=f,q=c.length+f;p<=q;p++){k=k||this.getCurrentCharStyle(h,p);m=this.getCurrentCharStyle(h,p+1);if(this._hasStyleChanged(k,m)||p===q)this._renderChar(b,d,h, +p-1,n,a,e,g),n="",k=m;n+=c[p-f]}d.restore()},_renderCharsFast:function(b,d,c,a,e){"fillText"===b&&this.fill&&this.callSuper("_renderChars",b,d,c,a,e);"strokeText"===b&&(this.stroke&&0<this.strokeWidth||this.skipFillStrokeCheck)&&this.callSuper("_renderChars",b,d,c,a,e)},_renderChar:function(b,d,c,a,e,h,f,l){var g,m,n,p=this._getStyleDeclaration(c,a),q,t;p?(g=this._getHeightOfChar(d,e,c,a),n=p.stroke,m=p.fill,q=p.textDecoration):g=this.fontSize;n=(n||this.stroke)&&"strokeText"===b;m=(m||this.fill)&& +"fillText"===b;p&&d.save();b=this._applyCharStylesGetWidth(d,e,c,a,p||null);q=q||this.textDecoration;p&&p.textBackgroundColor&&this._removeShadow(d);if(0!==this.charSpacing){c=this._getWidthOfCharSpacing();e=e.split("");a=b=0;for(var r=e.length;a<r;a++)t=e[a],m&&d.fillText(t,h+b,f),n&&d.strokeText(t,h+b,f),t=d.measureText(t).width+c,b+=0<t?t:0}else m&&d.fillText(e,h,f),n&&d.strokeText(e,h,f);if(q||""!==q)l=this._fontSizeFraction*l/this.lineHeight,this._renderCharDecoration(d,q,h,f,l,b,g);p&&d.restore(); +d.translate(b,0)},_hasStyleChanged:function(b,d){return b.fill!==d.fill||b.fontSize!==d.fontSize||b.textBackgroundColor!==d.textBackgroundColor||b.textDecoration!==d.textDecoration||b.fontFamily!==d.fontFamily||b.fontWeight!==d.fontWeight||b.fontStyle!==d.fontStyle||b.stroke!==d.stroke||b.strokeWidth!==d.strokeWidth},_renderCharDecoration:function(b,d,c,a,e,h,f){if(d){e=f/15;a={underline:a+f/10,"line-through":a-f*(this._fontSizeFraction+this._fontSizeMult-1)+e,overline:a-(this._fontSizeMult-this._fontSizeFraction)* +f};f=["underline","line-through","overline"];var g,k;for(g=0;g<f.length;g++)k=f[g],-1<d.indexOf(k)&&b.fillRect(c,a[k],h,e)}},_renderTextLine:function(b,d,c,a,e,h){this.isEmptyStyles()||(e+=this.fontSize*(this._fontSizeFraction+.03));this.callSuper("_renderTextLine",b,d,c,a,e,h)},_renderTextDecoration:function(b){if(this.isEmptyStyles())return this.callSuper("_renderTextDecoration",b)},_renderTextLinesBackground:function(b){this.callSuper("_renderTextLinesBackground",b);var d=0,c,a,e=this._getLeftOffset(), +h=this._getTopOffset(),f="",l,k,m,n,p,q,t;b.save();for(var r=0,v=this._textLines.length;r<v;r++){c=this._getHeightOfLine(b,r);l=this._textLines[r];if(""!==l&&this.styles&&this._getLineStyle(r)){a=this._getLineWidth(b,r);a=this._getLineLeftOffset(a);for(var A=n=p=q=t=0,w=l.length;A<w;A++)m=this._getStyleDeclaration(r,A)||{},f!==m.textBackgroundColor&&(t&&q&&(b.fillStyle=f,b.fillRect(n,p,q,t)),n=p=q=t=0,f=m.textBackgroundColor||""),m.textBackgroundColor?(k=l[A],f===m.textBackgroundColor&&(f=m.textBackgroundColor, +n||(n=e+a+this._getWidthOfCharsAt(b,r,A)),p=h+d,q+=this._getWidthOfChar(b,k,r,A),t=c/this.lineHeight)):f="";t&&q&&(b.fillStyle=f,b.fillRect(n,p,q,t))}d+=c}b.restore()},_getCacheProp:function(b,d){return b+d.fontSize+d.fontWeight+d.fontStyle},_getFontCache:function(b){fabric.charWidthsCache[b]||(fabric.charWidthsCache[b]={});return fabric.charWidthsCache[b]},_applyCharStylesGetWidth:function(b,d,c,a,g){var h=g||this._getStyleDeclaration(c,a);g=e(h);this._applyFontStyles(g);a=this._getFontCache(g.fontFamily); +c=this._getCacheProp(d,g);if(!h&&a[c]&&this.caching)return a[c];"string"===typeof g.shadow&&(g.shadow=new fabric.Shadow(g.shadow));h=g.fill||this.fill;b.fillStyle=h.toLive?h.toLive(b,this):h;g.stroke&&(b.strokeStyle=g.stroke&&g.stroke.toLive?g.stroke.toLive(b,this):g.stroke);b.lineWidth=g.strokeWidth||this.strokeWidth;b.font=this._getFontDeclaration.call(g);g.shadow&&(g.scaleX=this.scaleX,g.scaleY=this.scaleY,g.canvas=this.canvas,g.getObjectScaling=this.getObjectScaling,this._setShadow.call(g,b)); +return this.caching&&a[c]?a[c]:(b=b.measureText(d).width,this.caching&&(a[c]=b),b)},_applyFontStyles:function(b){b.fontFamily||(b.fontFamily=this.fontFamily);b.fontSize||(b.fontSize=this.fontSize);b.fontWeight||(b.fontWeight=this.fontWeight);b.fontStyle||(b.fontStyle=this.fontStyle)},_getStyleDeclaration:function(b,d,c){return c?this.styles[b]&&this.styles[b][d]?e(this.styles[b][d]):{}:this.styles[b]&&this.styles[b][d]?this.styles[b][d]:null},_setStyleDeclaration:function(b,d,c){this.styles[b][d]= +c},_deleteStyleDeclaration:function(b,d){delete this.styles[b][d]},_getLineStyle:function(b){return this.styles[b]},_setLineStyle:function(b,d){this.styles[b]=d},_deleteLineStyle:function(b){delete this.styles[b]},_getWidthOfChar:function(b,d,c,a){if(!this._isMeasuring&&"justify"===this.textAlign&&this._reSpacesAndTabs.test(d))return this._getWidthOfSpace(b,c);b.save();d=this._applyCharStylesGetWidth(b,d,c,a);0!==this.charSpacing&&(d+=this._getWidthOfCharSpacing());b.restore();return 0<d?d:0},_getHeightOfChar:function(b, +d,c){return(b=this._getStyleDeclaration(d,c))&&b.fontSize?b.fontSize:this.fontSize},_getWidthOfCharsAt:function(b,d,c){var a=0,e,h;for(e=0;e<c;e++)h=this._textLines[d][e],a+=this._getWidthOfChar(b,h,d,e);return a},_measureLine:function(b,d){this._isMeasuring=!0;var c=this._getWidthOfCharsAt(b,d,this._textLines[d].length);0!==this.charSpacing&&(c-=this._getWidthOfCharSpacing());this._isMeasuring=!1;return 0<c?c:0},_getWidthOfSpace:function(b,d){if(this.__widthOfSpace[d])return this.__widthOfSpace[d]; +var c=this._textLines[d],a=this._getWidthOfWords(b,c,d,0),a=this.width-a,c=c.length-c.replace(this._reSpacesAndTabs,"").length,c=Math.max(a/c,b.measureText(" ").width);return this.__widthOfSpace[d]=c},_getWidthOfWords:function(b,d,c,a){for(var e=0,h=0;h<d.length;h++){var f=d[h];f.match(/\s/)||(e+=this._getWidthOfChar(b,f,c,h+a))}return e},_getHeightOfLine:function(b,d){if(this.__lineHeights[d])return this.__lineHeights[d];for(var c=this._textLines[d],a=this._getHeightOfChar(b,d,0),e=1,c=c.length;e< +c;e++){var h=this._getHeightOfChar(b,d,e);h>a&&(a=h)}this.__lineHeights[d]=a*this.lineHeight*this._fontSizeMult;return this.__lineHeights[d]},_getTextHeight:function(b){for(var d,c=0,a=0,e=this._textLines.length;a<e;a++)d=this._getHeightOfLine(b,a),c+=a===e-1?d/this.lineHeight:d;return c},toObject:function(b){return fabric.util.object.extend(this.callSuper("toObject",b),{styles:e(this.styles,!0)})}});fabric.IText.fromObject=function(b,d,c){return fabric.Object._fromObject("IText",b,d,c,"text")}})(); +(function(){var e=fabric.util.object.clone;fabric.util.object.extend(fabric.IText.prototype,{initBehavior:function(){this.initAddedHandler();this.initRemovedHandler();this.initCursorSelectionHandlers();this.initDoubleClickSimulation();this.mouseMoveHandler=this.mouseMoveHandler.bind(this)},onDeselect:function(){this.isEditing&&this.exitEditing();this.selected=!1;this.callSuper("onDeselect")},initAddedHandler:function(){var b=this;this.on("added",function(){var d=b.canvas;d&&(d._hasITextHandlers|| +(d._hasITextHandlers=!0,b._initCanvasHandlers(d)),d._iTextInstances=d._iTextInstances||[],d._iTextInstances.push(b))})},initRemovedHandler:function(){var b=this;this.on("removed",function(){var d=b.canvas;d&&(d._iTextInstances=d._iTextInstances||[],fabric.util.removeFromArray(d._iTextInstances,b),0===d._iTextInstances.length&&(d._hasITextHandlers=!1,b._removeCanvasHandlers(d)))})},_initCanvasHandlers:function(b){b._mouseUpITextHandler=function(){b._iTextInstances&&b._iTextInstances.forEach(function(b){b.__isMousedown= +!1})}.bind(this);b.on("mouse:up",b._mouseUpITextHandler)},_removeCanvasHandlers:function(b){b.off("mouse:up",b._mouseUpITextHandler)},_tick:function(){this._currentTickState=this._animateCursor(this,1,this.cursorDuration,"_onTickComplete")},_animateCursor:function(b,d,c,a){var e;e={isAborted:!1,abort:function(){this.isAborted=!0}};b.animate("_currentCursorOpacity",d,{duration:c,onComplete:function(){if(!e.isAborted)b[a]()},onChange:function(){b.canvas&&b.selectionStart===b.selectionEnd&&b.renderCursorOrSelection()}, +abort:function(){return e.isAborted}});return e},_onTickComplete:function(){var b=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1);this._cursorTimeout1=setTimeout(function(){b._currentTickCompleteState=b._animateCursor(b,0,this.cursorDuration/2,"_tick")},100)},initDelayedCursor:function(b){var d=this;b=b?0:this.cursorDelay;this.abortCursorAnimation();this._currentCursorOpacity=1;this._cursorTimeout2=setTimeout(function(){d._tick()},b)},abortCursorAnimation:function(){var b=this._currentTickState|| +this._currentTickCompleteState;this._currentTickState&&this._currentTickState.abort();this._currentTickCompleteState&&this._currentTickCompleteState.abort();clearTimeout(this._cursorTimeout1);clearTimeout(this._cursorTimeout2);this._currentCursorOpacity=0;b&&this.canvas&&this.canvas.clearContext(this.canvas.contextTop||this.ctx)},selectAll:function(){this.selectionStart=0;this.selectionEnd=this.text.length;this._fireSelectionChanged();this._updateTextarea()},getSelectedText:function(){return this.text.slice(this.selectionStart, +this.selectionEnd)},findWordBoundaryLeft:function(b){var d=0,c=b-1;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)d++,c--;for(;/\S/.test(this.text.charAt(c))&&-1<c;)d++,c--;return b-d},findWordBoundaryRight:function(b){var d=0,c=b;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)d++,c++;for(;/\S/.test(this.text.charAt(c))&&c<this.text.length;)d++,c++;return b+d},findLineBoundaryLeft:function(b){for(var d=0,c=b-1;!/\n/.test(this.text.charAt(c))&& +-1<c;)d++,c--;return b-d},findLineBoundaryRight:function(b){for(var d=0,c=b;!/\n/.test(this.text.charAt(c))&&c<this.text.length;)d++,c++;return b+d},getNumNewLinesInSelectedText:function(){for(var b=this.getSelectedText(),d=0,c=0,a=b.length;c<a;c++)"\n"===b[c]&&d++;return d},searchWordBoundary:function(b,d){for(var c=this._reSpace.test(this.text.charAt(b))?b-1:b,a=this.text.charAt(c),e=/[ \n\.,;!\?\-]/;!e.test(a)&&0<c&&c<this.text.length;)c+=d,a=this.text.charAt(c);e.test(a)&&"\n"!==a&&(c+=1===d? +0:1);return c},selectWord:function(b){b=b||this.selectionStart;var d=this.searchWordBoundary(b,-1);b=this.searchWordBoundary(b,1);this.selectionStart=d;this.selectionEnd=b;this._fireSelectionChanged();this._updateTextarea();this.renderCursorOrSelection()},selectLine:function(b){b=b||this.selectionStart;var d=this.findLineBoundaryLeft(b);b=this.findLineBoundaryRight(b);this.selectionStart=d;this.selectionEnd=b;this._fireSelectionChanged();this._updateTextarea()},enterEditing:function(b){if(!this.isEditing&& +this.editable){this.canvas&&this.exitEditingOnOthers(this.canvas);this.selected=this.isEditing=!0;this.initHiddenTextarea(b);this.hiddenTextarea.focus();this._updateTextarea();this._saveEditingProps();this._setEditingProps();this._textBeforeEdit=this.text;this._tick();this.fire("editing:entered");this._fireSelectionChanged();if(!this.canvas)return this;this.canvas.fire("text:editing:entered",{target:this});this.initMouseMoveHandler();this.canvas.renderAll();return this}},exitEditingOnOthers:function(b){b._iTextInstances&& +b._iTextInstances.forEach(function(b){b.selected=!1;b.isEditing&&b.exitEditing()})},initMouseMoveHandler:function(){this.canvas.on("mouse:move",this.mouseMoveHandler)},mouseMoveHandler:function(b){if(this.__isMousedown&&this.isEditing){b=this.getSelectionStartFromPointer(b.e);var d=this.selectionStart,c=this.selectionEnd;if(b===this.__selectionStartOnMouseDown&&d!==c||d!==b&&c!==b)if(b>this.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=b):(this.selectionStart= +b,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart!==d||this.selectionEnd!==c)this.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()}},_setEditingProps:function(){this.hoverCursor="text";this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text");this.borderColor=this.editingBorderColor;this.hasControls=this.selectable=!1;this.lockMovementX=this.lockMovementY=!0},_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 b=this._calcTextareaPosition();this.hiddenTextarea.style.left=b.left;this.hiddenTextarea.style.top=b.top;this.hiddenTextarea.style.fontSize=b.fontSize}},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var b=this.text.split(""),d=this._getCursorBoundaries(b, +"cursor"),b=this.get2DCursorLocation(),b=this.getCurrentCharFontSize(b.lineIndex,b.charIndex),c=d.leftOffset,a=this.calcTransformMatrix(),d={x:d.left+c,y:d.top+d.topOffset+b},e=this.canvas.upperCanvasEl,c=e.width-b,e=e.height-b,d=fabric.util.transformPoint(d,a),d=fabric.util.transformPoint(d,this.canvas.viewportTransform);0>d.x&&(d.x=0);d.x>c&&(d.x=c);0>d.y&&(d.y=0);d.y>e&&(d.y=e);d.x+=this.canvas._offset.left;d.y+=this.canvas._offset.top;return{left:d.x+"px",top:d.y+"px",fontSize:b}},_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 b=this._textBeforeEdit!==this.text;this.isEditing=this.selected=!1;this.selectable=!0;this.selectionEnd=this.selectionStart;this.hiddenTextarea&&(this.hiddenTextarea.blur&&this.hiddenTextarea.blur(),this.canvas&&this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea),this.hiddenTextarea=null);this.abortCursorAnimation(); +this._restoreEditingProps();this._currentCursorOpacity=0;this.fire("editing:exited");b&&this.fire("modified");this.canvas&&(this.canvas.off("mouse:move",this.mouseMoveHandler),this.canvas.fire("text:editing:exited",{target:this}),b&&this.canvas.fire("object:modified",{target:this}));return this},_removeExtraneousStyles:function(){for(var b in this.styles)this._textLines[b]||delete this.styles[b]},_removeCharsFromTo:function(b,d){for(;d!==b;)this._removeSingleCharAndStyle(b+1),d--;this.selectionEnd= +this.selectionStart=b},_removeSingleCharAndStyle:function(b){var d="\n"===this.text[b-1];this.removeStyleObject(d,d?b:b-1);this.text=this.text.slice(0,b-1)+this.text.slice(b);this._textLines=this._splitTextIntoLines()},insertChars:function(b,d){var c;1<this.selectionEnd-this.selectionStart&&this._removeCharsFromTo(this.selectionStart,this.selectionEnd);if(!d&&this.isEmptyStyles())this.insertChar(b,!1);else for(var a=0,e=b.length;a<e;a++)d&&(c=fabric.util.object.clone(fabric.copiedTextStyle[a],!0)), +this.insertChar(b[a],a<e-1,c)},insertChar:function(b,d,c){var a="\n"===this.text[this.selectionStart];this.text=this.text.slice(0,this.selectionStart)+b+this.text.slice(this.selectionEnd);this._textLines=this._splitTextIntoLines();this.insertStyleObjects(b,a,c);this.selectionEnd=this.selectionStart+=b.length;d||(this._updateTextarea(),this.setCoords(),this._fireSelectionChanged(),this.fire("changed"),this.restartCursorIfNeeded(),this.canvas&&(this.canvas.fire("text:changed",{target:this}),this.canvas.renderAll()))}, +restartCursorIfNeeded:function(){this._currentTickState&&!this._currentTickState.isAborted&&this._currentTickCompleteState&&!this._currentTickCompleteState.isAborted||this.initDelayedCursor()},insertNewlineStyleObject:function(b,d,c){this.shiftLineStyles(b,1);var a={},g={};this.styles[b]&&this.styles[b][d-1]&&(a=this.styles[b][d-1]);if(c&&a)g[0]=e(a),this.styles[b+1]=g;else{c=!1;for(var h in this.styles[b])a=parseInt(h,10),a>=d&&(c=!0,g[a-d]=this.styles[b][h],delete this.styles[b][h]);c&&(this.styles[b+ +1]=g)}this._forceClearCache=!0},insertCharStyleObject:function(b,d,c){var a=this.styles[b],g=e(a);0!==d||c||(d=1);for(var h in g){var f=parseInt(h,10);f>=d&&(a[f+1]=g[f],g[f-1]||delete a[f])}(c=c||e(a[d-1]))&&(this.styles[b][d]=c);this._forceClearCache=!0},insertStyleObjects:function(b,d,c){var a=this.get2DCursorLocation(),e=a.lineIndex,a=a.charIndex;this._getLineStyle(e)||this._setLineStyle(e,{});"\n"===b?this.insertNewlineStyleObject(e,a,d):this.insertCharStyleObject(e,a,c)},shiftLineStyles:function(b, +d){var c=e(this.styles),a;for(a in c){var g=parseInt(a,10);g<=b&&delete c[g]}for(a in this.styles)g=parseInt(a,10),g>b&&(this.styles[g+d]=c[g],c[g-d]||delete this.styles[g])},removeStyleObject:function(b,d){var c=this.get2DCursorLocation(d);this._removeStyleObject(b,c,c.lineIndex,c.charIndex)},_getTextOnPreviousLine:function(b){return this._textLines[b-1]},_removeStyleObject:function(b,d,c,a){if(b){var g=this._getTextOnPreviousLine(d.lineIndex),g=g?g.length:0;this.styles[c-1]||(this.styles[c-1]={}); +for(a in this.styles[c])this.styles[c-1][parseInt(a,10)+g]=this.styles[c][a];this.shiftLineStyles(d.lineIndex,-1)}else for(g in(d=this.styles[c])&&delete d[a],c=e(d),c)b=parseInt(g,10),b>=a&&0!==b&&(d[b-1]=c[b],delete d[b])},insertNewline:function(){this.insertChars("\n")},setSelectionStartEndWithShift:function(b,d,c){c<=b?(d===b?this._selectionDirection="left":"right"===this._selectionDirection&&(this._selectionDirection="left",this.selectionEnd=b),this.selectionStart=c):c>b&&c<d?"right"===this._selectionDirection? +this.selectionEnd=c:this.selectionStart=c:(d===b?this._selectionDirection="right":"left"===this._selectionDirection&&(this._selectionDirection="right",this.selectionStart=d),this.selectionEnd=c)},setSelectionInBoundaries:function(){var b=this.text.length;this.selectionStart>b?this.selectionStart=b:0>this.selectionStart&&(this.selectionStart=0);this.selectionEnd>b?this.selectionEnd=b:0>this.selectionEnd&&(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(e){this.__newClickTime=+new Date;var b=this.canvas.getPointer(e.e);this.isTripleClick(b,e.e)?(this.fire("tripleclick",e),this._stopEvent(e.e)):this.isDoubleClick(b)&&(this.fire("dblclick",e),this._stopEvent(e.e));this.__lastLastClickTime=this.__lastClickTime; +this.__lastClickTime=this.__newClickTime;this.__lastPointer=b;this.__lastIsEditing=this.isEditing;this.__lastSelected=this.selected},isDoubleClick:function(e){return 500>this.__newClickTime-this.__lastClickTime&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y&&this.__lastIsEditing},isTripleClick:function(e){return 500>this.__newClickTime-this.__lastClickTime&&500>this.__lastClickTime-this.__lastLastClickTime&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y},_stopEvent:function(e){e.preventDefault&& +e.preventDefault();e.stopPropagation&&e.stopPropagation()},initCursorSelectionHandlers:function(){this.initMousedownHandler();this.initMouseupHandler();this.initClicks()},initClicks:function(){this.on("dblclick",function(e){this.selectWord(this.getSelectionStartFromPointer(e.e))});this.on("tripleclick",function(e){this.selectLine(this.getSelectionStartFromPointer(e.e))})},initMousedownHandler:function(){this.on("mousedown",function(e){if(this.editable&&(!e.e.button||1===e.e.button)){var b=this.canvas.getPointer(e.e); +this.__mousedownX=b.x;this.__mousedownY=b.y;this.__isMousedown=!0;this.selected&&this.setCursorByClick(e.e);this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection())}})},_isObjectMoved:function(e){e=this.canvas.getPointer(e);return this.__mousedownX!==e.x||this.__mousedownY!==e.y},initMouseupHandler:function(){this.on("mouseup",function(e){this.__isMousedown=!1;!this.editable||this._isObjectMoved(e.e)|| +e.e.button&&1!==e.e.button||(this.__lastSelected&&!this.__corner&&(this.enterEditing(e.e),this.selectionStart===this.selectionEnd?this.initDelayedCursor(!0):this.renderCursorOrSelection()),this.selected=!0)})},setCursorByClick:function(e){var b=this.getSelectionStartFromPointer(e),d=this.selectionStart,c=this.selectionEnd;e.shiftKey?this.setSelectionStartEndWithShift(d,c,b):this.selectionEnd=this.selectionStart=b;this.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(e){e= +this.getLocalPointer(e);for(var b=0,d,c=0,a=0,g,h=0,f=this._textLines.length;h<f;h++){g=this._textLines[h];c+=this._getHeightOfLine(this.ctx,h)*this.scaleY;d=this._getLineWidth(this.ctx,h);d=this._getLineLeftOffset(d)*this.scaleX;for(var l=0,k=g.length;l<k;l++)if(b=d,d+=this._getWidthOfChar(this.ctx,g[l],h,this.flipX?k-l:l)*this.scaleX,c<=e.y||d<=e.x)a++;else return this._getNewSelectionStartFromOffset(e,b,d,a+h,k);if(e.y<c)return this._getNewSelectionStartFromOffset(e,b,d,a+h-1,k)}return this.text.length}, +_getNewSelectionStartFromOffset:function(e,b,d,c,a){e=c+(d-e.x>e.x-b?0:1);this.flipX&&(e=a-e);e>this.text.length&&(e=this.text.length);return e}}); +fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea");this.hiddenTextarea.setAttribute("autocapitalize","off");this.hiddenTextarea.setAttribute("autocorrect","off");this.hiddenTextarea.setAttribute("autocomplete","off");this.hiddenTextarea.setAttribute("spellcheck","false");this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea","");this.hiddenTextarea.setAttribute("wrap","off");var e=this._calcTextareaPosition(); +this.hiddenTextarea.style.cssText="position: absolute; top: "+e.top+"; left: "+e.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; line-height: 1px; padding\uff70top: "+e.fontSize+";";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(e){if(this.isEditing){if(e.keyCode in this.keysMap)this[this.keysMap[e.keyCode]](e);else if(e.keyCode in this.ctrlKeysMapDown&&(e.ctrlKey||e.metaKey))this[this.ctrlKeysMapDown[e.keyCode]](e);else return;e.stopImmediatePropagation();e.preventDefault();33<=e.keyCode&&40>=e.keyCode?(this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.renderAll()}},onKeyUp:function(e){!this.isEditing||this._copyDone?this._copyDone=!1:e.keyCode in this.ctrlKeysMapUp&&(e.ctrlKey|| +e.metaKey)&&(this[this.ctrlKeysMapUp[e.keyCode]](e),e.stopImmediatePropagation(),e.preventDefault(),this.canvas&&this.canvas.renderAll())},onInput:function(e){if(this.isEditing&&!this.inCompositionMode){var b=this.selectionStart||0,d=this.selectionEnd||0,c=this.text.length,a=this.hiddenTextarea.value.length;a>c?(b="left"===this._selectionDirection?d:b,c=this.hiddenTextarea.value.slice(b,b+(a-c))):c=this.hiddenTextarea.value.slice(b,b+(a-c+d-b));this.insertChars(c);e.stopPropagation()}},onCompositionStart:function(){this.inCompositionMode= +!0;this.prevCompositionLength=0;this.compositionStart=this.selectionStart},onCompositionEnd:function(){this.inCompositionMode=!1},onCompositionUpdate:function(e){e=e.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(e){if(this.selectionStart===this.selectionEnd){if(this.selectionStart===this.text.length)return; +this.moveCursorRight(e)}this.removeChars(e)},copy:function(e){if(this.selectionStart!==this.selectionEnd){var b=this.getSelectedText(),d=this._getClipboardData(e);d&&d.setData("text",b);fabric.copiedText=b;fabric.copiedTextStyle=this.getSelectionStyles(this.selectionStart,this.selectionEnd);e.stopImmediatePropagation();e.preventDefault();this._copyDone=!0}},paste:function(e){var b;b=this._getClipboardData(e);var d=!0;b?(b=b.getData("text").replace(/\r/g,""),fabric.copiedTextStyle&&fabric.copiedText=== +b||(d=!1)):b=fabric.copiedText;b&&this.insertChars(b,d);e.stopImmediatePropagation();e.preventDefault()},cut:function(e){this.selectionStart!==this.selectionEnd&&(this.copy(e),this.removeChars(e))},_getClipboardData:function(e){return e&&e.clipboardData||fabric.window.clipboardData},_getWidthBeforeCursor:function(e,b){for(var d=this._textLines[e].slice(0,b),c=this._getLineWidth(this.ctx,e),c=this._getLineLeftOffset(c),a,g=0,h=d.length;g<h;g++)a=d[g],c+=this._getWidthOfChar(this.ctx,a,e,g);return c}, +getDownCursorOffset:function(e,b){var d=this._getSelectionForOffset(e,b),c=this.get2DCursorLocation(d),a=c.lineIndex;if(a===this._textLines.length-1||e.metaKey||34===e.keyCode)return this.text.length-d;d=c.charIndex;c=this._getWidthBeforeCursor(a,d);c=this._getIndexOnLine(a+1,c);return this._textLines[a].slice(d).length+c+2},_getSelectionForOffset:function(e,b){return e.shiftKey&&this.selectionStart!==this.selectionEnd&&b?this.selectionEnd:this.selectionStart},getUpCursorOffset:function(e,b){var d= +this._getSelectionForOffset(e,b),c=this.get2DCursorLocation(d),a=c.lineIndex;if(0===a||e.metaKey||33===e.keyCode)return-d;d=c.charIndex;c=this._getWidthBeforeCursor(a,d);c=this._getIndexOnLine(a-1,c);d=this._textLines[a].slice(0,d);return-this._textLines[a-1].length+c-d.length},_getIndexOnLine:function(e,b){for(var d=this._getLineWidth(this.ctx,e),c=this._textLines[e],d=this._getLineLeftOffset(d),a=0,g,h=0,f=c.length;h<f;h++){var l=this._getWidthOfChar(this.ctx,c[h],e,h),d=d+l;if(d>b){g=!0;a=Math.abs(d- +b)<Math.abs(d-l-b)?h:h-1;break}}g||(a=c.length-1);return a},moveCursorDown:function(e){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorUpOrDown("Down",e)},moveCursorUp:function(e){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",e)},_moveCursorUpOrDown:function(e,b){var d=this["get"+e+"CursorOffset"](b,"right"===this._selectionDirection);b.shiftKey?this.moveCursorWithShift(d):this.moveCursorWithoutShift(d);0!==d&&(this.setSelectionInBoundaries(), +this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(e){this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,"left"===this._selectionDirection?this.selectionStart+e:this.selectionEnd+e);return 0!==e},moveCursorWithoutShift:function(e){0>e?this.selectionEnd=this.selectionStart+=e:this.selectionStart=this.selectionEnd+=e;return 0!==e},moveCursorLeft:function(e){0===this.selectionStart&& +0===this.selectionEnd||this._moveCursorLeftOrRight("Left",e)},_move:function(e,b,d){if(e.altKey)e=this["findWordBoundary"+d](this[b]);else if(e.metaKey||35===e.keyCode||36===e.keyCode)e=this["findLineBoundary"+d](this[b]);else return this[b]+="Left"===d?-1:1,!0;if(this[b]!==e)return this[b]=e,!0},_moveLeft:function(e,b){return this._move(e,b,"Left")},_moveRight:function(e,b){return this._move(e,b,"Right")},moveCursorLeftWithoutShift:function(e){var b=!0;this._selectionDirection="left";this.selectionEnd=== +this.selectionStart&&0!==this.selectionStart&&(b=this._moveLeft(e,"selectionStart"));this.selectionEnd=this.selectionStart;return b},moveCursorLeftWithShift:function(e){if("right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd)return this._moveLeft(e,"selectionEnd");if(0!==this.selectionStart)return this._selectionDirection="left",this._moveLeft(e,"selectionStart")},moveCursorRight:function(e){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorLeftOrRight("Right", +e)},_moveCursorLeftOrRight:function(e,b){var d="moveCursor"+e+"With";this._currentCursorOpacity=1;d=b.shiftKey?d+"Shift":d+"outShift";this[d](b)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(e){if("left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd)return this._moveRight(e,"selectionStart");if(this.selectionEnd!==this.text.length)return this._selectionDirection="right",this._moveRight(e, +"selectionEnd")},moveCursorRightWithoutShift:function(e){var b=!0;this._selectionDirection="right";this.selectionStart===this.selectionEnd?(b=this._moveRight(e,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd;return b},removeChars:function(e){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(e):this._removeCharsFromTo(this.selectionStart,this.selectionEnd);this.set("dirty",!0);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(e){0!==this.selectionStart&&(e.metaKey?(e=this.findLineBoundaryLeft(this.selectionStart),this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)):e.altKey?(e=this.findWordBoundaryLeft(this.selectionStart),this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)):(this._removeSingleCharAndStyle(this.selectionStart), +this.setSelectionStart(this.selectionStart-1)))}}); +(function(){var e=fabric.util.toFixed,b=fabric.Object.NUM_FRACTION_DIGITS;fabric.util.object.extend(fabric.IText.prototype,{_setSVGTextLineText:function(b,c,a,e,h,f){this._getLineStyle(b)?this._setSVGTextLineChars(b,c,a,e,f):fabric.Text.prototype._setSVGTextLineText.call(this,b,c,a,e,h)},_setSVGTextLineChars:function(b,c,a,e,h){a=this._textLines[b];e=0;for(var d=this._getLineLeftOffset(this._getLineWidth(this.ctx,b))-this.width/2,g=this._getSVGLineTopOffset(b),k=this._getHeightOfLine(this.ctx,b), +m=0,n=a.length;m<n;m++){var p=this._getStyleDeclaration(b,m)||{};c.push(this._createTextCharSpan(a[m],p,d,g.lineTop+g.offset,e));var q=this._getWidthOfChar(this.ctx,a[m],b,m);p.textBackgroundColor&&h.push(this._createTextCharBg(p,d,g.lineTop,k,q,e));e+=q}},_getSVGLineTopOffset:function(b){for(var c=0,a=0;a<b;a++)c+=this._getHeightOfLine(this.ctx,a);b=this._getHeightOfLine(this.ctx,a);return{lineTop:c,offset:(this._fontSizeMult-this._fontSizeFraction)*b/(this.lineHeight*this._fontSizeMult)}},_createTextCharBg:function(d, +c,a,g,h,f){return['\t\t<rect fill="',d.textBackgroundColor,'" x="',e(c+f,b),'" y="',e(a-this.height/2,b),'" width="',e(h,b),'" height="',e(g/this.lineHeight,b),'"></rect>\n'].join("")},_createTextCharSpan:function(d,c,a,g,h){var f=this.getSvgStyles.call(fabric.util.object.extend({visible:!0,fill:this.fill,stroke:this.stroke,type:"text",getSvgFilter:fabric.Object.prototype.getSvgFilter},c));return['\t\t\t<tspan x="',e(a+h,b),'" y="',e(g-this.height/2,b),'" ',c.fontFamily?'font-family="'+c.fontFamily.replace(/"/g, +"'")+'" ':"",c.fontSize?'font-size="'+c.fontSize+'" ':"",c.fontStyle?'font-style="'+c.fontStyle+'" ':"",c.fontWeight?'font-weight="'+c.fontWeight+'" ':"",c.textDecoration?'text-decoration="'+c.textDecoration+'" ':"",'style="',f,'">',fabric.util.string.escapeXml(d),"</tspan>\n"].join("")}})})(); +(function(e){var b=e.fabric||(e.fabric={});b.Textbox=b.util.createClass(b.IText,b.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:2,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,noScaleCache:!1,_dimensionAffectingProps:b.Text.prototype._dimensionAffectingProps.concat("width"),initialize:function(d,c){this.callSuper("initialize",d,c);this.setControlsVisibility(b.Textbox.getTextboxControlVisibility());this.ctx=this.objectCaching?this._cacheContext:b.util.createCanvasElement().getContext("2d")}, +_initDimensions:function(d){this.__skipDimension||(d||(d=b.util.createCanvasElement().getContext("2d"),this._setTextStyles(d),this.clearContextTop()),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(d),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(d),this.setCoords())},_generateStyleMap:function(){for(var b=0,c=0,a=0,e={},h=0;h<this._textLines.length;h++)"\n"===this.text[a]&&0<h?(c=0,a++,b++):" "===this.text[a]&& +0<h&&(c++,a++),e[h]={line:b,offset:c},a+=this._textLines[h].length,c+=this._textLines[h].length;return e},_getStyleDeclaration:function(b,c,a){if(this._styleMap){var d=this._styleMap[b];if(!d)return a?{}:null;b=d.line;c=d.offset+c}return this.callSuper("_getStyleDeclaration",b,c,a)},_setStyleDeclaration:function(b,c,a){var d=this._styleMap[b];b=d.line;c=d.offset+c;this.styles[b][c]=a},_deleteStyleDeclaration:function(b,c){var a=this._styleMap[b];b=a.line;c=a.offset+c;delete this.styles[b][c]},_getLineStyle:function(b){return this.styles[this._styleMap[b].line]}, +_setLineStyle:function(b,c){this.styles[this._styleMap[b].line]=c},_deleteLineStyle:function(b){delete this.styles[this._styleMap[b].line]},_wrapText:function(b,c){var a=c.split(this._reNewline),d=[],e;for(e=0;e<a.length;e++)d=d.concat(this._wrapLine(b,a[e],e));return d},_measureText:function(b,c,a,e){var d=0;e=e||0;for(var f=0,g=c.length;f<g;f++)d+=this._getWidthOfChar(b,c[f],a,f+e);return d},_wrapLine:function(b,c,a){var d=0,e=[],f="";c=c.split(" ");for(var l,k=0,m,n=0,p=0,q=!0,t=this._getWidthOfCharSpacing(), +r=0;r<c.length;r++)l=c[r],m=this._measureText(b,l,a,k),k+=l.length,d+=n+m-t,d>=this.width&&!q?(e.push(f),f="",d=m,q=!0):d+=t,q||(f+=" "),f+=l,n=this._measureText(b," ",a,k),k++,q=!1,m>p&&(p=m);r&&e.push(f);p>this.dynamicMinWidth&&(this.dynamicMinWidth=p-t);return e},_splitTextIntoLines:function(b){b=b||this.ctx;var c=this.textAlign;this._styleMap=null;b.save();this._setTextStyles(b);this.textAlign="left";var a=this._wrapText(b,this.text);this.textAlign=c;b.restore();this._textLines=a;this._styleMap= +this._generateStyleMap();return a},setOnGroup:function(b,c){"scaleX"===b&&(this.set("scaleX",Math.abs(1/c)),this.set("width",this.get("width")*c/("undefined"===typeof this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=c)},get2DCursorLocation:function(b){"undefined"===typeof b&&(b=this.selectionStart);for(var c=this._textLines.length,a=0,d=0;d<c;d++){var e=this._textLines[d].length;if(b<=a+e)return{lineIndex:d,charIndex:b-a};a+=e;"\n"!==this.text[a]&&" "!==this.text[a]||a++}return{lineIndex:c- +1,charIndex:this._textLines[c-1].length}},_getCursorBoundariesOffsets:function(b,c){for(var a=0,d=0,e=this.get2DCursorLocation(),f=this._textLines[e.lineIndex].split(""),l=this._getLineLeftOffset(this._getLineWidth(this.ctx,e.lineIndex)),k=0;k<e.charIndex;k++)d+=this._getWidthOfChar(this.ctx,f[k],e.lineIndex,k);for(k=0;k<e.lineIndex;k++)a+=this._getHeightOfLine(this.ctx,k);"cursor"===c&&(a+=(1-this._fontSizeFraction)*this._getHeightOfLine(this.ctx,e.lineIndex)/this.lineHeight-this.getCurrentCharFontSize(e.lineIndex, +e.charIndex)*(1-this._fontSizeFraction));return{top:a,left:d,lineLeft:l}},getMinWidth:function(){return Math.max(this.minWidth,this.dynamicMinWidth)},toObject:function(b){return this.callSuper("toObject",["minWidth"].concat(b))}});b.Textbox.fromObject=function(d,c,a){return b.Object._fromObject("Textbox",d,c,a,"text")};b.Textbox.getTextboxControlVisibility=function(){return{tl:!1,tr:!1,br:!1,bl:!1,ml:!0,mt:!1,mr:!0,mb:!1,mtr:!0}}})("undefined"!==typeof exports?exports:this); +(function(){var e=fabric.Canvas.prototype._setObjectScale;fabric.Canvas.prototype._setObjectScale=function(b,d,c,a,g,h,f){var l=d.target;if(l instanceof fabric.Textbox){if(b=b.x/d.scaleX/(l.width+l.strokeWidth)*l.width,b>=l.getMinWidth())return l.set("width",b),!0}else return e.call(fabric.Canvas.prototype,b,d,c,a,g,h,f)};fabric.Group.prototype._refreshControlsVisibility=function(){if("undefined"!==typeof fabric.Textbox)for(var b=this._objects.length;b--;)if(this._objects[b]instanceof fabric.Textbox){this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility()); +break}};fabric.util.object.extend(fabric.Textbox.prototype,{_removeExtraneousStyles:function(){for(var b in this._styleMap)this._textLines[b]||delete this.styles[this._styleMap[b].line]},insertCharStyleObject:function(b,d,c){var a=this._styleMap[b];b=a.line;d=a.offset+d;fabric.IText.prototype.insertCharStyleObject.apply(this,[b,d,c])},insertNewlineStyleObject:function(b,d,c){var a=this._styleMap[b];b=a.line;d=a.offset+d;fabric.IText.prototype.insertNewlineStyleObject.apply(this,[b,d,c])},shiftLineStyles:function(b, +d){b=this._styleMap[b].line;fabric.IText.prototype.shiftLineStyles.call(this,b,d)},_getTextOnPreviousLine:function(b){for(var d=this._textLines[b-1];this._styleMap[b-2]&&this._styleMap[b-2].line===this._styleMap[b-1].line;)d=this._textLines[b-2]+d,b--;return d},removeStyleObject:function(b,d){var c=this.get2DCursorLocation(d),a=this._styleMap[c.lineIndex];this._removeStyleObject(b,c,a.line,a.offset+c.charIndex)}})})(); +(function(){var e=fabric.IText.prototype._getNewSelectionStartFromOffset;fabric.IText.prototype._getNewSelectionStartFromOffset=function(b,d,c,a,g){a=e.call(this,b,d,c,a,g);for(c=d=b=0;c<this._textLines.length;c++){b+=this._textLines[c].length;if(b+d>=a)break;"\n"!==this.text[b+d]&&" "!==this.text[b+d]||d++}return a-c+d}})(); +(function(){function e(b,d,e){var f=c.parse(b);f.port||(f.port=0===f.protocol.indexOf("https:")?443:80);b=(0===f.protocol.indexOf("https:")?g:a).request({hostname:f.hostname,port:f.port,path:f.path,method:"GET"},function(a){var b="";d&&a.setEncoding(d);a.on("end",function(){e(b)});a.on("data",function(c){200===a.statusCode&&(b+=c)})});b.on("error",function(a){a.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+f.hostname+":"+f.port):fabric.log(a.message);e(null)});b.end()} +function b(a,b){require("fs").readFile(a,function(a,c){if(a)throw fabric.log(a),a;b(c)})}if("undefined"===typeof document||"undefined"===typeof window){var d=require("xmldom").DOMParser,c=require("url"),a=require("http"),g=require("https"),h=require("canvas"),f=require("canvas").Image;fabric.util.loadImage=function(a,c,d){function g(b){b?(h.src=new Buffer(b,"binary"),h._src=a,c&&c.call(d,h)):(h=null,c&&c.call(d,null,!0))}var h=new f;a&&(a instanceof Buffer||0===a.indexOf("data"))?(h.src=h._src=a, +c&&c.call(d,h)):a&&0!==a.indexOf("http")?b(a,g):a?e(a,"binary",g):c&&c.call(d,a)};fabric.loadSVGFromURL=function(a,c,d){a=a.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim();0!==a.indexOf("http")?b(a,function(a){fabric.loadSVGFromString(a.toString(),c,d)}):e(a,"",function(a){fabric.loadSVGFromString(a,c,d)})};fabric.loadSVGFromString=function(a,b,c){a=(new d).parseFromString(a);fabric.parseSVGDocument(a.documentElement,function(a,c){b&&b(a,c)},c)};fabric.util.getScript=function(a,b){e(a,"",function(a){eval(a); +b&&b()})};fabric.createCanvasForNode=function(a,b,c,d){d=d||c;var e=fabric.document.createElement("canvas"),f=new h(a||600,b||600,d);a=new h(a||600,b||600,d);e.style={};e.width=f.width;e.height=f.height;c=c||{};c.nodeCanvas=f;c.nodeCacheCanvas=a;c=new (fabric.Canvas||fabric.StaticCanvas)(e,c);c.nodeCanvas=f;c.nodeCacheCanvas=a;c.contextContainer=f.getContext("2d");c.contextCache=a.getContext("2d");c.Font=h.Font;return c};var l=fabric.StaticCanvas.prototype._initStatic;fabric.StaticCanvas.prototype._initStatic= +function(a,b){a=a||fabric.document.createElement("canvas");this.nodeCanvas=new h(a.width,a.height);this.nodeCacheCanvas=new h(a.width,a.height);l.call(this,a,b);this.contextContainer=this.nodeCanvas.getContext("2d");this.contextCache=this.nodeCacheCanvas.getContext("2d");this.Font=h.Font};fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()};fabric.StaticCanvas.prototype.createJPEGStream=function(a){return this.nodeCanvas.createJPEGStream(a)};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 k=fabric.StaticCanvas.prototype._setBackstoreDimension;fabric.StaticCanvas.prototype._setBackstoreDimension=function(a,b){k.call(this,a,b);this.nodeCanvas[a]=b;return this};fabric.Canvas&&(fabric.Canvas.prototype._setBackstoreDimension=fabric.StaticCanvas.prototype._setBackstoreDimension)}})(); +/* pako 0.2.3 nodeca/pako */ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.pako=e()}}(function(){return function e(t,i,n){function a(s,o){if(!i[s]){if(!t[s]){var f="function"==typeof require&&require;if(!o&&f)return f(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var l=i[s]={exports:{}};t[s][0].call(l.exports,function(e){var i=t[s][1][e];return a(i?i:e)},l,l.exports,e,t,i,n)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s<n.length;s++)a(n[s]);return a}({1:[function(e,t,i){"use strict";function n(e,t){var i=new h(t);if(i.push(e,!0),i.err)throw i.msg;return i.result}function a(e,t){return t=t||{},t.raw=!0,n(e,t)}var r=e("./zlib/inflate.js"),s=e("./utils/common"),o=e("./utils/strings"),f=e("./zlib/constants"),l=e("./zlib/messages"),d=e("./zlib/zstream"),u=e("./zlib/gzheader"),h=function(e){this.options=s.assign({chunkSize:16384,windowBits:0,to:""},e||{});var t=this.options;t.raw&&t.windowBits>=0&&t.windowBits<16&&(t.windowBits=-t.windowBits,0===t.windowBits&&(t.windowBits=-15)),!(t.windowBits>=0&&t.windowBits<16)||e&&e.windowBits||(t.windowBits+=32),t.windowBits>15&&t.windowBits<48&&0===(15&t.windowBits)&&(t.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new d,this.strm.avail_out=0;var i=r.inflateInit2(this.strm,t.windowBits);if(i!==f.Z_OK)throw new Error(l[i]);this.header=new u,r.inflateGetHeader(this.strm,this.header)};h.prototype.push=function(e,t){var i,n,a,l,d,u=this.strm,h=this.options.chunkSize;if(this.ended)return!1;n=t===~~t?t:t===!0?f.Z_FINISH:f.Z_NO_FLUSH,u.input="string"==typeof e?o.binstring2buf(e):e,u.next_in=0,u.avail_in=u.input.length;do{if(0===u.avail_out&&(u.output=new s.Buf8(h),u.next_out=0,u.avail_out=h),i=r.inflate(u,f.Z_NO_FLUSH),i!==f.Z_STREAM_END&&i!==f.Z_OK)return this.onEnd(i),this.ended=!0,!1;u.next_out&&(0===u.avail_out||i===f.Z_STREAM_END||0===u.avail_in&&n===f.Z_FINISH)&&("string"===this.options.to?(a=o.utf8border(u.output,u.next_out),l=u.next_out-a,d=o.buf2string(u.output,a),u.next_out=l,u.avail_out=h-l,l&&s.arraySet(u.output,u.output,a,l,0),this.onData(d)):this.onData(s.shrinkBuf(u.output,u.next_out)))}while((u.avail_in>0||0===u.avail_out)&&i!==f.Z_STREAM_END);return i===f.Z_STREAM_END&&(n=f.Z_FINISH),n===f.Z_FINISH?(i=r.inflateEnd(this.strm),this.onEnd(i),this.ended=!0,i===f.Z_OK):!0},h.prototype.onData=function(e){this.chunks.push(e)},h.prototype.onEnd=function(e){e===f.Z_OK&&(this.result="string"===this.options.to?this.chunks.join(""):s.flattenChunks(this.chunks)),this.chunks=[],this.err=e,this.msg=this.strm.msg},i.Inflate=h,i.inflate=n,i.inflateRaw=a,i.ungzip=n},{"./utils/common":2,"./utils/strings":3,"./zlib/constants":5,"./zlib/gzheader":7,"./zlib/inflate.js":9,"./zlib/messages":11,"./zlib/zstream":12}],2:[function(e,t,i){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;i.assign=function(e){for(var t=Array.prototype.slice.call(arguments,1);t.length;){var i=t.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(var n in i)i.hasOwnProperty(n)&&(e[n]=i[n])}}return e},i.shrinkBuf=function(e,t){return e.length===t?e:e.subarray?e.subarray(0,t):(e.length=t,e)};var a={arraySet:function(e,t,i,n,a){if(t.subarray&&e.subarray)return void e.set(t.subarray(i,i+n),a);for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){var t,i,n,a,r,s;for(n=0,t=0,i=e.length;i>t;t++)n+=e[t].length;for(s=new Uint8Array(n),a=0,t=0,i=e.length;i>t;t++)r=e[t],s.set(r,a),a+=r.length;return s}},r={arraySet:function(e,t,i,n,a){for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){return[].concat.apply([],e)}};i.setTyped=function(e){e?(i.Buf8=Uint8Array,i.Buf16=Uint16Array,i.Buf32=Int32Array,i.assign(i,a)):(i.Buf8=Array,i.Buf16=Array,i.Buf32=Array,i.assign(i,r))},i.setTyped(n)},{}],3:[function(e,t,i){"use strict";function n(e,t){if(65537>t&&(e.subarray&&s||!e.subarray&&r))return String.fromCharCode.apply(null,a.shrinkBuf(e,t));for(var i="",n=0;t>n;n++)i+=String.fromCharCode(e[n]);return i}var a=e("./common"),r=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(o){r=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(o){s=!1}for(var f=new a.Buf8(256),l=0;256>l;l++)f[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;f[254]=f[254]=1,i.string2buf=function(e){var t,i,n,r,s,o=e.length,f=0;for(r=0;o>r;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),f+=128>i?1:2048>i?2:65536>i?3:4;for(t=new a.Buf8(f),s=0,r=0;f>s;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),128>i?t[s++]=i:2048>i?(t[s++]=192|i>>>6,t[s++]=128|63&i):65536>i?(t[s++]=224|i>>>12,t[s++]=128|i>>>6&63,t[s++]=128|63&i):(t[s++]=240|i>>>18,t[s++]=128|i>>>12&63,t[s++]=128|i>>>6&63,t[s++]=128|63&i);return t},i.buf2binstring=function(e){return n(e,e.length)},i.binstring2buf=function(e){for(var t=new a.Buf8(e.length),i=0,n=t.length;n>i;i++)t[i]=e.charCodeAt(i);return t},i.buf2string=function(e,t){var i,a,r,s,o=t||e.length,l=new Array(2*o);for(a=0,i=0;o>i;)if(r=e[i++],128>r)l[a++]=r;else if(s=f[r],s>4)l[a++]=65533,i+=s-1;else{for(r&=2===s?31:3===s?15:7;s>1&&o>i;)r=r<<6|63&e[i++],s--;s>1?l[a++]=65533:65536>r?l[a++]=r:(r-=65536,l[a++]=55296|r>>10&1023,l[a++]=56320|1023&r)}return n(l,a)},i.utf8border=function(e,t){var i;for(t=t||e.length,t>e.length&&(t=e.length),i=t-1;i>=0&&128===(192&e[i]);)i--;return 0>i?t:0===i?t:i+f[e[it?i:t}},{"./common":2}],4:[function(e,t){"use strict";function i(e,t,i,n){for(var a=65535&e|0,r=e>>>16&65535|0,s=0;0!==i;){s=i>2e3?2e3:i,i-=s;do a=a+t[n++]|0,r=r+a|0;while(--s);a%=65521,r%=65521}return a|r<<16|0}t.exports=i},{}],5:[function(e,t){t.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],6:[function(e,t){"use strict";function i(){for(var e,t=[],i=0;256>i;i++){e=i;for(var n=0;8>n;n++)e=1&e?3988292384^e>>>1:e>>>1;t[i]=e}return t}function n(e,t,i,n){var r=a,s=n+i;e=-1^e;for(var o=n;s>o;o++)e=e>>>8^r[255&(e^t[o])];return-1^e}var a=i();t.exports=n},{}],7:[function(e,t){"use strict";function i(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}t.exports=i},{}],8:[function(e,t){"use strict";var i=30,n=12;t.exports=function(e,t){var a,r,s,o,f,l,d,u,h,c,b,w,m,k,g,_,v,p,x,y,S,B,E,Z,A;a=e.state,r=e.next_in,Z=e.input,s=r+(e.avail_in-5),o=e.next_out,A=e.output,f=o-(t-e.avail_out),l=o+(e.avail_out-257),d=a.dmax,u=a.wsize,h=a.whave,c=a.wnext,b=a.window,w=a.hold,m=a.bits,k=a.lencode,g=a.distcode,_=(1<m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,0===x)A[o++]=65535&p;else{if(!(16&x)){if(0===(64&x)){p=k[(65535&p)+(w&(1<m&&(w+=Z[r++]<>>=x,m-=x),15>m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,!(16&x)){if(0===(64&x)){p=g[(65535&p)+(w&(1<m&&(w+=Z[r++]<m&&(w+=Z[r++]<d){e.msg="invalid distance too far back",a.mode=i;break e}if(w>>>=x,m-=x,x=o-f,S>x){if(x=S-x,x>h&&a.sane){e.msg="invalid distance too far back",a.mode=i;break e}if(B=0,E=b,0===c){if(B+=u-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}else if(x>c){if(B+=u+c-x,x-=c,y>x){y-=x;do A[o++]=b[B++];while(--x);if(B=0,y>c){x=c,y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}}else if(B+=c-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}for(;y>2;)A[o++]=E[B++],A[o++]=E[B++],A[o++]=E[B++],y-=3;y&&(A[o++]=E[B++],y>1&&(A[o++]=E[B++]))}else{B=o-S;do A[o++]=A[B++],A[o++]=A[B++],A[o++]=A[B++],y-=3;while(y>2);y&&(A[o++]=A[B++],y>1&&(A[o++]=A[B++]))}break}}break}}while(s>r&&l>o);y=m>>3,r-=y,m-=y<<3,w&=(1<r?5+(s-r):5-(r-s),e.avail_out=l>o?257+(l-o):257-(o-l),a.hold=w,a.bits=m}},{}],9:[function(e,t,i){"use strict";function n(e){return(e>>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function a(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new k.Buf16(320),this.work=new k.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function r(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=F,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new k.Buf32(bt),t.distcode=t.distdyn=new k.Buf32(wt),t.sane=1,t.back=-1,A):C}function s(e){var t;return e&&e.state?(t=e.state,t.wsize=0,t.whave=0,t.wnext=0,r(e)):C}function o(e,t){var i,n;return e&&e.state?(n=e.state,0>t?(i=0,t=-t):(i=(t>>4)+1,48>t&&(t&=15)),t&&(8>t||t>15)?C:(null!==n.window&&n.wbits!==t&&(n.window=null),n.wrap=i,n.wbits=t,s(e))):C}function f(e,t){var i,n;return e?(n=new a,e.state=n,n.window=null,i=o(e,t),i!==A&&(e.state=null),i):C}function l(e){return f(e,kt)}function d(e){if(gt){var t;for(w=new k.Buf32(512),m=new k.Buf32(32),t=0;144>t;)e.lens[t++]=8;for(;256>t;)e.lens[t++]=9;for(;280>t;)e.lens[t++]=7;for(;288>t;)e.lens[t++]=8;for(p(y,e.lens,0,288,w,0,e.work,{bits:9}),t=0;32>t;)e.lens[t++]=5;p(S,e.lens,0,32,m,0,e.work,{bits:5}),gt=!1}e.lencode=w,e.lenbits=9,e.distcode=m,e.distbits=5}function u(e,t,i,n){var a,r=e.state;return null===r.window&&(r.wsize=1<=r.wsize?(k.arraySet(r.window,t,i-r.wsize,r.wsize,0),r.wnext=0,r.whave=r.wsize):(a=r.wsize-r.wnext,a>n&&(a=n),k.arraySet(r.window,t,i-n,a,r.wnext),n-=a,n?(k.arraySet(r.window,t,i-n,n,0),r.wnext=n,r.whave=r.wsize):(r.wnext+=a,r.wnext===r.wsize&&(r.wnext=0),r.whavec;){if(0===f)break e;f--,h+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0),h=0,c=0,i.mode=D;break}if(i.flags=0,i.head&&(i.head.done=!1),!(1&i.wrap)||(((255&h)<<8)+(h>>8))%31){e.msg="incorrect header check",i.mode=ut;break}if((15&h)!==T){e.msg="unknown compression method",i.mode=ut;break}if(h>>>=4,c-=4,xt=(15&h)+8,0===i.wbits)i.wbits=xt;else if(xt>i.wbits){e.msg="invalid window size",i.mode=ut;break}i.dmax=1<c;){if(0===f)break e;f--,h+=a[s++]<>8&1),512&i.flags&&(Zt[0]=255&h,Zt[1]=h>>>8&255,i.check=_(i.check,Zt,2,0)),h=0,c=0,i.mode=U;case U:for(;32>c;){if(0===f)break e;f--,h+=a[s++]<>>8&255,Zt[2]=h>>>16&255,Zt[3]=h>>>24&255,i.check=_(i.check,Zt,4,0)),h=0,c=0,i.mode=L;case L:for(;16>c;){if(0===f)break e;f--,h+=a[s++]<>8),512&i.flags&&(Zt[0]=255&h,Zt[1]=h>>>8&255,i.check=_(i.check,Zt,2,0)),h=0,c=0,i.mode=H;case H:if(1024&i.flags){for(;16>c;){if(0===f)break e;f--,h+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0)),h=0,c=0}else i.head&&(i.head.extra=null);i.mode=M;case M:if(1024&i.flags&&(m=i.length,m>f&&(m=f),m&&(i.head&&(xt=i.head.extra_len-i.length,i.head.extra||(i.head.extra=new Array(i.head.extra_len)),k.arraySet(i.head.extra,a,s,m,xt)),512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,i.length-=m),i.length))break e;i.length=0,i.mode=K;case K:if(2048&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.name+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.name=null);i.length=0,i.mode=j;case j:if(4096&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.comment+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.comment=null);i.mode=P;case P:if(512&i.flags){for(;16>c;){if(0===f)break e;f--,h+=a[s++]<>9&1,i.head.done=!0),e.adler=i.check=0,i.mode=G;break;case q:for(;32>c;){if(0===f)break e;f--,h+=a[s++]<>>=7&c,c-=7&c,i.mode=ft;break}for(;3>c;){if(0===f)break e;f--,h+=a[s++]<>>=1,c-=1,3&h){case 0:i.mode=W;break;case 1:if(d(i),i.mode=tt,t===Z){h>>>=2,c-=2;break e}break;case 2:i.mode=V;break;case 3:e.msg="invalid block type",i.mode=ut}h>>>=2,c-=2;break;case W:for(h>>>=7&c,c-=7&c;32>c;){if(0===f)break e;f--,h+=a[s++]<>>16^65535)){e.msg="invalid stored block lengths",i.mode=ut;break}if(i.length=65535&h,h=0,c=0,i.mode=J,t===Z)break e;case J:i.mode=Q;case Q:if(m=i.length){if(m>f&&(m=f),m>l&&(m=l),0===m)break e;k.arraySet(r,a,s,m,o),f-=m,s+=m,l-=m,o+=m,i.length-=m;break}i.mode=G;break;case V:for(;14>c;){if(0===f)break e;f--,h+=a[s++]<>>=5,c-=5,i.ndist=(31&h)+1,h>>>=5,c-=5,i.ncode=(15&h)+4,h>>>=4,c-=4,i.nlen>286||i.ndist>30){e.msg="too many length or distance symbols",i.mode=ut;break}i.have=0,i.mode=$;case $:for(;i.havec;){if(0===f)break e;f--,h+=a[s++]<>>=3,c-=3}for(;i.have<19;)i.lens[At[i.have++]]=0;if(i.lencode=i.lendyn,i.lenbits=7,St={bits:i.lenbits},yt=p(x,i.lens,0,19,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid code lengths set",i.mode=ut;break}i.have=0,i.mode=et;case et:for(;i.have>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,h+=a[s++]<gt)h>>>=mt,c-=mt,i.lens[i.have++]=gt;else{if(16===gt){for(Bt=mt+2;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=mt,c-=mt,0===i.have){e.msg="invalid bit length repeat",i.mode=ut;break}xt=i.lens[i.have-1],m=3+(3&h),h>>>=2,c-=2}else if(17===gt){for(Bt=mt+3;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=mt,c-=mt,xt=0,m=3+(7&h),h>>>=3,c-=3}else{for(Bt=mt+7;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=mt,c-=mt,xt=0,m=11+(127&h),h>>>=7,c-=7}if(i.have+m>i.nlen+i.ndist){e.msg="invalid bit length repeat",i.mode=ut;break}for(;m--;)i.lens[i.have++]=xt}}if(i.mode===ut)break;if(0===i.lens[256]){e.msg="invalid code -- missing end-of-block",i.mode=ut;break}if(i.lenbits=9,St={bits:i.lenbits},yt=p(y,i.lens,0,i.nlen,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid literal/lengths set",i.mode=ut;break}if(i.distbits=6,i.distcode=i.distdyn,St={bits:i.distbits},yt=p(S,i.lens,i.nlen,i.ndist,i.distcode,0,i.work,St),i.distbits=St.bits,yt){e.msg="invalid distances set",i.mode=ut;break}if(i.mode=tt,t===Z)break e;case tt:i.mode=it;case it:if(f>=6&&l>=258){e.next_out=o,e.avail_out=l,e.next_in=s,e.avail_in=f,i.hold=h,i.bits=c,v(e,w),o=e.next_out,r=e.output,l=e.avail_out,s=e.next_in,a=e.input,f=e.avail_in,h=i.hold,c=i.bits,i.mode===G&&(i.back=-1);break}for(i.back=0;Et=i.lencode[h&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,h+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,h+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(h>>>=mt,c-=mt,i.back+=mt,i.length=gt,0===kt){i.mode=ot;break}if(32&kt){i.back=-1,i.mode=G;break}if(64&kt){e.msg="invalid literal/length code",i.mode=ut;break}i.extra=15&kt,i.mode=nt;case nt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}i.was=i.length,i.mode=at;case at:for(;Et=i.distcode[h&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,h+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,h+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(h>>>=mt,c-=mt,i.back+=mt,64&kt){e.msg="invalid distance code",i.mode=ut;break}i.offset=gt,i.extra=15&kt,i.mode=rt;case rt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}if(i.offset>i.dmax){e.msg="invalid distance too far back",i.mode=ut;break}i.mode=st;case st:if(0===l)break e;if(m=w-l,i.offset>m){if(m=i.offset-m,m>i.whave&&i.sane){e.msg="invalid distance too far back",i.mode=ut;break}m>i.wnext?(m-=i.wnext,bt=i.wsize-m):bt=i.wnext-m,m>i.length&&(m=i.length),wt=i.window}else wt=r,bt=o-i.offset,m=i.length;m>l&&(m=l),l-=m,i.length-=m;do r[o++]=wt[bt++];while(--m);0===i.length&&(i.mode=it);break;case ot:if(0===l)break e;r[o++]=i.length,l--,i.mode=it;break;case ft:if(i.wrap){for(;32>c;){if(0===f)break e;f--,h|=a[s++]<c;){if(0===f)break e;f--,h+=a[s++]<=z;z++)M[z]=0;for(R=0;b>R;R++)M[t[c+R]]++;for(I=A,N=n;N>=1&&0===M[N];N--);if(I>N&&(I=N),0===N)return w[m++]=20971520,w[m++]=20971520,g.bits=1,0;for(C=1;N>C&&0===M[C];C++);for(C>I&&(I=C),F=1,z=1;n>=z;z++)if(F<<=1,F-=M[z],0>F)return-1;if(F>0&&(e===s||1!==N))return-1;for(K[1]=0,z=1;n>z;z++)K[z+1]=K[z]+M[z];for(R=0;b>R;R++)0!==t[c+R]&&(k[K[t[c+R]]++]=R);switch(e){case s:L=j=k,S=19;break;case o:L=l,H-=257,j=d,P-=257,S=256;break;default:L=u,j=h,S=-1}if(U=0,R=0,z=C,y=m,O=I,T=0,p=-1,D=1<a||e===f&&D>r)return 1;for(var q=0;;){q++,B=z-T,k[R]S?(E=j[P+k[R]],Z=L[H+k[R]]):(E=96,Z=0),_=1<>T)+v]=B<<24|E<<16|Z|0;while(0!==v);for(_=1<>=1;if(0!==_?(U&=_-1,U+=_):U=0,R++,0===--M[z]){if(z===N)break;z=t[c+k[R]]}if(z>I&&(U&x)!==p){for(0===T&&(T=I),y+=C,O=z-T,F=1<O+T&&(F-=M[O+T],!(0>=F));)O++,F<<=1;if(D+=1<a||e===f&&D>r)return 1;p=U&x,w[p]=I<<24|O<<16|y-m|0}}return 0!==U&&(w[y+U]=z-T<<24|64<<16|0),g.bits=I,0}},{"../utils/common":2}],11:[function(e,t){"use strict";t.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],12:[function(e,t){"use strict";function i(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}t.exports=i},{}]},{},[1])(1)});/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ var saveAs=saveAs||"undefined"!=typeof navigator&&navigator.msSaveOrOpenBlob&&navigator.msSaveOrOpenBlob.bind(navigator)||function(e){"use strict";if("undefined"==typeof navigator||!/MSIE [1-9]\./.test(navigator.userAgent)){var t=e.document,n=function(){return e.URL||e.webkitURL||e},o=t.createElementNS("http://www.w3.org/1999/xhtml","a"),r="download"in o,i=function(n){var o=t.createEvent("MouseEvents");o.initMouseEvent("click",!0,!1,e,0,0,0,0,0,!1,!1,!1,!1,0,null),n.dispatchEvent(o)},a=e.webkitRequestFileSystem,c=e.requestFileSystem||a||e.mozRequestFileSystem,s=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},u="application/octet-stream",f=0,d=500,l=function(t){var o=function(){"string"==typeof t?n().revokeObjectURL(t):t.remove()};e.chrome?o():setTimeout(o,d)},v=function(e,t,n){t=[].concat(t);for(var o=t.length;o--;){var r=e["on"+t[o]];if("function"==typeof r)try{r.call(e,n||e)}catch(i){s(i)}}},p=function(t,s){var d,p,w,y=this,m=t.type,S=!1,h=function(){v(y,"writestart progress write writeend".split(" "))},O=function(){if((S||!d)&&(d=n().createObjectURL(t)),p)p.location.href=d;else{var o=e.open(d,"_blank");void 0==o&&"undefined"!=typeof safari&&(e.location.href=d)}y.readyState=y.DONE,h(),l(d)},b=function(e){return function(){return y.readyState!==y.DONE?e.apply(this,arguments):void 0}},g={create:!0,exclusive:!1};return y.readyState=y.INIT,s||(s="download"),r?(d=n().createObjectURL(t),o.href=d,o.download=s,i(o),y.readyState=y.DONE,h(),void l(d)):(/^\s*(?:text\/(?:plain|xml)|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(t.type)&&(t=new Blob(["",t],{type:t.type})),e.chrome&&m&&m!==u&&(w=t.slice||t.webkitSlice,t=w.call(t,0,t.size,u),S=!0),a&&"download"!==s&&(s+=".download"),(m===u||a)&&(p=e),c?(f+=t.size,void c(e.TEMPORARY,f,b(function(e){e.root.getDirectory("saved",g,b(function(e){var n=function(){e.getFile(s,g,b(function(e){e.createWriter(b(function(n){n.onwriteend=function(t){p.location.href=e.toURL(),y.readyState=y.DONE,v(y,"writeend",t),l(e)},n.onerror=function(){var e=n.error;e.code!==e.ABORT_ERR&&O()},"writestart progress write abort".split(" ").forEach(function(e){n["on"+e]=y["on"+e]}),n.write(t),y.abort=function(){n.abort(),y.readyState=y.DONE},y.readyState=y.WRITING}),O)}),O)};e.getFile(s,{create:!1},b(function(e){e.remove(),n()}),b(function(e){e.code===e.NOT_FOUND_ERR?n():O()}))}),O)}),O)):void O())},w=p.prototype,y=function(e,t){return new p(e,t)};return w.abort=function(){var e=this;e.readyState=e.DONE,v(e,"abort")},w.readyState=w.INIT=0,w.WRITING=1,w.DONE=2,w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null,y}}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this.content);"undefined"!=typeof module&&module.exports?module.exports.saveAs=saveAs:"undefined"!=typeof define&&null!==define&&null!=define.amd&&define([],function(){return saveAs});/* canvas-toBlob.js * A canvas.toBlob() implementation. diff --git a/js9support.js b/js9support.js index ba63deda..c581e267 100644 --- a/js9support.js +++ b/js9support.js @@ -47825,6 +47825,10 @@ fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.Stati else { return this.minScaleLimit; } + } else if (value !== value) { + return this.minScaleLimit; + } else if (value === 0) { + return 1e-4; } return value; }, diff --git a/js9support.min.js b/js9support.min.js index f60a21d6..379707f1 100644 --- a/js9support.min.js +++ b/js9support.min.js @@ -219,7 +219,562 @@ b)},cleanup:function(){for(var a=0;a-1},complexity:function(){return this.getObjects().reduce(function(t,e){return t+=e.complexity?e.complexity():0},0)}},fabric.CommonMethods={_setOptions:function(t){for(var e in t)this.set(e,t[e])},_initGradient:function(t,e){!t||!t.colorStops||t instanceof fabric.Gradient||this.set(e,new fabric.Gradient(t))},_initPattern:function(t,e,i){!t||!t.source||t instanceof fabric.Pattern?i&&i():this.set(e,new fabric.Pattern(t,i))},_initClipping:function(t){if(t.clipTo&&"string"==typeof t.clipTo){var e=fabric.util.getFunctionBody(t.clipTo);void 0!==e&&(this.clipTo=new Function("ctx",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,e){this[t]=e},toggle:function(t){var e=this.get(t);return"boolean"==typeof e&&this.set(t,!e),this},get:function(t){return this[t]}},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-1!==i&&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);return{x:t.x*r-t.y*i,y:t.x*i+t.y*r}},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);return{left:i,top:o,width:n,height:Math.abs(o-a)}},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])>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--;)n="set"+(r=(i=o.stateProperties[e]).charAt(0).toUpperCase()+i.slice(1)),o[s="get"+r]||(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?P-=2*f:1===c&&P<0&&(P+=2*f);for(var E=Math.ceil(Math.abs(P/f*2)),I=[],L=P/E,F=8/3*Math.sin(L/4)*Math.sin(L/4)/Math.sin(L/2),B=A+L,R=0;R=n?s-n:2*Math.PI-(n-s)}function i(t,e,i,r,n,a,h,c){var l=o.call(arguments);if(s[l])return s[l];var u,f,d,g,p,v,b,m,_=Math.sqrt,y=Math.min,x=Math.max,C=Math.abs,S=[],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*a,u=-3*e+9*r-9*a+3*c,d=3*r-3*e),C(u)<1e-12){if(C(f)<1e-12)continue;0<(g=-d/f)&&g<1&&S.push(g)}else(b=f*f-4*d*u)<0||(0<(p=(-f+(m=_(b)))/(2*u))&&p<1&&S.push(p),0<(v=(-f-m)/(2*u))&&v<1&&S.push(v));for(var T,j,k,M=S.length,D=M;M--;)T=(k=1-(g=S[M]))*k*k*t+3*k*k*g*i+3*k*g*g*n+g*g*g*h,w[0][M]=T,j=k*k*k*e+3*k*k*g*r+3*k*g*g*a+g*g*g*c,w[1][M]=j;w[0][D]=t,w[1][D]=e,w[0][D+1]=h,w[1][D+1]=c;var A=[{x:y.apply(null,w[0]),y:y.apply(null,w[1])},{x:x.apply(null,w[0]),y:x.apply(null,w[1])}];return s[l]=A,A}var r={},n={},s={},o=Array.prototype.join;fabric.util.drawArc=function(e,i,r,n){for(var s=n[0],o=n[1],a=n[2],h=n[3],c=n[4],l=[[],[],[],[]],u=t(n[5]-i,n[6]-r,s,o,h,c,a),f=0,d=u.length;f>>0;if(0===i)return-1;var r=0;if(arguments.length>0&&((r=Number(arguments[1]))!=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=e})}}}(),function(){function t(e,i,r){if(r)if(!fabric.isLikelyNode&&i instanceof Element)e=i;else if(i instanceof Array){e=[];for(var n=0,s=i.length;n/g,">")}}}(),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){for(var e=null,r=this;r.constructor.superclass;){var n=r.constructor.superclass.prototype[t];if(r[t]!==n){e=n;break}r=r.constructor.superclass.prototype}return e?arguments.length>1?e.apply(this,i.call(arguments,1)):e.call(this):console.log("tried to callSuper "+t+", method not found in prototype chain",this)}var i=Array.prototype.slice,r=function(){},n=function(){for(var t in{toString:1})if("toString"===t)return!1;return!0}(),s=function(t,e,i){for(var r in e)r in t.prototype&&"function"==typeof t.prototype[r]&&(e[r]+"").indexOf("callSuper")>-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],n&&(e.toString!==Object.prototype.toString&&(t.prototype.toString=e.toString),e.valueOf!==Object.prototype.valueOf&&(t.prototype.valueOf=e.valueOf))};fabric.util.createClass=function(){function n(){this.initialize.apply(this,arguments)}var o=null,a=i.call(arguments,0);"function"==typeof a[0]&&(o=a.shift()),n.superclass=o,n.subclasses=[],o&&(t.prototype=o.prototype,n.prototype=new t,o.subclasses.push(n));for(var h=0,c=a.length;h=.9999?"":"alpha(opacity="+100*e+")",i.filter=i.filter.replace(r,e)):i.filter+=" alpha(opacity="+100*e+")",t}),fabric.util.setStyle=function(t,e){var i=t.style;if(!i)return t;if("string"==typeof e)return t.style.cssText+=";"+e,e.indexOf("opacity")>-1?n(t,e.match(/opacity:\s*(\d?\.?\d*)/)[1]):t;for(var r in e)"opacity"===r?n(t,e[r]):i["float"===r||"cssFloat"===r?void 0===i.styleFloat?"cssFloat":"styleFloat":r]=e[r];return t}}(),function(){function t(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 e(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)===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}}var i,r=Array.prototype.slice,n=function(t){return r.call(t,0)};try{i=n(fabric.document.childNodes)instanceof Array}catch(t){}i||(n=function(t){for(var e=new Array(t.length),i=t.length;i--;)e[i]=t[i];return e});var s;s=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(){var t=fabric.document.documentElement.style,e="userSelect"in t?"userSelect":"MozUserSelect"in t?"MozUserSelect":"WebkitUserSelect"in t?"WebkitUserSelect":"KhtmlUserSelect"in t?"KhtmlUserSelect":"";fabric.util.makeElementUnselectable=function(t){return void 0!==t.onselectstart&&(t.onselectstart=fabric.util.falseFunction),e?t.style[e]="none":"string"==typeof t.unselectable&&(t.unselectable="on"),t},fabric.util.makeElementSelectable=function(t){return void 0!==t.onselectstart&&(t.onselectstart=null),e?t.style[e]="":"string"==typeof t.unselectable&&(t.unselectable=""),t}}(),function(){fabric.util.getScript=function(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.getById=function(t){return"string"==typeof t?fabric.document.getElementById(t):t},fabric.util.toArray=n,fabric.util.makeElement=t,fabric.util.addClass=function(t,e){t&&-1===(" "+t.className+" ").indexOf(" "+e+" ")&&(t.className+=(t.className?" ":"")+e)},fabric.util.wrapElement=function(e,i,r){return"string"==typeof i&&(i=t(i,r)),e.parentNode&&e.parentNode.replaceChild(i,e),i.appendChild(e),i},fabric.util.getScrollLeftTop=e,fabric.util.getElementOffset=function(t){var i,r,n=t&&t.ownerDocument,o={left:0,top:0},a={left:0,top:0},h={borderLeftWidth:"left",borderTopWidth:"top",paddingLeft:"left",paddingTop:"top"};if(!n)return a;for(var c in h)a[h[c]]+=parseInt(s(t,c),10)||0;return i=n.documentElement,void 0!==t.getBoundingClientRect&&(o=t.getBoundingClientRect()),r=e(t),{left:o.left+r.left-(i.clientLeft||0)+a.left,top:o.top+r.top-(i.clientTop||0)+a.top}},fabric.util.getElementStyle=s}(),function(){function t(){}var e=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{if(t[e]())return t[e]}catch(t){}}();fabric.util.request=function(i,r){r||(r={});var n=r.method?r.method.toUpperCase():"GET",s=r.onComplete||function(){},o=e(),a=r.body||r.parameters;return o.onreadystatechange=function(){4===o.readyState&&(s(o),o.onreadystatechange=t)},"GET"===n&&(a=null,"string"==typeof r.parameters&&(i=function(t,e){return t+(/\?/.test(t)?"&":"?")+e}(i,r.parameters))),o.open(n,i,!0),"POST"!==n&&"PUT"!==n||o.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),o.send(a),o}}(),fabric.log=function(){},fabric.warn=function(){},"undefined"!=typeof console&&["log","warn"].forEach(function(t){void 0!==console[t]&&"function"==typeof console[t].apply&&(fabric[t]=function(){return console[t].apply(console,arguments)})}),function(){function t(){return!1}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=function(i){e(function(r){i||(i={});var n,s=r||+new Date,o=i.duration||500,a=s+o,h=i.onChange||t,c=i.abort||t,l=i.onComplete||t,u=i.easing||function(t,e,i,r){return-i*Math.cos(t/r*(Math.PI/2))+i+e},f="startValue"in i?i.startValue:0,d="endValue"in i?i.endValue:100,g=i.byValue||d-f;i.onStart&&i.onStart(),function t(r){if(c())l(d,1,1);else{var p=(n=r||+new Date)>a?o:n-s,v=p/o,b=u(p,f,g,o),m=Math.abs((b-f)/g);h(b,m,v),n>a?i.onComplete&&i.onComplete():e(t)}}(s)})},fabric.util.requestAnimFrame=e}(),function(){fabric.util.animateColor=function(t,e,i,r){var n=new fabric.Color(t).getSource(),s=new fabric.Color(e).getSource();r=r||{},fabric.util.animate(fabric.util.object.extend(r,{duration:i||500,startValue:n,endValue:s,byValue:s,easing:function(t,e,i,n){return function(t,e,i){var r="rgba("+parseInt(t[0]+i*(e[0]-t[0]),10)+","+parseInt(t[1]+i*(e[1]-t[1]),10)+","+parseInt(t[2]+i*(e[2]-t[2]),10);return r+=","+(t&&e?parseFloat(t[3]+i*(e[3]-t[3])):1),r+=")"}(e,i,r.colorEasing?r.colorEasing(t,n):1-Math.cos(t/n*(Math.PI/2)))}}))}}(),function(){function t(t,e,i,r){return ta?a:o),1===o&&1===a&&0===c&&0===l&&0===g&&0===v)return C;if((g||v)&&(S=" translate("+f(g)+" "+f(v)+") "),r=S+" matrix("+o+" 0 0 "+a+" "+c*o+" "+l*a+") ","svg"===t.nodeName){for(n=t.ownerDocument.createElement("g");t.firstChild;)n.appendChild(t.firstChild);t.appendChild(n)}else r=(n=t).getAttribute("transform")+r;return n.setAttribute("transform",r),C}var h=t.fabric||(t.fabric={}),c=h.util.object.extend,l=h.util.object.clone,u=h.util.toFixed,f=h.util.parseUnit,d=h.util.multiplyTransformMatrices,g=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i,p=/^(symbol|image|marker|pattern|view|svg)$/i,v=/^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i,b=/^(symbol|g|a|svg)$/i,m={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",opacity:"opacity"},_={stroke:"strokeOpacity",fill:"fillOpacity"};h.cssRules={},h.gradientDefs={},h.parseTransformAttribute=function(){function t(t,e,i){t[i]=Math.tan(h.util.degreesToRadians(e[0]))}var e=[1,0,0,1,0,0],i=h.reNum,r="(?:\\s+,?\\s*|,\\s*)",n="(?:"+("(?:(matrix)\\s*\\(\\s*("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")"+r+"("+i+")\\s*\\))")+"|"+("(?:(translate)\\s*\\(\\s*("+i+")(?:"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(scale)\\s*\\(\\s*("+i+")(?:"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(rotate)\\s*\\(\\s*("+i+")(?:"+r+"("+i+")"+r+"("+i+"))?\\s*\\))")+"|"+("(?:(skewX)\\s*\\(\\s*("+i+")\\s*\\))")+"|"+("(?:(skewY)\\s*\\(\\s*("+i+")\\s*\\))")+")",s="^\\s*(?:"+("(?:"+n+"(?:"+r+"*"+n+")*)")+"?)\\s*$",o=new RegExp(s),a=new RegExp(n,"g");return function(i){var r=e.concat(),s=[];if(!i||i&&!o.test(i))return r;i.replace(a,function(i){var o=new RegExp(n).exec(i).filter(function(t){return!!t}),a=o[1],c=o.slice(2).map(parseFloat);switch(a){case"translate":!function(t,e){t[4]=e[0],2===e.length&&(t[5]=e[1])}(r,c);break;case"rotate":c[0]=h.util.degreesToRadians(c[0]),function(t,e){var i=Math.cos(e[0]),r=Math.sin(e[0]),n=0,s=0;3===e.length&&(n=e[1],s=e[2]),t[0]=i,t[1]=r,t[2]=-r,t[3]=i,t[4]=n-(i*n-r*s),t[5]=s-(r*n+i*s)}(r,c);break;case"scale":!function(t,e){var i=e[0],r=2===e.length?e[1]:e[0];t[0]=i,t[3]=r}(r,c);break;case"skewX":t(r,c,2);break;case"skewY":t(r,c,1);break;case"matrix":r=c}s.push(r.concat()),r=e.concat()});for(var c=s[0];s.length>1;)s.shift(),c=h.util.multiplyTransformMatrices(c,s[0]);return c}}();var y=new RegExp("^\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*,?\\s*("+h.reNum+"+)\\s*$");h.parseSVGDocument=function(t,e,i,n){if(t){!function(t){for(var e=r(t,["use","svg:use"]),i=0;e.length&&i/i,""))),n&&n.documentElement||e&&e(null),h.parseSVGDocument(n.documentElement,function(t,i){e&&e(t,i)},i,r)}})},loadSVGFromString:function(t,e,i,r){t=t.trim();var n;if("undefined"!=typeof DOMParser){var s=new DOMParser;s&&s.parseFromString&&(n=s.parseFromString(t,"text/xml"))}else h.window.ActiveXObject&&((n=new ActiveXObject("Microsoft.XMLDOM")).async="false",n.loadXML(t.replace(//i,"")));h.parseSVGDocument(n.documentElement,function(t,i){e(t,i)},i,r)}})}("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,i){return void 0===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={});i.Intersection?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")).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},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={});r.Color?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,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}var i=fabric.util.object.clone;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:parseFloat(e),color:i.toRgb(),opacity:i.getAlpha()})}return this},toObject:function(t){var e={type:this.type,coords:this.coords,colorStops:this.colorStops,offsetX:this.offsetX,offsetY:this.offsetY,gradientTransform:this.gradientTransform?this.gradientTransform.concat():this.gradientTransform};return fabric.util.populateWithProperties(this,e,t),e},toSVG:function(t){var e,r,n=i(this.coords,!0),s=i(this.colorStops,!0),o=n.r1>n.r2;if(s.sort(function(t,e){return t.offset-e.offset}),!t.group||"path-group"!==t.group.type)for(var a in n)"x1"===a||"x2"===a?n[a]+=this.offsetX-t.width/2:"y1"!==a&&"y2"!==a||(n[a]+=this.offsetY-t.height/2);if(r='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"',this.gradientTransform&&(r+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" '),"linear"===this.type?e=["\n']:"radial"===this.type&&(e=["\n']),"radial"===this.type){if(o){(s=s.concat()).reverse();for(l=0;l0)for(var c=h/Math.max(n.r1,n.r2),l=0;l\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'},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 e=t.fabric||(t.fabric={}),i=e.util.toFixed;e.Shadow?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)||[];return{color:(i.replace(e.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").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));return t.width&&t.height&&(r=100*i((Math.abs(o.x)+this.blur)/t.width,s)+20,n=100*i((Math.abs(o.y)+this.blur)/t.height,s)+20),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}}),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)fabric.warn("fabric.StaticCanvas is already defined.");else{var t=fabric.util.object.extend,e=fabric.util.getElementOffset,i=fabric.util.removeFromArray,r=fabric.util.toFixed,n=fabric.util.transformPoint,s=fabric.util.invertTransform,o=new Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(t,e){e||(e={}),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:!1,_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){return this[t]=e,this._initGradient(e,t),this._initPattern(e,t,i),this},_createCanvasElement:function(t){var e=fabric.util.createCanvasElement(t);if(e.style||(e.style={}),!e)throw o;if(void 0===e.getContext)throw o;return e},_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){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 this.viewportTransform[0]},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","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),"\n")},createSVGRefElementsMarkup:function(){var t=this;return["backgroundColor","overlayColor"].map(function(e){var i=t[e];if(i&&i.toLive)return i.toSVG(t,!1)}).join("")},createSVGFontFacesMarkup:function(){for(var t,e,i,r,n,s,o="",a={},h=fabric.fontPaths,c=this.getObjects(),l=0,u=c.length;l',"\n",o,"","\n"].join("")),o},_setSVGObjects:function(t,e){for(var i,r=0,n=this.getObjects(),s=n.length;r\n")}else t.push('\n")},sendToBack:function(t){if(!t)return this;var e,r,n,s=this._activeGroup;if(t===s)for(e=(n=s._objects).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;e0+c&&(o=s-1,i(this._objects,n),this._objects.splice(o,0,n)),c++;else 0!==(s=this._objects.indexOf(t))&&(o=this._findNewLowerIndex(t,s,e),i(this._objects,t),this._objects.splice(o,0,t));return this.renderAll&&this.renderAll(),this},_findNewLowerIndex:function(t,e,i){var r;if(i){r=e;for(var n=e-1;n>=0;--n){if(t.intersectsWithObject(this._objects[n])||t.isContainedWithinObject(this._objects[n])||this._objects[n].isContainedWithinObject(t)){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,c=0;if(t===h)for(r=(a=h._objects).length;r--;)n=a[r],(s=this._objects.indexOf(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 void 0!==i.getImageData;case"setLineDash":return void 0!==i.setLineDash;case"toDataURL":return void 0!==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,e=this.canvas.getZoom();t.shadowColor=this.shadow.color,t.shadowBlur=this.shadow.blur*e,t.shadowOffsetX=this.shadow.offsetX*e,t.shadowOffsetY=this.shadow.offsetY*e}},_resetShadow:function(){var t=this.canvas.contextTop;t.shadowColor="",t.shadowBlur=t.shadowOffsetX=t.shadowOffsetY=0}}),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.length>1&&t.eq(this._points[this._points.length-1])||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,e,i=this.canvas.contextTop,r=this.canvas.viewportTransform,n=this._points[0],s=this._points[1];if(i.save(),i.transform(r[0],r[1],r[2],r[3],r[4],r[5]),i.beginPath(),2===this._points.length&&n.x===s.x&&n.y===s.y){var o=this.width/1e3;n=new fabric.Point(n.x,n.y),s=new fabric.Point(s.x,s.y),n.x-=o,s.x+=o}for(i.moveTo(n.x,n.y),t=1,e=this._points.length;t2;for(c&&(a=t[2].xt[e-2].x?1:n.x===t[e-2].x?0:-1,h=n.y>t[e-2].y?1:n.y===t[e-2].y?0:-1),i.push("L ",n.x+a*r," ",n.y+h*r),i},createPath:function(t){var e=new fabric.Path(t,{fill:null,stroke:this.color,strokeWidth:this.width,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeDashArray:this.strokeDashArray,originX:"center",originY:"center"}),i=new fabric.Point(e.left,e.top);return e.originX=fabric.Object.prototype.originX,e.originY=fabric.Object.prototype.originY,i=e.translateToGivenOrigin(i,"center","center",e.originX,e.originY),e.top=i.y,e.left=i.x,this.shadow&&(this.shadow.affectStroke=!0,e.setShadow(this.shadow)),e},_finalizeAndAddPath:function(){this.canvas.contextTop.closePath();var t=this.convertPointsToSVGPath(this._points).join("");if("M 0 0 Q 0 0 0 0 L 0 0"!==t){var e=this.createPath(t);this.canvas.add(e),e.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire("path:created",{path:e})}else this.canvas.renderAll()}}),fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(t){this.canvas=t,this.points=[]},drawDot:function(t){var e=this.addPoint(t),i=this.canvas.contextTop,r=this.canvas.viewportTransform;i.save(),i.transform(r[0],r[1],r[2],r[3],r[4],r[5]),i.fillStyle=e.fill,i.beginPath(),i.arc(e.x,e.y,e.radius,0,2*Math.PI,!1),i.closePath(),i.fill(),i.restore()},onMouseDown:function(t){this.points.length=0,this.canvas.clearContext(this.canvas.contextTop),this._setShadow(),this.drawDot(t)},onMouseMove:function(t){this.drawDot(t)},onMouseUp:function(){var t=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var e=[],i=0,r=this.points.length;i0?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])<=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&&cs?t.x<0?t.x+=s:t.x-=s:t.x=0,n(t.y)>s?t.y<0?t.y+=s:t.y-=s: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),h=!0;if(n.target.snapAngle>0){var c=n.target.snapAngle,l=n.target.snapThreshold||c,u=Math.ceil(a/c)*c,f=Math.floor(a/c)*c;Math.abs(a-f)0?0:-i),e.ey-(r>0?0:-r),o,a)),this.selectionLineWidth&&this.selectionBorderColor)if(t.lineWidth=this.selectionLineWidth,t.strokeStyle=this.selectionBorderColor,this.selectionDashArray.length>1&&!s){var h=e.ex+.5-(i>0?0:o),c=e.ey+.5-(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 fabric.Object.prototype._setLineDash.call(this,t,this.selectionDashArray),t.strokeRect(e.ex+.5-(i>0?0:o),e.ey+.5-(r>0?0:a),o,a)},findTarget:function(t,e){if(!this.skipTargetFind){var i,r,n=this.getPointer(t,!0),s=this.getActiveGroup(),o=this.getActiveObject();if(this.targets=[],s&&!e&&s===this._searchPossibleTargets([s],n))return this._fireOverOutEvents(s,t),s;if(o&&o._findTargetCorner(n))return this._fireOverOutEvents(o,t),o;if(o&&o===this._searchPossibleTargets([o],n)){if(!this.preserveObjectStacking)return this._fireOverOutEvents(o,t),o;i=o,r=this.targets,this.targets=[]}var a=this._searchPossibleTargets(this._objects,n);return t[this.altSelectionKey]&&a&&i&&a!==i&&(a=i,this.targets=r),this._fireOverOutEvents(a,t),a}},_fireOverOutEvents:function(t,e){var i,r,n=this._hoveredTarget;n!==t&&(i={e:e,target:t,previousTarget:this._hoveredTarget},r={e:e,target:this._hoveredTarget,nextTarget:t},this._hoveredTarget=t),t?n!==t&&(n&&(this.fire("mouse:out",r),n.fire("mouseout",r)),this.fire("mouse:over",i),t.fire("mouseover",i)):n&&(this.fire("mouse:out",r),n.fire("mouseout",r))},_checkTarget:function(t,e){if(e&&e.visible&&e.evented&&this.containsPoint(null,e,t)){if(!this.perPixelTargetFind&&!e.perPixelTargetFind||e.isEditing)return!0;if(!this.isTargetTransparent(e,t.x,t.y))return!0}},_searchPossibleTargets:function(t,e){for(var i,r,n,s=t.length;s--;)if(this._checkTarget(e,t[s])){"group"===(i=t[s]).type&&i.subTargetCheck&&(r=this._normalizePointer(i,e),(n=this._searchPossibleTargets(i._objects,r))&&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.upperCanvasEl.className="":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,"touch-action":"none"}),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){var e=this._activeObject;e&&(e.set("active",!1),t!==e&&e.onDeselect&&"function"==typeof e.onDeselect&&e.onDeselect()),this._activeObject=t,t.set("active",!0)},setActiveObject:function(t,e){var i=this.getActiveObject();return i&&i!==t&&i.fire("deselected",{e:e}),this._setActiveObject(t),this.fire("object:selected",{target:t,e:e}),t.fire("selected",{e:e}),this.renderAll(),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._hoveredTarget===t&&(this._hoveredTarget=null),this.callSuper("_onObjectRemoved",t)},_discardActiveObject:function(){var t=this._activeObject;t&&(t.set("active",!1),t.onDeselect&&"function"==typeof t.onDeselect&&t.onDeselect()),this._activeObject=null},discardActiveObject:function(t){var e=this._activeObject;return e&&(this.fire("before:selection:cleared",{target:e,e:t}),this._discardActiveObject(),this.fire("selection:cleared",{e:t}),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 e&&(this.fire("before:selection:cleared",{e:t,target:e}),this._discardActiveGroup(),this.fire("selection:cleared",{e:t})),this},deactivateAll:function(){for(var t,e=this.getObjects(),i=0,r=e.length;i1)){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||null)}},__onMouseWheel:function(t){this._handleEvent(t,"wheel")},_transformObject:function(t){var e=this.getPointer(t),i=this._currentTransform;i.reset=!1,i.target.isMoving=!0,i.shiftKey=t.shiftKey,i.altKey=t[this.centeredKey],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))&&(this._fire("moving",s,t),this.setCursor(s.moveCursor||this.moveCursor)),e.actionPerformed=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,r=this.getActiveGroup(),n=e._findTargetCorner&&(!r||!r.contains(e))&&e._findTargetCorner(this.getPointer(t,!0));return n?this._setCornerCursor(n,e,t):this.setCursor(i),!0},_setCornerCursor:function(t,i,r){if(t in e)this.setCursor(this._getRotatedCornerCursor(t,i,r));else{if("mtr"!==t||!i.hasRotatingPoint)return this.setCursor(this.defaultCursor),!1;this.setCursor(this.rotationCursor)}},_getRotatedCornerCursor:function(t,i,r){var n=Math.round(i.getAngle()%360/45);return n<0&&(n+=8),n+=e[t],r[this.altActionKey]&&e[t]%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),e)}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,e),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})).addWithUpdate(),this.setActiveGroup(e,t),e.saveCoords(),this.fire("selection:created",{target:e,e:t}),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.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.height||this.getHeight())*r,h=this.getZoom()*r,c=this.viewportTransform,l=[h,0,0,h,(c[4]-i.left)*r,(c[5]-i.top)*r],u=this.interactive;this.viewportTransform=l,this.interactive&&(this.interactive=!1),n!==o||s!==a?this.setDimensions({width:o,height:a},{backstoreOnly:!0}):this.renderAll();var f=this.__toDataURL(t,e,i);return u&&(this.interactive=u),this.viewportTransform=c,this.setDimensions({width:n,height:s},{backstoreOnly:!0}),f},__toDataURL:function(e,i){var r=this.contextContainer.canvas;"jpg"===e&&(e="jpeg");return t?r.toDataURL("image/"+e,i):r.toDataURL("image/"+e)},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),n=this,s=this.renderOnAddRemove;return this.renderOnAddRemove=!1,this._enlivenObjects(r.objects,function(t){n.clear(),n._setBgOverlay(r,function(){t.forEach(function(t,e){n.insertAt(t,e)}),n.renderOnAddRemove=s,delete r.objects,delete r.backgroundImage,delete r.overlayImage,delete r.background,delete r.overlay,n._setOptions(r),n.renderAll(),e&&e()})},i),this}},_setBgOverlay:function(t,e){var i={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(t.backgroundImage||t.overlayImage||t.background||t.overlay){var r=function(){i.backgroundImage&&i.overlayImage&&i.backgroundColor&&i.overlayColor&&e&&e()};this.__setBgOverlay("backgroundImage",t.backgroundImage,i,r),this.__setBgOverlay("overlayImage",t.overlayImage,i,r),this.__setBgOverlay("backgroundColor",t.background,i,r),this.__setBgOverlay("overlayColor",t.overlay,i,r)}else e&&e()},__setBgOverlay:function(t,e,i,r){var n=this;if(!e)return i[t]=!0,void(r&&r());"backgroundImage"===t||"overlayImage"===t?fabric.util.enlivenObjects([e],function(e){n[t]=e[0],i[t]=!0,r&&r()}):this["set"+fabric.util.string.capitalize(t,!0)](e,function(){i[t]=!0,r&&r()})},_enlivenObjects:function(t,e,i){t&&0!==t.length?fabric.util.enlivenObjects(t,function(t){e&&e(t)},null,i):e&&e([])},_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.object.clone,n=e.util.toFixed,s=e.util.string.capitalize,o=e.util.degreesToRadians,a=e.StaticCanvas.supports("setLineDash"),h=!e.isLikelyNode;e.Object||(e.Object=e.util.createClass(e.CommonMethods,{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,objectCaching:h,statefullCache:!1,noScaleCache:!0,dirty:!0,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor skewX skewY fillRule".split(" "),cacheProperties:"fill stroke strokeWidth strokeDashArray width height strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor".split(" "),initialize:function(t){(t=t||{})&&this.setOptions(t)},_createCacheCanvas:function(){this._cacheProperties={},this._cacheCanvas=e.document.createElement("canvas"),this._cacheContext=this._cacheCanvas.getContext("2d"),this._updateCacheCanvas()},_limitCacheSize:function(t){var i=e.perfLimitSizeTotal,r=t.width,n=t.height,s=e.maxCacheSideLimit,o=e.minCacheSideLimit;if(r<=s&&n<=s&&r*n<=i)return rl&&(t.zoomX/=r/l,t.width=l,t.capped=!0),n>u&&(t.zoomY/=n/u,t.height=u,t.capped=!0),t},_getCacheCanvasDimensions:function(){var t=this.canvas&&this.canvas.getZoom()||1,i=this.getObjectScaling(),r=this.canvas&&this.canvas._isRetinaScaling()?e.devicePixelRatio:1,n=this._getNonTransformedDimensions(),s=i.scaleX*t*r,o=i.scaleY*t*r;return{width:n.x*s+2,height:n.y*o+2,zoomX:s,zoomY:o,x:n.x,y:n.y}},_updateCacheCanvas:function(){if(this.noScaleCache&&this.canvas&&this.canvas._currentTransform){var t=this.canvas._currentTransform.target,i=this.canvas._currentTransform.action;if(this===t&&i.slice&&"scale"===i.slice(0,5))return!1}var r,n,s=this._cacheCanvas,o=this._limitCacheSize(this._getCacheCanvasDimensions()),a=e.minCacheSideLimit,h=o.width,c=o.height,l=o.zoomX,u=o.zoomY,f=h!==this.cacheWidth||c!==this.cacheHeight,d=this.zoomX!==l||this.zoomY!==u,g=f||d,p=0,v=0,b=!1;if(f){var m=this._cacheCanvas.width,_=this._cacheCanvas.height,y=h>m||c>_;b=y||(h<.9*m||c<.9*_)&&m>a&&_>a,y&&!o.capped&&(h>a||c>a)&&(p=.1*h,v=.1*c)}return!!g&&(b?(s.width=Math.ceil(h+p),s.height=Math.ceil(c+v)):(this._cacheContext.setTransform(1,0,0,1,0,0),this._cacheContext.clearRect(0,0,s.width,s.height)),r=o.x*l/2,n=o.y*u/2,this.cacheTranslationX=Math.round(s.width/2-r)+r,this.cacheTranslationY=Math.round(s.height/2-n)+n,this.cacheWidth=h,this.cacheHeight=c,this._cacheContext.translate(this.cacheTranslationX,this.cacheTranslationY),this._cacheContext.scale(l,u),this.zoomX=l,this.zoomY=u,!0)},setOptions:function(t){this._setOptions(t),this._initGradient(t.fill,"fill"),this._initGradient(t.stroke,"stroke"),this._initClipping(t),this._initPattern(t.fill,"fill"),this._initPattern(t.stroke,"stroke")},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),this.angle&&t.rotate(o(this.angle)),t.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1)),this.skewX&&t.transform(1,0,Math.tan(o(this.skewX)),1,0,0),this.skewY&&t.transform(1,Math.tan(o(this.skewY)),0,1,0,0)},toObject:function(t){var i=e.Object.NUM_FRACTION_DIGITS,r={type:this.type,originX:this.originX,originY:this.originY,left:n(this.left,i),top:n(this.top,i),width:n(this.width,i),height:n(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:n(this.strokeWidth,i),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:n(this.strokeMiterLimit,i),scaleX:n(this.scaleX,i),scaleY:n(this.scaleY,i),angle:n(this.getAngle(),i),flipX:this.flipX,flipY:this.flipY,opacity:n(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():null,skewX:n(this.skewX,i),skewY:n(this.skewY,i)};return e.util.populateWithProperties(this,r,t),this.includeDefaultValues||(r=this._removeDefaultValues(r)),r},toDatalessObject:function(t){return this.toObject(t)},_removeDefaultValues:function(t){var i=e.util.getKlass(t.type).prototype;return i.stateProperties.forEach(function(e){t[e]===i[e]&&delete t[e];"[object Array]"===Object.prototype.toString.call(t[e])&&"[object Array]"===Object.prototype.toString.call(i[e])&&0===t[e].length&&0===i[e].length&&delete t[e]}),t},toString:function(){return"#"},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}},_set:function(t,i){var r="scaleX"===t||"scaleY"===t,n=this[t]!==i;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?"dirty"===t&&this.group&&this.group.set("dirty",i):i=new e.Shadow(i),this[t]=i,n&&this.cacheProperties.indexOf(t)>-1&&(this.group&&this.group.set("dirty",!0),this.dirty=!0),n&&this.group&&this.stateProperties.indexOf(t)>-1&&this.group.set("dirty",!0),"width"!==t&&"height"!==t||(this.minScaleLimit=Math.min(.1,1/Math.max(this.width,this.height))),this},setOnGroup:function(){},setSourcePath:function(t){return this.sourcePath=t,this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:e.iMatrix.concat()},isNotVisible:function(){return 0===this.opacity||0===this.width&&0===this.height||!this.visible},render:function(t,i){this.isNotVisible()||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(t.save(),this._setupCompositeOperation(t),this.drawSelectionBackground(t),i||this.transform(t),this._setOpacity(t),this._setShadow(t),this.transformMatrix&&t.transform.apply(t,this.transformMatrix),this.clipTo&&e.util.clipContext(this,t),this.shouldCache(i)?(this._cacheCanvas||this._createCacheCanvas(),this.isCacheDirty(i)&&(this.statefullCache&&this.saveState({propertySet:"cacheProperties"}),this.drawObject(this._cacheContext,i),this.dirty=!1),this.drawCacheOnCanvas(t)):(this._removeCacheCanvas(),this.dirty=!1,this.drawObject(t,i),i&&this.objectCaching&&this.statefullCache&&this.saveState({propertySet:"cacheProperties"})),this.clipTo&&t.restore(),t.restore())},_removeCacheCanvas:function(){this._cacheCanvas=null,this.cacheWidth=0,this.cacheHeight=0},needsItsOwnCache:function(){return!1},shouldCache:function(t){return!t&&this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching())},willDrawShadow:function(){return!!this.shadow&&(0!==this.shadow.offsetX||0!==this.shadow.offsetY)},drawObject:function(t,e){this._renderBackground(t),this._setStrokeStyles(t),this._setFillStyles(t),this._render(t,e)},drawCacheOnCanvas:function(t){t.scale(1/this.zoomX,1/this.zoomY),t.drawImage(this._cacheCanvas,-this.cacheTranslationX,-this.cacheTranslationY)},isCacheDirty:function(t){if(this.isNotVisible())return!1;if(this._cacheCanvas&&!t&&this._updateCacheCanvas())return!0;if(this.dirty||this.statefullCache&&this.hasStateChanged("cacheProperties")){if(this._cacheCanvas&&!t){var e=this.cacheWidth/this.zoomX,i=this.cacheHeight/this.zoomY;this._cacheContext.clearRect(-e/2,-i/2,e,i)}return!0}return!1},_renderBackground:function(t){if(this.backgroundColor){var e=this._getNonTransformedDimensions();t.fillStyle=this.backgroundColor,t.fillRect(-e.x/2,-e.y/2,e.x,e.y),this._removeShadow(t)}},_setOpacity:function(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),a?t.setLineDash(e):i&&i(t))},_renderControls:function(t){if(this.active&&(!this.group||this.group===this.canvas.getActiveGroup())){var i,r=this.getViewportTransform(),n=this.calcTransformMatrix();n=e.util.multiplyTransformMatrices(r,n),i=e.util.qrDecompose(n),t.save(),t.translate(i.translateX,i.translateY),t.lineWidth=1*this.borderScaleFactor,this.group||(t.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1),this.group&&this.group===this.canvas.getActiveGroup()?(t.rotate(o(i.angle)),this.drawBordersInGroup(t,i)):(t.rotate(o(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)},_applyPatternGradientTransform:function(t,e){if(e.toLive){var i=e.gradientTransform||e.patternTransform;i&&t.transform.apply(t,i);var r=-this.width/2+e.offsetX||0,n=-this.height/2+e.offsetY||0;t.translate(r,n)}},_renderFill:function(t){this.fill&&(t.save(),this._applyPatternGradientTransform(t,this.fill),"evenodd"===this.fillRule?t.fill("evenodd"):t.fill(),t.restore())},_renderStroke:function(t){this.stroke&&0!==this.strokeWidth&&(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(t),t.save(),this._setLineDash(t,this.strokeDashArray,this._renderDashedStroke),this._applyPatternGradientTransform(t,this.stroke),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 1},toJSON:function(t){return this.toObject(t)},setGradient:function(t,i){i||(i={});var r={colorStops:[]};return 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),r.gradientTransform=i.gradientTransform,e.Gradient.prototype.addColorStop.call(r,i.colorStops),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.group&&this.group===this.canvas._activeGroup&&this.group.remove(this),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,o(-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._fromObject=function(t,i,n,s,o){var a=e[t];if(i=r(i,!0),!s){var h=o?new a(i[o],i):new a(i);return n&&n(h),h}e.util.enlivenPatterns([i.fill,i.stroke],function(t){void 0!==t[0]&&(i.fill=t[0]),void 0!==t[1]&&(i.stroke=t[1]);var e=o?new a(i[o],i):new a(i);n&&n(e)})},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=void 0!==i&&void 0!==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")},onDeselect:function(){}})}(),function(){var t=fabric.util.degreesToRadians,e=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,aCoords:null,getCoords:function(t,e){this.oCoords||this.setCoords();var i=t?this.aCoords:this.oCoords;return function(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)]}(e?this.calcCoords(t):i)},intersectsWithRect:function(t,e,i,r){var n=this.getCoords(i,r);return"Intersection"===fabric.Intersection.intersectPolygonRectangle(n,t,e).status},intersectsWithObject:function(t,e,i){return"Intersection"===fabric.Intersection.intersectPolygonPolygon(this.getCoords(e,i),t.getCoords(e,i)).status||t.isContainedWithinObject(this,e,i)||this.isContainedWithinObject(t,e,i)},isContainedWithinObject:function(t,e,i){for(var r=this.getCoords(e,i),n=0,s=t._getImageLines(i?t.calcCoords(e):e?t.aCoords:t.oCoords);n<4;n++)if(!t.containsPoint(r[n],s))return!1;return!0},isContainedWithinRect:function(t,e,i,r){var n=this.getBoundingRect(i,r);return n.left>=t.x&&n.left+n.width<=e.x&&n.top>=t.y&&n.top+n.height<=e.y},containsPoint:function(t,e,i,r){var e=e||this._getImageLines(r?this.calcCoords(i):i?this.aCoords:this.oCoords),n=this._findCrossPoints(t,e);return 0!==n&&n%2==1},isOnScreen:function(t){if(!this.canvas)return!1;for(var e,i=this.canvas.vptCoords.tl,r=this.canvas.vptCoords.br,n=this.getCoords(!0,t),s=0;s<4;s++)if((e=n[s]).x<=r.x&&e.x>=i.x&&e.y<=r.y&&e.y>=i.y)return!0;if(this.intersectsWithRect(i,r,!0))return!0;var o={x:(i.x+r.x)/2,y:(i.y+r.y)/2};return!!this.containsPoint(o,null,!0)},_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=0;for(var a in e)if(!((s=e[a]).o.y=t.y&&s.d.y>=t.y||(s.o.x===s.d.x&&s.o.x>=t.x?n=s.o.x:(i=0,r=(s.d.y-s.o.y)/(s.d.x-s.o.x),n=-(t.y-i*t.x-(s.o.y-r*s.o.x))/(i-r)),n>=t.x&&(o+=1),2!==o)))break;return o},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(t,e){var i=this.getCoords(t,e);return fabric.util.makeBoundingBoxFromPoints(i)},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(t){return Math.abs(t)0?Math.atan(o/s):0,l=s/Math.cos(c)/2,u=Math.cos(c+i)*l,f=Math.sin(c+i)*l,d=this.getCenterPoint(),g=e?d:fabric.util.transformPoint(d,r),p=new fabric.Point(g.x-u,g.y-f),v=new fabric.Point(p.x+s*h,p.y+s*a),b=new fabric.Point(p.x-o*a,p.y+o*h),m=new fabric.Point(g.x+u,g.y+f);if(!e)var _=new fabric.Point((p.x+b.x)/2,(p.y+b.y)/2),y=new fabric.Point((v.x+p.x)/2,(v.y+p.y)/2),x=new fabric.Point((m.x+v.x)/2,(m.y+v.y)/2),C=new fabric.Point((m.x+b.x)/2,(m.y+b.y)/2),S=new fabric.Point(y.x+a*this.rotatingPointOffset,y.y-h*this.rotatingPointOffset);g={tl:p,tr:v,br:m,bl:b};return e||(g.ml=_,g.mt=y,g.mr=x,g.mb=C,g.mtr=S),g},setCoords:function(t,e){return this.oCoords=this.calcCoords(t),e||(this.aCoords=this.calcCoords(!0)),t||this._setCornerCoords&&this._setCornerCoords(),this},_calcRotateMatrix:function(){if(this.angle){var e=t(this.angle),i=Math.cos(e),r=Math.sin(e);return 6.123233995736766e-17!==i&&-1.8369701987210297e-16!==i||(i=0),[i,r,-r,i,0,0]}return fabric.iMatrix.concat()},calcTransformMatrix:function(t){var i,r,n=this.getCenterPoint(),s=[1,0,0,1,n.x,n.y],o=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0);return r=this.group&&!t?e(this.group.calcTransformMatrix(),s):s,this.angle&&(i=this._calcRotateMatrix(),r=e(r,i)),r=e(r,o)},_calcDimensionsTransformMatrix:function(i,r,n){var s,o=[this.scaleX*(n&&this.flipX?-1:1),0,0,this.scaleY*(n&&this.flipY?-1:1),0,0];return i&&(s=[1,0,Math.tan(t(i)),1],o=e(o,s,!0)),r&&(s=[1,Math.tan(t(r)),0,1],o=e(o,s,!0)),o},_getNonTransformedDimensions:function(){var t=this.strokeWidth;return{x:this.width+t,y:this.height+t}},_getTransformedDimensions:function(t,e){void 0===t&&(t=this.skewX),void 0===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("")}}),i.Line.ATTRIBUTE_NAMES=i.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),i.Line.fromElement=function(t,e){e=e||{};var n=i.parseAttributes(t,i.Line.ATTRIBUTE_NAMES),s=[n.x1||0,n.y1||0,n.x2||0,n.y2||0];return e.originX="left",e.originY="top",new i.Line(s,r(n,e))},i.Line.fromObject=function(t,e,r){var s=n(t,!0);s.points=[t.x1,t.y1,t.x2,t.y2];var o=i.Object._fromObject("Line",s,function(t){delete t.points,e&&e(t)},r,"points");return o&&delete o.points,o})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=Math.PI,r=e.util.object.extend;e.Circle?e.warn("fabric.Circle is already defined."):(e.Circle=e.util.createClass(e.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*i,cacheProperties:e.Object.prototype.cacheProperties.concat("radius"),initialize:function(t){this.callSuper("initialize",t),this.set("radius",t&&t.radius||0)},_set:function(t,e){return this.callSuper("_set",t,e),"radius"===t&&this.setRadius(e),this},toObject:function(t){return this.callSuper("toObject",["radius","startAngle","endAngle"].concat(t))},toSVG:function(t){var e=this._createBaseSVGMarkup(),r=0,n=0,s=(this.endAngle-this.startAngle)%(2*i);if(0===s)this.group&&"path-group"===this.group.type&&(r=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>i?"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)}}),e.Circle.ATTRIBUTE_NAMES=e.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),e.Circle.fromElement=function(t,i){i||(i={});var n=e.parseAttributes(t,e.Circle.ATTRIBUTE_NAMES);if(!function(t){return"radius"in t&&t.radius>=0}(n))throw new Error("value of `r` attribute is required and can not be negative");n.left=n.left||0,n.top=n.top||0;var s=new e.Circle(r(n,i));return s.left-=s.radius,s.top-=s.radius,s},e.Circle.fromObject=function(t,i,r){return e.Object._fromObject("Circle",t,i,r)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={});e.Triangle?e.warn("fabric.Triangle is already defined"):(e.Triangle=e.util.createClass(e.Object,{type:"triangle",initialize:function(t){this.callSuper("initialize",t),this.set("width",t&&t.width||100).set("height",t&&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("")}}),e.Triangle.fromObject=function(t,i,r){return e.Object._fromObject("Triangle",t,i,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;e.Ellipse?e.warn("fabric.Ellipse is already defined."):(e.Ellipse=e.util.createClass(e.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:e.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this.set("rx",t&&t.rx||0),this.set("ry",t&&t.ry||0)},_set:function(t,e){switch(this.callSuper("_set",t,e),t){case"rx":this.rx=e,this.set("width",2*e);break;case"ry":this.ry=e,this.set("height",2*e)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(t){return this.callSuper("toObject",["rx","ry"].concat(t))},toSVG:function(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)}}),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},e.Ellipse.fromObject=function(t,i,r){return e.Object._fromObject("Ellipse",t,i,r)})}("undefined"!=typeof exports?exports:this),function(t){"use strict";var e=t.fabric||(t.fabric={}),i=e.util.object.extend;e.Rect?e.warn("fabric.Rect is already defined"):(e.Rect=e.util.createClass(e.Object,{stateProperties:e.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:e.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(t){this.callSuper("initialize",t),this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(t,e){if(1!==this.width||1!==this.height){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)}else t.fillRect(-.5,-.5,1,1)},_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){return this.callSuper("toObject",["rx","ry"].concat(t))},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("")}}),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,r){return e.Object._fromObject("Rect",t,i,r)})}("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.toFixed,o=e.Object.NUM_FRACTION_DIGITS;e.Polyline?e.warn("fabric.Polyline is already defined"):(e.Polyline=e.util.createClass(e.Object,{type:"polyline",points:null,minX:0,minY:0,cacheProperties:e.Object.prototype.cacheProperties.concat("points"),initialize:function(t,e){e=e||{},this.points=t||[],this.callSuper("initialize",e),this._calcDimensions(),"top"in e||(this.top=this.minY),"left"in e||(this.left=this.minX),this.pathOffset={x:this.minX+this.width/2,y:this.minY+this.height/2}},_calcDimensions:function(){var t=this.points,e=r(t,"x"),i=r(t,"y"),s=n(t,"x"),o=n(t,"y");this.width=s-e||0,this.height=o-i||0,this.minX=e||0,this.minY=i||0},toObject:function(t){return i(this.callSuper("toObject",t),{points:this.points.concat()})},toSVG:function(t){var e=[],i=0,r=0,n=this._createBaseSVGMarkup();this.group&&"path-group"===this.group.type||(i=this.pathOffset.x,r=this.pathOffset.y);for(var a=0,h=this.points.length;a\n'),t?t(n.join("")):n.join("")},commonRender:function(t,e){var i,r=this.points.length,n=e?0:this.pathOffset.x,s=e?0:this.pathOffset.y;if(!r||isNaN(this.points[r-1].y))return!1;t.beginPath(),t.moveTo(this.points[0].x-n,this.points[0].y-s);for(var o=0;o"},toObject:function(t){return n(this.callSuper("toObject",["sourcePath","pathOffset"].concat(t)),{path:this.path.map(function(t){return t.slice()}),top:this.top,left:this.left})},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){var r=t.paths;delete t.paths,"string"==typeof r?e.loadSVGFromURL(r,function(n){var s=r,o=e.util.groupSVGElements(n,t,s);t.paths=r,i(o)}):e.util.enlivenObjects(r,function(n){var s=new e.PathGroup(n,t);t.paths=r,i(s)})},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;if(!e.Group){var s={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,cacheProperties:[],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;e.originX&&(this.originX=e.originX),e.originY&&(this.originY=e.originY),i?(this._updateObjectsCoords(!0),this._updateObjectsACoords()):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",e)),this.setCoords(),this.saveCoords()},_updateObjectsACoords:function(){for(var t=this._objects.length;t--;)this._objects[t].setCoords(!0,!0)},_updateObjectsCoords:function(t){for(var e=this.getCenterPoint(),i=this._objects.length;i--;)this._updateObjectCoords(this._objects[i],e,t)},_updateObjectCoords:function(t,e,i){if(t.__origHasControls=t.hasControls,t.hasControls=!1,!i){var r=t.getLeft(),n=t.getTop();t.set({left:r-e.x,top:n-e.y}),t.setCoords(!0,!0)}},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.setCoords(),this.dirty=!0,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.setCoords(),this.dirty=!0,this},_onObjectAdded:function(t){this.dirty=!0,t.group=this,t._set("canvas",this.canvas)},_onObjectRemoved:function(t){this.dirty=!0,delete t.group,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){var e=this.getObjects().map(function(e){var i=e.includeDefaultValues;e.includeDefaultValues=e.group.includeDefaultValues;var r=e.toObject(t);return e.includeDefaultValues=i,r});return i(this.callSuper("toObject",t),{objects:e})},toDatalessObject:function(t){var e=this.getObjects().map(function(e){var i=e.includeDefaultValues;e.includeDefaultValues=e.group.includeDefaultValues;var r=e.toDatalessObject(t);return e.includeDefaultValues=i,r});return i(this.callSuper("toDatalessObject",t),{objects:e})},render:function(t){this._transformDone=!0,this.callSuper("render",t),this._transformDone=!1},shouldCache:function(){var t=this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching());if(this.caching=t,t)for(var e=0,i=this._objects.length;e\n');for(var i=0,r=this._objects.length;i\n"),t?t(e.join("")):e.join("")},get:function(t){if(t in s){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(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){var e=function(){},i=(t=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()}}),fabric.Image.filters.BaseFilter.fromObject=function(t,e){var i=new fabric.Image.filters[t.type](t);return e&&e(i),i},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[S*d+w],e+=p[h]*c,i+=p[h+1]*c,r+=p[h+2]*c,n+=p[h+3]*c);_[s]=e,_[s+1]=i,_[s+2]=r,_[s+3]=n+y*(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=e.Image.filters.BaseFilter.fromObject}("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).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*f=e)){P=r(1e3*s(c-O.x)),w[P]||(w[P]={});for(var I=T.y-S;I<=T.y+S;I++)I<0||I>=o||(E=r(1e3*s(I-O.y)),w[P][E]||(w[P][E]=b(n(i(P*y,2)+i(E*x,2))/1e3)),(f=w[P][E])>0&&(j+=f,k+=f*p[d=4*(I*e+c)],M+=f*p[d+1],D+=f*p[d+2],A+=f*p[d+3]))}v[d=4*(h*a+t)]=k/j,v[d+1]=M/j,v[d+2]=D/j,v[d+3]=A/j}return++tt)return 0;if(e*=Math.PI,s(e)<1e-16)return 1;var i=e/t;return h(e)*h(i)/e/i}}(this.lanczosLobes),m=this.rcpScaleX,_=this.rcpScaleY,y=2/this.rcpScaleX,x=2/this.rcpScaleY,C=c(m*this.lanczosLobes/2),S=c(_*this.lanczosLobes/2),w={},O={},T={};return u(0)},bilinearFiltering:function(t,e,i,n,s){var o,a,h,c,l,u,f,d,g,p=0,v=this.rcpScaleX,b=this.rcpScaleY,m=t.getContext("2d"),_=4*(e-1),y=m.getImageData(0,0,e,i).data,x=m.getImageData(0,0,n,s),C=x.data;for(h=0;h1&&I<-1||(y=2*I*I*I-3*I*I+1)>0&&(T+=y*g[(E=4*(P+k*e))+3],C+=y,g[E+3]<255&&(y=y*g[E+3]/250),S+=y*g[E],w+=y*g[E+1],O+=y*g[E+2],x+=y)}v[_]=S/x,v[_+1]=w/x,v[_+2]=O/x,v[_+3]=T/C}return p},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}}),e.Image.filters.Resize.fromObject=e.Image.filters.BaseFilter.fromObject}("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'},_getCacheCanvasDimensions:function(){var t=this.callSuper("_getCacheCanvasDimensions"),e=this.fontSize;return t.width+=e*t.zoomX,t.height+=e*t.zoomY,t},_render:function(t){this._setTextStyles(t),this.group&&"path-group"===this.group.type&&t.translate(this.left,this.top),this._renderTextLinesBackground(t),this._renderText(t),this._renderTextDecoration(t)},_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},_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)for(var l=this._getWidthOfCharSpacing(),u=0,f=(i=i.split("")).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?i: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;t.fillStyle=s,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=[]},_shouldClearDimensionCache:function(){var t=this._forceClearCache;return t||(t=this.hasStateChanged("_dimensionAffectingProps")),t&&(this.saveState({propertySet:"_dimensionAffectingProps"}),this.dirty=!0),t},_getLineWidth:function(t,e){if(this.__lineWidths[e])return-1===this.__lineWidths[e]?this.width:this.__lineWidths[e];var i,r=this._textLines[e];return i=""===r?0:this._measureLine(t,e),this.__lineWidths[e]=i,i&&"justify"===this.textAlign&&r.split(/\s+/).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=this._textLines[e],n=t.measureText(r).width,s=0;return 0!==this.charSpacing&&(s=(r.split("").length-1)*this._getWidthOfCharSpacing()),(i=n+s)>0?i:0},_renderTextDecoration:function(t){if(this.textDecoration){var e=this.height/2,i=this,r=[];this.textDecoration.indexOf("underline")>-1&&r.push(.85),this.textDecoration.indexOf("line-through")>-1&&r.push(.43),this.textDecoration.indexOf("overline")>-1&&r.push(-.12),r.length>0&&function(r){var n,s,o,a,h,c,l,u=0;for(n=0,s=i._textLines.length;n\n",e.textBgRects.join(""),'\t\t\n',e.textSpans.join(""),"\t\t\n","\t\n")},getSvgStyles:function(t){return e.Object.prototype.getSvgStyles.call(this,t)+" white-space: pre;"},_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"):this._setSVGTextLineJustifed(t,n,h,o)},_setSVGTextLineJustifed:function(t,n,s,o){var a=e.util.createCanvasElement().getContext("2d");this._setTextStyles(a);var h,c,l=this._textLines[t].split(/\s+/),u=this._getWidthOfWords(a,l.join("")),f=this.width-u,d=l.length-1,g=d>0?f/d:0,p=this._getFillAttributes(this.fill);for(o+=this._getLineLeftOffset(this._getLineWidth(a,t)),t=0,c=l.length;t",e.util.string.escapeXml(h),"\n"),o+=this._getWidthOfWords(a,h)+g},_setSVGTextLineBg:function(t,e,n,s,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),this._dimensionAffectingProps.indexOf(t)>-1&&(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)).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)*o,h=s.getHeight()+a,c=0;return"left"===s.originX&&(c=s.getWidth()/2),"right"===s.originX&&(c=-s.getWidth()/2),s.set({left:s.getLeft()+c,top:s.getTop()-h/2+s.fontSize*(.18+s._fontSizeFraction)/s.lineHeight}),s},e.Text.fromObject=function(t,i,r){return e.Object._fromObject("Text",t,i,r,"text")},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=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(),h=0;for(var m,_=0,y=(g=n.split("")).length;_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);var e,i,r,n,s,o,a,h,c,l,u=0,f=this._getLeftOffset(),d=this._getTopOffset(),g="";t.save();for(var p=0,v=this._textLines.length;p0?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.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()))}},_setEditingProps:function(){this.hoverCursor="text",this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text"),this.borderColor=this.editingBorderColor,this.hasControls=this.selectable=!1,this.lockMovementX=this.lockMovementY=!0},_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=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)).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.hiddenTextarea.blur&&this.hiddenTextarea.blur(),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())for(var r=0,n=t.length;r=i&&(o=!0,s[h-i]=this.styles[e][a],delete this.styles[e][a])}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])}var h=r||t(n[i-1]);h&&(this.styles[e][i]=h),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 r){(s=parseInt(n,10))<=e&&delete r[s]}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,t.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.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&&(!t.e.button||1===t.e.button)){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)||t.e.button&&1!==t.e.button||(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.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(t){for(var e,i=this.getLocalPointer(t),r=0,n=0,s=0,o=0,a=0,h=this._textLines.length;as?0:1);return this.flipX&&(o=n-o),o>this.text.length&&(o=this.text.length),o}}),fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.setAttribute("autocorrect","off"),this.hiddenTextarea.setAttribute("autocomplete","off"),this.hiddenTextarea.setAttribute("spellcheck","false"),this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea",""),this.hiddenTextarea.setAttribute("wrap","off");var t=this._calcTextareaPosition();this.hiddenTextarea.style.cssText="position: absolute; top: "+t.top+"; left: "+t.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; line-height: 1px; paddingーtop: "+t.fontSize+";",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(),t.keyCode>=33&&t.keyCode<=40?(this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.renderAll()}},onKeyUp:function(t){this.isEditing&&!this._copyDone?t.keyCode in this.ctrlKeysMapUp&&(t.ctrlKey||t.metaKey)&&(this[this.ctrlKeysMapUp[t.keyCode]](t),t.stopImmediatePropagation(),t.preventDefault(),this.canvas&&this.canvas.renderAll()):this._copyDone=!1},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 u=s-l,f=s,d=Math.abs(u-e);o=Math.abs(f-e)=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorUpOrDown("Down",t)},moveCursorUp:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",t)},_moveCursorUpOrDown:function(t,e){var i=this["get"+t+"CursorOffset"](e,"right"===this._selectionDirection);e.shiftKey?this.moveCursorWithShift(i):this.moveCursorWithoutShift(i),0!==i&&(this.setSelectionInBoundaries(),this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(t){var e="left"===this._selectionDirection?this.selectionStart+t:this.selectionEnd+t;return this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,e),0!==t},moveCursorWithoutShift:function(t){return t<0?(this.selectionStart+=t,this.selectionEnd=this.selectionStart):(this.selectionEnd+=t,this.selectionStart=this.selectionEnd),0!==t},moveCursorLeft:function(t){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorLeftOrRight("Left",t)},_move:function(t,e,i){var r;if(t.altKey)r=this["findWordBoundary"+i](this[e]);else{if(!t.metaKey&&35!==t.keyCode&&36!==t.keyCode)return this[e]+="Left"===i?-1:1,!0;r=this["findLineBoundary"+i](this[e])}if(void 0!==typeof r&&this[e]!==r)return this[e]=r,!0},_moveLeft:function(t,e){return this._move(t,e,"Left")},_moveRight:function(t,e){return this._move(t,e,"Right")},moveCursorLeftWithoutShift:function(t){var e=!0;return this._selectionDirection="left",this.selectionEnd===this.selectionStart&&0!==this.selectionStart&&(e=this._moveLeft(t,"selectionStart")),this.selectionEnd=this.selectionStart,e},moveCursorLeftWithShift:function(t){return"right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveLeft(t,"selectionEnd"):0!==this.selectionStart?(this._selectionDirection="left",this._moveLeft(t,"selectionStart")):void 0},moveCursorRight:function(t){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorLeftOrRight("Right",t)},_moveCursorLeftOrRight:function(t,e){var i="moveCursor"+t+"With";this._currentCursorOpacity=1,e.shiftKey?i+="Shift":i+="outShift",this[i](e)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(t){return"left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd?this._moveRight(t,"selectionStart"):this.selectionEnd!==this.text.length?(this._selectionDirection="right",this._moveRight(t,"selectionEnd")):void 0},moveCursorRightWithoutShift:function(t){var e=!0;return this._selectionDirection="right",this.selectionStart===this.selectionEnd?(e=this._moveRight(t,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd,e},removeChars:function(t){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(t):this._removeCharsFromTo(this.selectionStart,this.selectionEnd),this.set("dirty",!0),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={});e.Textbox=e.util.createClass(e.IText,e.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:2,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,noScaleCache:!1,_dimensionAffectingProps:e.Text.prototype._dimensionAffectingProps.concat("width"),initialize:function(t,i){this.callSuper("initialize",t,i),this.setControlsVisibility(e.Textbox.getTextboxControlVisibility()),this.ctx=this.objectCaching?this._cacheContext:e.util.createCanvasElement().getContext("2d")},_initDimensions:function(t){this.__skipDimension||(t||(t=e.util.createCanvasElement().getContext("2d"),this._setTextStyles(t),this.clearContextTop()),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(t),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(t),this.setCoords())},_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&&!f?(n.push(s),s="",r=c,f=!0):r+=d,f||(s+=" "),s+=a,l=this._measureText(t," ",i,h),h++,f=!1,c>u&&(u=c);return g&&n.push(s),u>this.dynamicMinWidth&&(this.dynamicMinWidth=u-d),n},_splitTextIntoLines:function(t){t=t||this.ctx;var e=this.textAlign;this._styleMap=null,t.save(),this._setTextStyles(t),this.textAlign="left";var i=this._wrapText(t,this.text);return this.textAlign=e,t.restore(),this._textLines=i,this._styleMap=this._generateStyleMap(),i},setOnGroup:function(t,e){"scaleX"===t&&(this.set("scaleX",Math.abs(1/e)),this.set("width",this.get("width")*e/(void 0===this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=e)},get2DCursorLocation:function(t){void 0===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(void 0!==fabric.Textbox)for(var t=this._objects.length;t--;)if(this._objects[t]instanceof fabric.Textbox)return void this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility())},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,e){t=this._styleMap[t].line,fabric.IText.prototype.shiftLineStyles.call(this,t,e)},_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).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)})});n.on("error",function(t){t.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+r.hostname+":"+r.port):fabric.log(t.message),i(null)}),n.end()}function requestFs(t,e){require("fs").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){0!==(t=t.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim()).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||{}).nodeCanvas=s,i.nodeCacheCanvas=o;var a=new(fabric.Canvas||fabric.StaticCanvas)(n,i);return a.nodeCanvas=s,a.nodeCacheCanvas=o,a.contextContainer=s.getContext("2d"),a.contextCache=o.getContext("2d"),a.Font=Canvas.Font,a};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)}}();/* pako 0.2.3 nodeca/pako */ +var $jscomp={scope:{}};$jscomp.defineProperty="function"==typeof Object.defineProperties?Object.defineProperty:function(e,b,d){if(d.get||d.set)throw new TypeError("ES3 does not support getters and setters.");e!=Array.prototype&&e!=Object.prototype&&(e[b]=d.value)};$jscomp.getGlobal=function(e){return"undefined"!=typeof window&&window===e?e:"undefined"!=typeof global?global:e};$jscomp.global=$jscomp.getGlobal(this); +$jscomp.polyfill=function(e,b,d,c){if(b){d=$jscomp.global;e=e.split(".");for(c=0;cd&&(d=Math.max(0,a+d));if(null==c||c>a)c=a;c=Number(c);0>c&&(c=Math.max(0,a+c));for(d=Number(d||0);db||1342177279>>=1)d+=d;return c}},"es6-impl","es3");$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};$jscomp.symbolCounter_=0; +$jscomp.Symbol=function(e){return $jscomp.SYMBOL_PREFIX+(e||"")+$jscomp.symbolCounter_++};$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var e=$jscomp.global.Symbol.iterator;e||(e=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("iterator"));"function"!=typeof Array.prototype[e]&&$jscomp.defineProperty(Array.prototype,e,{configurable:!0,writable:!0,value:function(){return $jscomp.arrayIterator(this)}});$jscomp.initSymbolIterator=function(){}}; +$jscomp.arrayIterator=function(e){var b=0;return $jscomp.iteratorPrototype(function(){return bf;)f+=n[l++%h], +f>e&&(f=e),a[k?"lineTo":"moveTo"](f,0),k=!k;a.restore()},createCanvasElement:function(a){a||(a=fabric.document.createElement("canvas"));a.getContext||"undefined"===typeof G_vmlCanvasManager||G_vmlCanvasManager.initElement(a);return a},createImage:function(){return fabric.isLikelyNode?new (require("canvas").Image):fabric.document.createElement("img")},createAccessors:function(a){a=a.prototype;var f,c,b,d;for(f=a.stateProperties.length;f--;)c=a.stateProperties[f],b=c.charAt(0).toUpperCase()+c.slice(1), +d="set"+b,b="get"+b,a[b]||(a[b]=new Function('return this.get("'+c+'")')),a[d]||(a[d]=new Function("value",'return this.set("'+c+'", value)'))},clipContext:function(a,f){f.save();f.beginPath();a.clipTo(f);f.clip()},multiplyTransformMatrices:function(a,f,c){return[a[0]*f[0]+a[2]*f[1],a[1]*f[0]+a[3]*f[1],a[0]*f[2]+a[2]*f[3],a[1]*f[2]+a[3]*f[3],c?0:a[0]*f[4]+a[2]*f[5]+a[4],c?0:a[1]*f[4]+a[3]*f[5]+a[5]]},qrDecompose:function(a){var f=d(a[1],a[0]),h=c(a[0],2)+c(a[1],2),k=b(h),e=(a[0]*a[3]-a[2]*a[1])/k, +h=d(a[0]*a[2]+a[1]*a[3],h);return{angle:f/g,scaleX:k,scaleY:e,skewX:h/g,skewY:0,translateX:a[4],translateY:a[5]}},customTransformMatrix:function(c,f,b){b=[1,0,a(Math.tan(b*g)),1];c=[a(c),0,0,a(f)];return fabric.util.multiplyTransformMatrices(c,b,!0)},resetObjectTransform:function(a){a.scaleX=1;a.scaleY=1;a.skewX=0;a.skewY=0;a.flipX=!1;a.flipY=!1;a.setAngle(0)},getFunctionBody:function(a){return(String(a).match(/function[^{]*\{([\s\S]*)\}/)||{})[1]},isTransparent:function(a,f,c,b){0b?f-b: +0,c=c>b?c-b:0);var d=!0;f=a.getImageData(f,c,2*b||1,2*b||1);c=f.data.length;for(a=3;a=d,!1!==d);a+=4);return d},parsePreserveAspectRatioAttribute:function(a){var f="meet",c;(a=a.split(" "))&&a.length&&(f=a.pop(),"meet"!==f&&"slice"!==f?(c=f,f="meet"):a.length&&(c=a.pop()));a="none"!==c?c.slice(1,4):"none";c="none"!==c?c.slice(5,8):"none";return{meetOrSlice:f,alignX:a,alignY:c}},clearFabricFontCache:function(a){a?fabric.charWidthsCache[a]&&delete fabric.charWidthsCache[a]:fabric.charWidthsCache= +{}},limitDimsByArea:function(a,f){var c=Math.sqrt(f*a);return{x:Math.floor(c),y:Math.floor(f/c)}},capValue:function(a,f,c){return Math.max(a,Math.min(f,c))}}})("undefined"!==typeof exports?exports:this); +(function(){function e(c,g,h,e,p,q,t){var l=f.call(arguments);if(a[l])return a[l];var k=Math.PI,m=t*k/180,n=Math.sin(m),m=Math.cos(m),y=0,x=0;h=Math.abs(h);e=Math.abs(e);var u=-m*c*.5-n*g*.5,C=-m*g*.5+n*c*.5,D=h*h,z=e*e,E=C*C,B=u*u,F=D*z-D*E-z*B,G=0;0>F?(D=Math.sqrt(1-F/(D*z)),h*=D,e*=D):G=(p===q?-1:1)*Math.sqrt(F/(D*E+z*B));E=G*h*C/e;B=-G*e*u/h;G=m*E-n*B+.5*c;D=n*E+m*B+.5*g;z=d(1,0,(u-E)/h,(C-B)/e);C=d((u-E)/h,(C-B)/e,(-u-E)/h,(-C-B)/e);0===q&&0C&&(C+=2*k);k=Math.ceil(Math.abs(C/ +k*2));u=[];C/=k;E=8/3*Math.sin(C/4)*Math.sin(C/4)/Math.sin(C/2);B=z+C;for(F=0;F=a?c-a:2*Math.PI- +(a-c)}function c(a,c,b,d,g,e,t,r){var l=f.call(arguments);if(h[l])return h[l];var k=Math.sqrt,m=Math.min,n=Math.max,p=Math.abs,q=[],C=[[],[]],D,z,E,B,F;z=6*a-12*b+6*g;D=-3*a+9*b-9*g+3*t;E=3*b-3*a;for(var G=0;2>G;++G)0p(D)?1E-12>p(z)||(B=-E/z,0B&&q.push(B)):(B=z*z-4*E*D,0>B||(F=k(B),B=(-z+F)/(2*D),0B&&q.push(B),B=(-z-F)/(2*D),0B&&q.push(B)));for(p=k=q.length;k--;)B=q[k],z=1-B,D=z*z*z*a+3*z*z*B*b+3*z*B*B*g+B*B*B*t,C[0][k]=D,D= +z*z*z*c+3*z*z*B*d+3*z*B*B*e+B*B*B*r,C[1][k]=D;C[0][p]=a;C[1][p]=c;C[0][p+1]=t;C[1][p+1]=r;m=[{x:m.apply(null,C[0]),y:m.apply(null,C[1])},{x:n.apply(null,C[0]),y:n.apply(null,C[1])}];return h[l]=m}var a={},g={},h={},f=Array.prototype.join;fabric.util.drawArc=function(a,f,c,b){var d=[[],[],[],[]];b=e(b[5]-f,b[6]-c,b[0],b[1],b[3],b[4],b[2]);for(var g=0,h=b.length;g>>0;if(0===a)return-1;var d=0;0=a)return-1;for(d=0<=d?d:Math.max(a-Math.abs(d),0);d>>0;a>>0;d>> +0;a>>0;a>>0;h>>0,a=0,d;if(1=c)throw new TypeError;}while(1)}for(;a=c})}}})(); +(function(){function e(b,d,c){if(c)if(!fabric.isLikelyNode&&d instanceof Element)b=d;else if(d instanceof Array){b=[];for(var a=0,g=d.length;a/g,">")}}})(); +(function(){var e=Array.prototype.slice,b=Function.prototype.apply,d=function(){};Function.prototype.bind||(Function.prototype.bind=function(c){var a=this,g=e.call(arguments,1),h;h=g.length?function(){return b.call(a,this instanceof d?this:c,g.concat(e.call(arguments)))}:function(){return b.call(a,this instanceof d?this:c,arguments)};d.prototype=this.prototype;h.prototype=new d;return h})})(); +(function(){function e(){}function b(a){for(var f=null,c=this;c.constructor.superclass;){var b=c.constructor.superclass.prototype[a];if(c[a]!==b){f=b;break}c=c.constructor.superclass.prototype}return f?1f?h:l-d;a=g/h;g=p(g,q,r,h);k(g,Math.abs((g-q)/r),a);l>f?c.onComplete&&c.onComplete():b(A)}})(d)})};fabric.util.requestAnimFrame=b})(); +(function(){fabric.util.animateColor=function(e,b,d,c){e=(new fabric.Color(e)).getSource();b=(new fabric.Color(b)).getSource();c=c||{};fabric.util.animate(fabric.util.object.extend(c,{duration:d||500,startValue:e,endValue:b,byValue:b,easing:function(a,b,d,f){a=c.colorEasing?c.colorEasing(a,f):1-Math.cos(a/f*(Math.PI/2));f="rgba("+parseInt(b[0]+a*(d[0]-b[0]),10)+","+parseInt(b[1]+a*(d[1]-b[1]),10)+","+parseInt(b[2]+a*(d[2]-b[2]),10);f+=","+(b&&d?parseFloat(b[3]+a*(d[3]-b[3])):1);return f+")"}}))}})(); +(function(){function e(a,c,b,f){aa?b/2*a*a+c:-b/2*(--a*(a-2)-1)+c},easeInCubic:function(a,c,b,f){return b*(a/=f)*a*a+c},easeOutCubic:function(a,c,b,f){return b*((a=a/f-1)*a*a+1)+c},easeInOutCubic:function(a,c,b,f){a/=f/2;return 1>a?b/2*a*a*a+c:b/2*((a-=2)*a*a+2)+c},easeInQuart:function(a,c,b,f){return b*(a/=f)*a*a*a+c},easeOutQuart:function(a,c,b,f){return-b*((a=a/f-1)*a*a*a-1)+c},easeInOutQuart:function(a, +c,b,f){a/=f/2;return 1>a?b/2*a*a*a*a+c:-b/2*((a-=2)*a*a*a-2)+c},easeInQuint:function(a,c,b,f){return b*(a/=f)*a*a*a*a+c},easeOutQuint:function(a,c,b,f){return b*((a=a/f-1)*a*a*a*a+1)+c},easeInOutQuint:function(a,c,b,f){a/=f/2;return 1>a?b/2*a*a*a*a*a+c:b/2*((a-=2)*a*a*a*a+2)+c},easeInSine:function(a,c,b,f){return-b*Math.cos(a/f*(Math.PI/2))+b+c},easeOutSine:function(a,c,b,f){return b*Math.sin(a/f*(Math.PI/2))+c},easeInOutSine:function(a,c,b,f){return-b/2*(Math.cos(Math.PI*a/f)-1)+c},easeInExpo:function(a, +c,b,f){return 0===a?c:b*Math.pow(2,10*(a/f-1))+c},easeOutExpo:function(a,c,b,f){return a===f?c+b:b*(-Math.pow(2,-10*a/f)+1)+c},easeInOutExpo:function(a,c,b,f){if(0===a)return c;if(a===f)return c+b;a/=f/2;return 1>a?b/2*Math.pow(2,10*(a-1))+c:b/2*(-Math.pow(2,-10*--a)+2)+c},easeInCirc:function(a,c,b,f){return-b*(Math.sqrt(1-(a/=f)*a)-1)+c},easeOutCirc:function(a,c,b,f){return b*Math.sqrt(1-(a=a/f-1)*a)+c},easeInOutCirc:function(a,c,b,f){a/=f/2;return 1>a?-b/2*(Math.sqrt(1-a*a)-1)+c:b/2*(Math.sqrt(1- +(a-=2)*a)+1)+c},easeInElastic:function(a,c,d,f){var g=0;if(0===a)return c;a/=f;if(1===a)return c+d;g||(g=.3*f);d=e(d,d,g,1.70158);return-b(d,a,f)+c},easeOutElastic:function(a,c,b,f){var d=0;if(0===a)return c;a/=f;if(1===a)return c+b;d||(d=.3*f);b=e(b,b,d,1.70158);return b.a*Math.pow(2,-10*a)*Math.sin(2*(a*f-b.s)*Math.PI/b.p)+b.c+c},easeInOutElastic:function(a,c,d,f){var g=0;if(0===a)return c;a/=f/2;if(2===a)return c+d;g||(g=.3*f*1.5);d=e(d,d,g,1.70158);return 1>a?-.5*b(d,a,f)+c:d.a*Math.pow(2,-10* +--a)*Math.sin(2*(a*f-d.s)*Math.PI/d.p)*.5+d.c+c},easeInBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);return b*(a/=f)*a*((d+1)*a-d)+c},easeOutBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);return b*((a=a/f-1)*a*((d+1)*a+d)+1)+c},easeInOutBack:function(a,c,b,f,d){void 0===d&&(d=1.70158);a/=f/2;return 1>a?b/2*a*a*(((d*=1.525)+1)*a-d)+c:b/2*((a-=2)*a*(((d*=1.525)+1)*a+d)+2)+c},easeInBounce:d,easeOutBounce:c,easeInOutBounce:function(a,b,h,f){return ab?b:c);if(1===c&&1===b&&0===d&&0===g&& +0===m&&0===n)return r;if(m||n)A=" translate("+q(m)+" "+q(n)+") ";c=A+" matrix("+c+" 0 0 "+b+" "+d*c+" "+g*b+") ";if("svg"===a.nodeName){for(b=a.ownerDocument.createElement("g");a.firstChild;)b.appendChild(a.firstChild);a.appendChild(b)}else b=a,c=b.getAttribute("transform")+c;b.setAttribute("transform",c);return r}var k=e.fabric||(e.fabric={}),m=k.util.object.extend,n=k.util.object.clone,p=k.util.toFixed,q=k.util.parseUnit,t=k.util.multiplyTransformMatrices,r=/^(path|circle|polygon|polyline|ellipse|rect|line|image|text)$/i, +v=/^(symbol|image|marker|pattern|view|svg)$/i,A=/^(?:pattern|defs|symbol|metadata|clipPath|mask)$/i,w=/^(symbol|g|a|svg)$/i,y={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",opacity:"opacity"},x={stroke:"strokeOpacity",fill:"fillOpacity"};k.cssRules={};k.gradientDefs={};k.parseTransformAttribute=function(){function a(a,f){var c=Math.cos(f[0]),b=Math.sin(f[0]),d=0,g=0;3===f.length&&(d=f[1],g=f[2]);a[0]=c;a[1]=b;a[2]=-b;a[3]=c;a[4]=d-(c*d-b*g);a[5]=g-(b*d+c*g)}function f(a,f){var c=2===f.length?f[1]:f[0];a[0]=f[0];a[3]=c}function c(a,f){a[4]=f[0];2=== +f.length&&(a[5]=f[1])}var b=[1,0,0,1,0,0],d=k.reNum,g="(?:"+("(?:(matrix)\\s*\\(\\s*("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+")\\s*\\))")+"|"+("(?:(translate)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+("(?:(scale)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+("(?:(rotate)\\s*\\(\\s*("+d+")(?:(?:\\s+,?\\s*|,\\s*)("+d+")(?:\\s+,?\\s*|,\\s*)("+d+"))?\\s*\\))")+"|"+ +("(?:(skewX)\\s*\\(\\s*("+d+")\\s*\\))")+"|"+("(?:(skewY)\\s*\\(\\s*("+d+")\\s*\\))")+")",l=new RegExp("^\\s*(?:"+("(?:"+g+"(?:(?:\\s+,?\\s*|,\\s*)*"+g+")*)")+"?)\\s*$"),h=new RegExp(g,"g");return function(d){var e=b.concat(),m=[];if(!d||d&&!l.test(d))return e;d.replace(h,function(d){var l=(new RegExp(g)).exec(d).filter(function(a){return!!a});d=l[1];l=l.slice(2).map(parseFloat);switch(d){case "translate":c(e,l);break;case "rotate":l[0]=k.util.degreesToRadians(l[0]);a(e,l);break;case "scale":f(e, +l);break;case "skewX":e[2]=Math.tan(k.util.degreesToRadians(l[0]));break;case "skewY":e[1]=Math.tan(k.util.degreesToRadians(l[0]));break;case "matrix":e=l}m.push(e.concat());e=b.concat()});for(d=m[0];1/i,"")));d&&d.documentElement||f&&f(null);k.parseSVGDocument(d.documentElement,function(a,c){f&&f(a,c)},c,b)}})},loadSVGFromString:function(a,f,c,b){a=a.trim();var d;if("undefined"!==typeof DOMParser){var g=new DOMParser;g&&g.parseFromString&&(d=g.parseFromString(a,"text/xml"))}else k.window.ActiveXObject&& +(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(a.replace(//i,"")));k.parseSVGDocument(d.documentElement,function(a,c){f(a,c)},c,b)}})})("undefined"!==typeof exports?exports:this);fabric.ElementsParser=function(e,b,d,c,a){this.elements=e;this.callback=b;this.options=d;this.reviver=c;this.svgUid=d&&d.svgUid||0;this.parsingOptions=a}; +fabric.ElementsParser.prototype.parse=function(){this.instances=Array(this.elements.length);this.numElements=this.elements.length;this.createObjects()};fabric.ElementsParser.prototype.createObjects=function(){for(var e=0,b=this.elements.length;eb.x&&this.y>b.y},gte:function(b){return this.x>=b.x&&this.y>=b.y},lerp:function(d,c){"undefined"===typeof c&&(c=.5);c=Math.max(Math.min(1,c),0);return new b(this.x+(d.x-this.x)*c,this.y+(d.y-this.y)*c)},distanceFrom:function(b){var c=this.x-b.x;b=this.y-b.y;return Math.sqrt(c*c+b*b)},midPointFrom:function(b){return this.lerp(b)},min:function(d){return new b(Math.min(this.x,d.x),Math.min(this.y,d.y))},max:function(d){return new b(Math.max(this.x,d.x),Math.max(this.y, +d.y))},toString:function(){return this.x+","+this.y},setXY:function(b,c){this.x=b;this.y=c;return this},setX:function(b){this.x=b;return this},setY:function(b){this.y=b;return this},setFromPoint:function(b){this.x=b.x;this.y=b.y;return this},swap:function(b){var c=this.x,a=this.y;this.x=b.x;this.y=b.y;b.x=c;b.y=a},clone:function(){return new b(this.x,this.y)}})})("undefined"!==typeof exports?exports:this); +(function(e){function b(b){this.status=b;this.points=[]}var d=e.fabric||(e.fabric={});d.Intersection?d.warn("fabric.Intersection is already defined"):(d.Intersection=b,d.Intersection.prototype={constructor:b,appendPoint:function(b){this.points.push(b);return this},appendPoints:function(b){this.points=this.points.concat(b);return this}},d.Intersection.intersectLineLine=function(c,a,g,h){var f,l=(h.x-g.x)*(c.y-g.y)-(h.y-g.y)*(c.x-g.x);f=(a.x-c.x)*(c.y-g.y)-(a.y-c.y)*(c.x-g.x);g=(h.y-g.y)*(a.x-c.x)- +(h.x-g.x)*(a.y-c.y);0!==g?(l/=g,f/=g,0<=l&&1>=l&&0<=f&&1>=f?(f=new b("Intersection"),f.appendPoint(new d.Point(c.x+l*(a.x-c.x),c.y+l*(a.y-c.y)))):f=new b):f=0===l||0===f?new b("Coincident"):new b("Parallel");return f},d.Intersection.intersectLinePolygon=function(c,a,d){for(var g=new b,f=d.length,l,e,m=0;mc&&(c+=1);1c?b:c<2/3?a+(b-a)*(2/3-c)*6:a}var c=e.fabric||(e.fabric={});c.Color?c.warn("fabric.Color is already defined."):(c.Color=b,c.Color.prototype={_tryParsingColor:function(a){var c;a in b.colorNameMap&&(a=b.colorNameMap[a]);"transparent"===a&&(c=[255,255,255,0]);c||(c=b.sourceFromHex(a));c||(c=b.sourceFromRgb(a));c||(c=b.sourceFromHsl(a));c||(c=[0,0,0,1]);c&& +this.setSource(c)},_rgbToHsl:function(a,b,d){a/=255;b/=255;d/=255;var f,g,h,e=c.util.array.max([a,b,d]);g=c.util.array.min([a,b,d]);h=(e+g)/2;if(e===g)f=g=0;else{var n=e-g;g=.5l;l++)c.push(Math.round(.5*f[l]+.5*a[l]));c[3]=d;this.setSource(c);return this}},c.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*)?\)$/,c.Color.reHSLa= +/^hsla?\(\s*(\d{1,3})\s*,\s*(\d{1,3}\%)\s*,\s*(\d{1,3}\%)\s*(?:\s*,\s*(\d+(?:\.\d+)?)\s*)?\)$/,c.Color.reHex=/^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i,c.Color.colorNameMap={aqua:"#00FFFF",black:"#000000",blue:"#0000FF",fuchsia:"#FF00FF",gray:"#808080",grey:"#808080",green:"#008000",lime:"#00FF00",maroon:"#800000",navy:"#000080",olive:"#808000",orange:"#FFA500",purple:"#800080",red:"#FF0000",silver:"#C0C0C0",teal:"#008080",white:"#FFFFFF",yellow:"#FFFF00"},c.Color.fromRgb=function(a){return b.fromSource(b.sourceFromRgb(a))}, +c.Color.sourceFromRgb=function(a){if(a=a.match(b.reRGBa)){var c=parseInt(a[1],10)/(/%$/.test(a[1])?100:1)*(/%$/.test(a[1])?255:1),d=parseInt(a[2],10)/(/%$/.test(a[2])?100:1)*(/%$/.test(a[2])?255:1),f=parseInt(a[3],10)/(/%$/.test(a[3])?100:1)*(/%$/.test(a[3])?255:1);return[parseInt(c,10),parseInt(d,10),parseInt(f,10),a[4]?parseFloat(a[4]):1]}},c.Color.fromRgba=b.fromRgb,c.Color.fromHsl=function(a){return b.fromSource(b.sourceFromHsl(a))},c.Color.sourceFromHsl=function(a){if(a=a.match(b.reHSLa)){var c= +(parseFloat(a[1])%360+360)%360/360,h=parseFloat(a[2])/(/%$/.test(a[2])?100:1),f=parseFloat(a[3])/(/%$/.test(a[3])?100:1);if(0===h)f=h=c=f;else var l=.5>=f?f*(h+1):f+h-f*h,e=2*f-l,f=d(e,l,c+1/3),h=d(e,l,c),c=d(e,l,c-1/3);return[Math.round(255*f),Math.round(255*h),Math.round(255*c),a[4]?parseFloat(a[4]):1]}},c.Color.fromHsla=b.fromHsl,c.Color.fromHex=function(a){return b.fromSource(b.sourceFromHex(a))},c.Color.sourceFromHex=function(a){if(a.match(b.reHex)){var c=a.slice(a.indexOf("#")+1),d=3===c.length|| +4===c.length,f=8===c.length||4===c.length;a=d?c.charAt(0)+c.charAt(0):c.substring(0,2);var l=d?c.charAt(1)+c.charAt(1):c.substring(2,4),e=d?c.charAt(2)+c.charAt(2):c.substring(4,6),c=f?d?c.charAt(3)+c.charAt(3):c.substring(6,8):"FF";return[parseInt(a,16),parseInt(l,16),parseInt(e,16),parseFloat((parseInt(c,16)/255).toFixed(2))]}},c.Color.fromSource=function(a){var c=new b;c.setSource(a);return c})})("undefined"!==typeof exports?exports:this); +(function(){function e(c){var a=c.getAttribute("style"),b=c.getAttribute("offset")||0,d,f,b=parseFloat(b)/(/%$/.test(b)?100:1),b=0>b?0:1a.r2;h.sort(function(a,f){return a.offset-f.offset});if(!b.group||"path-group"!==b.group.type)for(var l in a)if("x1"===l||"x2"===l)a[l]+=this.offsetX-b.width/2;else if("y1"===l||"y2"===l)a[l]+=this.offsetY-b.height/2;b='id="SVGID_'+this.id+'" gradientUnits="userSpaceOnUse"';this.gradientTransform&&(b+=' gradientTransform="matrix('+this.gradientTransform.join(" ")+')" ');"linear"===this.type?c=["\n']:"radial"===this.type&&(c=["\n']);if("radial"===this.type){if(f)for(h=h.concat(),h.reverse(),f=0;f\n');c.push("linear"===this.type?"\n":"\n");return c.join("")},toLive:function(b,a){var c,d,f=fabric.util.object.clone(this.coords);if(this.type){if(a.group&&"path-group"===a.group.type)for(d in f)if("x1"===d||"x2"===d)f[d]+=-this.offsetX+a.width/2;else if("y1"===d||"y2"===d)f[d]+=-this.offsetY+a.height/2;"linear"===this.type?c=b.createLinearGradient(f.x1,f.y1,f.x2,f.y2):"radial"=== +this.type&&(c=b.createRadialGradient(f.x1,f.y1,f.r1,f.x2,f.y2,f.r2));d=0;for(f=this.colorStops.length;d\n\n\n'},setOptions:function(b){for(var d in b)this[d]=b[d]}, +toLive:function(b){var d="function"===typeof this.source?this.source():this.source;return d&&("undefined"===typeof d.src||d.complete&&0!==d.naturalWidth&&0!==d.naturalHeight)?b.createPattern(d,this.repeat):""}})})(); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.toFixed;b.Shadow?b.warn("fabric.Shadow is already defined."):(b.Shadow=b.util.createClass({color:"rgb(0,0,0)",blur:0,offsetX:0,offsetY:0,affectStroke:!1,includeDefaultValues:!0,initialize:function(c){"string"===typeof c&&(c=this._parseShadow(c));for(var a in c)this[a]=c[a];this.id=b.Object.__uid++},_parseShadow:function(c){c=c.trim();var a=b.Shadow.reOffsetsAndBlur.exec(c)||[];return{color:(c.replace(b.Shadow.reOffsetsAndBlur,"")||"rgb(0,0,0)").trim(), +offsetX:parseInt(a[1],10)||0,offsetY:parseInt(a[2],10)||0,blur:parseInt(a[3],10)||0}},toString:function(){return[this.offsetX,this.offsetY,this.blur,this.color].join("px ")},toSVG:function(c){var a=40,g=40,h=b.Object.NUM_FRACTION_DIGITS,f=b.util.rotateVector({x:this.offsetX,y:this.offsetY},b.util.degreesToRadians(-c.angle));c.width&&c.height&&(a=100*d((Math.abs(f.x)+this.blur)/c.width,h)+20,g=100*d((Math.abs(f.y)+this.blur)/c.height,h)+20);c.flipX&&(f.x*=-1);c.flipY&&(f.y*=-1);return'\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 c={},a=b.Shadow.prototype;["color","blur","offsetX","offsetY","affectStroke"].forEach(function(b){this[b]!==a[b]&&(c[b]=this[b])},this);return c}}),b.Shadow.reOffsetsAndBlur=/(?:\s|^)(-?\d+(?:px)?(?:\s?|$))?(-?\d+(?:px)?(?:\s?|$))?(\d+(?:px)?)?(?:\s?|$)(?:$|\s)/)})("undefined"!==typeof exports?exports:this); +(function(){if(fabric.StaticCanvas)fabric.warn("fabric.StaticCanvas is already defined.");else{var e=fabric.util.object.extend,b=fabric.util.getElementOffset,d=fabric.util.removeFromArray,c=fabric.util.toFixed,a=fabric.util.transformPoint,g=fabric.util.invertTransform,h=Error("Could not initialize `canvas` element");fabric.StaticCanvas=fabric.util.createClass(fabric.CommonMethods,{initialize:function(a,b){b||(b={});this._initStatic(a,b)},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:!1,_initStatic:function(a,b){var f=fabric.StaticCanvas.prototype.renderAll.bind(this);this._objects=[];this._createLowerCanvas(a);this._initOptions(b);this._setImageSmoothing();this.interactive||this._initRetinaScaling(); +b.overlayImage&&this.setOverlayImage(b.overlayImage,f);b.backgroundImage&&this.setBackgroundImage(b.backgroundImage,f);b.backgroundColor&&this.setBackgroundColor(b.backgroundColor,f);b.overlayColor&&this.setOverlayColor(b.overlayColor,f);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(){this._offset=b(this.lowerCanvasEl);return this},setOverlayImage:function(a,b,c){return this.__setBgOverlayImage("overlayImage",a,b,c)},setBackgroundImage:function(a,b,c){return this.__setBgOverlayImage("backgroundImage",a,b,c)},setOverlayColor:function(a,b){return this.__setBgOverlayColor("overlayColor", +a,b)},setBackgroundColor:function(a,b){return this.__setBgOverlayColor("backgroundColor",a,b)},_setImageSmoothing:function(){var a=this.getContext();a.imageSmoothingEnabled=a.imageSmoothingEnabled||a.webkitImageSmoothingEnabled||a.mozImageSmoothingEnabled||a.msImageSmoothingEnabled||a.oImageSmoothingEnabled;a.imageSmoothingEnabled=this.imageSmoothingEnabled},__setBgOverlayImage:function(a,b,c,d){"string"===typeof b?fabric.util.loadImage(b,function(b){b&&(this[a]=new fabric.Image(b,d));c&&c(b)},this, +d&&d.crossOrigin):(d&&b.setOptions(d),this[a]=b,c&&c(b));return this},__setBgOverlayColor:function(a,b,c){this[a]=b;this._initGradient(b,a);this._initPattern(b,a,c);return this},_createCanvasElement:function(a){a=fabric.util.createCanvasElement(a);a.style||(a.style={});if(!a)throw h;if("undefined"===typeof a.getContext)throw h;return a},_initOptions:function(a){this._setOptions(a);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(a){this.lowerCanvasEl=fabric.util.getById(a)||this._createCanvasElement(a);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(a,b){return this.setDimensions({width:a},b)},setHeight:function(a,b){return this.setDimensions({height:a},b)},setDimensions:function(a,b){var f;b=b||{};for(var c in a)f=a[c],b.cssOnly||(this._setBackstoreDimension(c,a[c]),f+="px"),b.backstoreOnly||this._setCssDimension(c,f);this._initRetinaScaling();this._setImageSmoothing();this.calcOffset();b.cssOnly||this.renderAll(); +return this},_setBackstoreDimension:function(a,b){this.lowerCanvasEl[a]=b;this.upperCanvasEl&&(this.upperCanvasEl[a]=b);this.cacheCanvasEl&&(this.cacheCanvasEl[a]=b);this[a]=b;return this},_setCssDimension:function(a,b){this.lowerCanvasEl.style[a]=b;this.upperCanvasEl&&(this.upperCanvasEl.style[a]=b);this.wrapperEl&&(this.wrapperEl.style[a]=b);return this},getZoom:function(){return this.viewportTransform[0]},setViewportTransform:function(a){var b=this._activeGroup;this.viewportTransform=a;for(var f= +0,c=this._objects.length;f");return c.join("")},_setSVGPreamble:function(a,b){b.suppressPreamble||a.push('\n','\n')},_setSVGHeader:function(a,b){var f=b.width||this.width,d= +b.height||this.height,g;g='viewBox="0 0 '+this.width+" "+this.height+'" ';var h=fabric.Object.NUM_FRACTION_DIGITS;b.viewBox?g='viewBox="'+b.viewBox.x+" "+b.viewBox.y+" "+b.viewBox.width+" "+b.viewBox.height+'" ':this.svgViewportTransformation&&(g=this.viewportTransform,g='viewBox="'+c(-g[4]/g[0],h)+" "+c(-g[5]/g[3],h)+" "+c(this.width/g[0],h)+" "+c(this.height/g[3],h)+'" ');a.push("\n',"Created with Fabric.js ",fabric.version,"\n","\n",this.createSVGFontFacesMarkup(),this.createSVGRefElementsMarkup(),"\n")},createSVGRefElementsMarkup:function(){var a=this;return["backgroundColor","overlayColor"].map(function(b){if((b=a[b])&&b.toLive)return b.toSVG(a,!1)}).join("")},createSVGFontFacesMarkup:function(){for(var a="",b={},c,d,g,h,e,t=fabric.fontPaths,r=this.getObjects(),v=0,A=r.length;v\n',a,"]]\x3e</style>\n"].join(""));return a},_setSVGObjects:function(a,b){for(var c,f=0,d=this.getObjects(),g=d.length;f<g;f++)c=d[f],c.excludeFromExport||this._setSVGObject(a,c,b)},_setSVGObject:function(a, +b,c){a.push(b.toSVG(c))},_setSVGBgOverlayImage:function(a,b,c){this[b]&&this[b].toSVG&&a.push(this[b].toSVG(c))},_setSVGBgOverlayColor:function(a,b){var c=this[b];if(c)if(c.toLive){var f=c.repeat;a.push('<rect transform="translate(',this.width/2,",",this.height/2,')"',' x="',c.offsetX-this.width/2,'" y="',c.offsetY-this.height/2,'" ','width="',"repeat-y"===f||"no-repeat"===f?c.source.width:this.width,'" height="',"repeat-x"===f||"no-repeat"===f?c.source.height:this.height,'" fill="url(#SVGID_'+c.id+ +')"',"></rect>\n")}else a.push('<rect x="0" y="0" ','width="',this.width,'" height="',this.height,'" fill="',this[b],'"',"></rect>\n")},sendToBack:function(a){if(!a)return this;var b=this._activeGroup,c;if(a===b)for(c=b._objects,a=c.length;a--;)b=c[a],d(this._objects,b),this._objects.unshift(b);else d(this._objects,a),this._objects.unshift(a);return this.renderAll&&this.renderAll()},bringToFront:function(a){if(!a)return this;var b=this._activeGroup,c;if(a===b)for(c=b._objects,a=0;a<c.length;a++)b= +c[a],d(this._objects,b),this._objects.push(b);else d(this._objects,a),this._objects.push(a);return this.renderAll&&this.renderAll()},sendBackwards:function(a,b){if(!a)return this;var c=this._activeGroup,f,g,h,e=0;if(a===c)for(h=c._objects,c=0;c<h.length;c++)f=h[c],g=this._objects.indexOf(f),g>0+e&&(--g,d(this._objects,f),this._objects.splice(g,0,f)),e++;else g=this._objects.indexOf(a),0!==g&&(g=this._findNewLowerIndex(a,g,b),d(this._objects,a),this._objects.splice(g,0,a));this.renderAll&&this.renderAll(); +return this},_findNewLowerIndex:function(a,b,c){if(c)for(c=b,--b;0<=b;--b){if(a.intersectsWithObject(this._objects[b])||a.isContainedWithinObject(this._objects[b])||this._objects[b].isContainedWithinObject(a)){c=b;break}}else c=b-1;return c},bringForward:function(a,b){if(!a)return this;var c=this._activeGroup,f,g,h,e=0;if(a===c)for(h=c._objects,c=h.length;c--;)f=h[c],g=this._objects.indexOf(f),g<this._objects.length-1-e&&(g+=1,d(this._objects,f),this._objects.splice(g,0,f)),e++;else g=this._objects.indexOf(a), +g!==this._objects.length-1&&(g=this._findNewUpperIndex(a,g,b),d(this._objects,a),this._objects.splice(g,0,a));this.renderAll&&this.renderAll();return this},_findNewUpperIndex:function(a,b,c){if(c)for(c=b,b+=1;b<this._objects.length;++b){if(a.intersectsWithObject(this._objects[b])||a.isContainedWithinObject(this._objects[b])||this._objects[b].isContainedWithinObject(a)){c=b;break}}else c=b+1;return c},moveTo:function(a,b){d(this._objects,a);this._objects.splice(b,0,a);return this.renderAll&&this.renderAll()}, +dispose:function(){this.clear();return this},toString:function(){return"#<fabric.Canvas ("+this.complexity()+"): { objects: "+this.getObjects().length+" }>"}});e(fabric.StaticCanvas.prototype,fabric.Observable);e(fabric.StaticCanvas.prototype,fabric.Collection);e(fabric.StaticCanvas.prototype,fabric.DataURLExporter);e(fabric.StaticCanvas,{EMPTY_JSON:'{"objects": [], "background": "white"}',supports:function(a){var b=fabric.util.createCanvasElement();if(!b||!b.getContext)return null;var c=b.getContext("2d"); +if(!c)return null;switch(a){case "getImageData":return"undefined"!==typeof c.getImageData;case "setLineDash":return"undefined"!==typeof c.setLineDash;case "toDataURL":return"undefined"!==typeof b.toDataURL;case "toDataURLWithQuality":try{return b.toDataURL("image/jpeg",0),!0}catch(m){}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(e){this.shadow=new fabric.Shadow(e);return this},_setBrushStyles:function(){var e=this.canvas.contextTop;e.strokeStyle=this.color;e.lineWidth=this.width;e.lineCap=this.strokeLineCap;e.lineJoin=this.strokeLineJoin;this.strokeDashArray&&fabric.StaticCanvas.supports("setLineDash")&&e.setLineDash(this.strokeDashArray)},_setShadow:function(){if(this.shadow){var e= +this.canvas.contextTop,b=this.canvas.getZoom();e.shadowColor=this.shadow.color;e.shadowBlur=this.shadow.blur*b;e.shadowOffsetX=this.shadow.offsetX*b;e.shadowOffsetY=this.shadow.offsetY*b}},_resetShadow:function(){var e=this.canvas.contextTop;e.shadowColor="";e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0}}); +(function(){fabric.PencilBrush=fabric.util.createClass(fabric.BaseBrush,{initialize:function(e){this.canvas=e;this._points=[]},onMouseDown:function(e){this._prepareForDrawing(e);this._captureDrawingPath(e);this._render()},onMouseMove:function(e){this._captureDrawingPath(e);this.canvas.clearContext(this.canvas.contextTop);this._render()},onMouseUp:function(){this._finalizeAndAddPath()},_prepareForDrawing:function(e){e=new fabric.Point(e.x,e.y);this._reset();this._addPoint(e);this.canvas.contextTop.moveTo(e.x, +e.y)},_addPoint:function(e){1<this._points.length&&e.eq(this._points[this._points.length-1])||this._points.push(e)},_reset:function(){this._points.length=0;this._setBrushStyles();this._setShadow()},_captureDrawingPath:function(e){e=new fabric.Point(e.x,e.y);this._addPoint(e)},_render:function(){var e=this.canvas.contextTop,b,d;b=this.canvas.viewportTransform;var c=this._points[0],a=this._points[1];e.save();e.transform(b[0],b[1],b[2],b[3],b[4],b[5]);e.beginPath();2===this._points.length&&c.x===a.x&& +c.y===a.y&&(b=this.width/1E3,c=new fabric.Point(c.x,c.y),a=new fabric.Point(a.x,a.y),c.x-=b,a.x+=b);e.moveTo(c.x,c.y);b=1;for(d=this._points.length;b<d;b++)a=c.midPointFrom(a),e.quadraticCurveTo(c.x,c.y,a.x,a.y),c=this._points[b],a=this._points[b+1];e.lineTo(c.x,c.y);e.stroke();e.restore()},convertPointsToSVGPath:function(e){var b=[],d,c=this.width/1E3,a=new fabric.Point(e[0].x,e[0].y),g=new fabric.Point(e[1].x,e[1].y),h=e.length,f=1,l=1,k=2<h;k&&(f=e[2].x<g.x?-1:e[2].x===g.x?0:1,l=e[2].y<g.y?-1: +e[2].y===g.y?0:1);b.push("M ",a.x-f*c," ",a.y-l*c," ");for(d=1;d<h;d++){if(!a.eq(g)){var m=a.midPointFrom(g);b.push("Q ",a.x," ",a.y," ",m.x," ",m.y," ")}a=e[d];d+1<e.length&&(g=e[d+1])}k&&(f=a.x>e[d-2].x?1:a.x===e[d-2].x?0:-1,l=a.y>e[d-2].y?1:a.y===e[d-2].y?0:-1);b.push("L ",a.x+f*c," ",a.y+l*c);return b},createPath:function(e){e=new fabric.Path(e,{fill:null,stroke:this.color,strokeWidth:this.width,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeDashArray:this.strokeDashArray, +originX:"center",originY:"center"});var b=new fabric.Point(e.left,e.top);e.originX=fabric.Object.prototype.originX;e.originY=fabric.Object.prototype.originY;b=e.translateToGivenOrigin(b,"center","center",e.originX,e.originY);e.top=b.y;e.left=b.x;this.shadow&&(this.shadow.affectStroke=!0,e.setShadow(this.shadow));return e},_finalizeAndAddPath:function(){this.canvas.contextTop.closePath();var e=this.convertPointsToSVGPath(this._points).join("");"M 0 0 Q 0 0 0 0 L 0 0"===e?this.canvas.renderAll():(e= +this.createPath(e),this.canvas.add(e),e.setCoords(),this.canvas.clearContext(this.canvas.contextTop),this._resetShadow(),this.canvas.renderAll(),this.canvas.fire("path:created",{path:e}))}})})(); +fabric.CircleBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,initialize:function(e){this.canvas=e;this.points=[]},drawDot:function(e){e=this.addPoint(e);var b=this.canvas.contextTop,d=this.canvas.viewportTransform;b.save();b.transform(d[0],d[1],d[2],d[3],d[4],d[5]);b.fillStyle=e.fill;b.beginPath();b.arc(e.x,e.y,e.radius,0,2*Math.PI,!1);b.closePath();b.fill();b.restore()},onMouseDown:function(e){this.points.length=0;this.canvas.clearContext(this.canvas.contextTop);this._setShadow();this.drawDot(e)}, +onMouseMove:function(e){this.drawDot(e)},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove=!1;for(var b=[],d=0,c=this.points.length;d<c;d++){var a=this.points[d],a=new fabric.Circle({radius:a.radius,left:a.x,top:a.y,originX:"center",originY:"center",fill:a.fill});this.shadow&&a.setShadow(this.shadow);b.push(a)}b=new fabric.Group(b,{originX:"center",originY:"center"});b.canvas=this.canvas;this.canvas.add(b);this.canvas.fire("path:created",{path:b});this.canvas.clearContext(this.canvas.contextTop); +this._resetShadow();this.canvas.renderOnAddRemove=e;this.canvas.renderAll()},addPoint:function(e){e=new fabric.Point(e.x,e.y);var b=fabric.util.getRandomInt(Math.max(0,this.width-20),this.width+20)/2,d=(new fabric.Color(this.color)).setAlpha(fabric.util.getRandomInt(0,100)/100).toRgba();e.radius=b;e.fill=d;this.points.push(e);return e}}); +fabric.SprayBrush=fabric.util.createClass(fabric.BaseBrush,{width:10,density:20,dotWidth:1,dotWidthVariance:1,randomOpacity:!1,optimizeOverlapping:!0,initialize:function(e){this.canvas=e;this.sprayChunks=[]},onMouseDown:function(e){this.sprayChunks.length=0;this.canvas.clearContext(this.canvas.contextTop);this._setShadow();this.addSprayChunk(e);this.render()},onMouseMove:function(e){this.addSprayChunk(e);this.render()},onMouseUp:function(){var e=this.canvas.renderOnAddRemove;this.canvas.renderOnAddRemove= +!1;for(var b=[],d=0,c=this.sprayChunks.length;d<c;d++)for(var a=this.sprayChunks[d],g=0,h=a.length;g<h;g++){var f=new fabric.Rect({width:a[g].width,height:a[g].width,left:a[g].x+1,top:a[g].y+1,originX:"center",originY:"center",fill:this.color});this.shadow&&f.setShadow(this.shadow);b.push(f)}this.optimizeOverlapping&&(b=this._getOptimizedRects(b));b=new fabric.Group(b,{originX:"center",originY:"center"});b.canvas=this.canvas;this.canvas.add(b);this.canvas.fire("path:created",{path:b});this.canvas.clearContext(this.canvas.contextTop); +this._resetShadow();this.canvas.renderOnAddRemove=e;this.canvas.renderAll()},_getOptimizedRects:function(e){for(var b={},d,c=0,a=e.length;c<a;c++)d=e[c].left+""+e[c].top,b[d]||(b[d]=e[c]);e=[];for(d in b)e.push(b[d]);return e},render:function(){var e=this.canvas.contextTop;e.fillStyle=this.color;var b=this.canvas.viewportTransform;e.save();e.transform(b[0],b[1],b[2],b[3],b[4],b[5]);for(var b=0,d=this.sprayChunkPoints.length;b<d;b++){var c=this.sprayChunkPoints[b];"undefined"!==typeof c.opacity&&(e.globalAlpha= +c.opacity);e.fillRect(c.x,c.y,c.width,c.width)}e.restore()},addSprayChunk:function(e){this.sprayChunkPoints=[];for(var b,d,c,a=this.width/2,g=0;g<this.density;g++)b=fabric.util.getRandomInt(e.x-a,e.x+a),d=fabric.util.getRandomInt(e.y-a,e.y+a),c=this.dotWidthVariance?fabric.util.getRandomInt(Math.max(1,this.dotWidth-this.dotWidthVariance),this.dotWidth+this.dotWidthVariance):this.dotWidth,b=new fabric.Point(b,d),b.width=c,this.randomOpacity&&(b.opacity=fabric.util.getRandomInt(0,100)/100),this.sprayChunkPoints.push(b); +this.sprayChunks.push(this.sprayChunkPoints)}}); +fabric.PatternBrush=fabric.util.createClass(fabric.PencilBrush,{getPatternSrc:function(){var e=fabric.document.createElement("canvas"),b=e.getContext("2d");e.width=e.height=25;b.fillStyle=this.color;b.beginPath();b.arc(10,10,10,0,2*Math.PI,!1);b.closePath();b.fill();return e},getPatternSrcFunction:function(){return String(this.getPatternSrc).replace("this.color",'"'+this.color+'"')},getPattern:function(){return this.canvas.contextTop.createPattern(this.source||this.getPatternSrc(),"repeat")},_setBrushStyles:function(){this.callSuper("_setBrushStyles"); +this.canvas.contextTop.strokeStyle=this.getPattern()},createPath:function(e){e=this.callSuper("createPath",e);var b=e._getLeftTopCoords().scalarAdd(e.strokeWidth/2);e.stroke=new fabric.Pattern({source:this.source||this.getPatternSrcFunction(),offsetX:-b.x,offsetY:-b.y});return e}}); +(function(){var e=fabric.util.getPointer,b=fabric.util.degreesToRadians,d=fabric.util.radiansToDegrees,c=Math.atan2,a=Math.abs,g=fabric.StaticCanvas.supports("setLineDash");fabric.Canvas=fabric.util.createClass(fabric.StaticCanvas,{initialize:function(a,b){b||(b={});this._initStatic(a,b);this._initInteractive();this._createCacheCanvas()},uniScaleTransform:!1,uniScaleKey:"shiftKey",centeredScaling:!1,centeredRotation:!1,centeredKey:"altKey",altActionKey:"shiftKey",interactive:!0,selection:!0,selectionKey:"shiftKey", +altSelectionKey:null,selectionColor:"rgba(100, 100, 255, 0.3)",selectionDashArray:[],selectionBorderColor:"rgba(255, 255, 255, 0.3)",selectionLineWidth:1,hoverCursor:"move",moveCursor:"move",defaultCursor:"default",freeDrawingCursor:"crosshair",rotationCursor:"crosshair",containerClass:"canvas-container",perPixelTargetFind:!1,targetFindTolerance:0,skipTargetFind:!1,isDrawingMode:!1,preserveObjectStacking:!1,snapAngle:0,snapThreshold:null,stopContextMenu:!1,fireRightClick:!1,fireMiddleClick:!1,_initInteractive:function(){this._groupSelector= +this._currentTransform=null;this._initWrapperElement();this._createUpperCanvas();this._initEventListeners();this._initRetinaScaling();this.freeDrawingBrush=fabric.PencilBrush&&new fabric.PencilBrush(this);this.calcOffset()},_chooseObjectsToRender:function(){var a=this.getActiveGroup(),b=this.getActiveObject(),c,d=[],g=[];if(!a&&!b||this.preserveObjectStacking)d=this._objects;else{for(var h=0,e=this._objects.length;h<e;h++)c=this._objects[h],a&&a.contains(c)||c===b?g.push(c):d.push(c);a&&(a._set("_objects", +g),d.push(a));b&&d.push(b)}return d},renderAll:function(){!this.contextTopDirty||this._groupSelector||this.isDrawingMode||(this.clearContext(this.contextTop),this.contextTopDirty=!1);this.renderCanvas(this.contextContainer,this._chooseObjectsToRender());return this},renderTop:function(){var a=this.contextTop;this.clearContext(a);this.selection&&this._groupSelector&&this._drawSelection(a);this.fire("after:render");this.contextTopDirty=!0;return this},_resetCurrentTransform:function(){var a=this._currentTransform; +a.target.set({scaleX:a.original.scaleX,scaleY:a.original.scaleY,skewX:a.original.skewX,skewY:a.original.skewY,left:a.original.left,top:a.original.top});this._shouldCenterTransform(a.target)?"rotate"===a.action?this._setOriginToCenter(a.target):("center"!==a.originX&&(a.mouseXSign="right"===a.originX?-1:1),"center"!==a.originY&&(a.mouseYSign="bottom"===a.originY?-1:1),a.originX="center",a.originY="center"):(a.originX=a.original.originX,a.originY=a.original.originY)},containsPoint:function(a,b,c){a= +c||this.getPointer(a,!0);c=b.group&&b.group===this.getActiveGroup()?this._normalizePointer(b.group,a):{x:a.x,y:a.y};return b.containsPoint(c)||b._findTargetCorner(a)},_normalizePointer:function(a,b){var c=a.calcTransformMatrix(),c=fabric.util.invertTransform(c),f=this.restorePointerVpt(b);return fabric.util.transformPoint(f,c)},isTargetTransparent:function(a,b,c){var f=a.hasBorders,d=a.transparentCorners,g=this.contextCache,h=a.selectionBackgroundColor;a.hasBorders=a.transparentCorners=!1;a.selectionBackgroundColor= +"";g.save();g.transform.apply(g,this.viewportTransform);a.render(g);g.restore();a.active&&a._renderControls(g);a.hasBorders=f;a.transparentCorners=d;a.selectionBackgroundColor=h;a=fabric.util.isTransparent(g,b,c,this.targetFindTolerance);this.clearContext(g);return a},_shouldClearSelection:function(a,b){var c=this.getActiveGroup(),f=this.getActiveObject();return!b||b&&c&&!c.contains(b)&&c!==b&&!a[this.selectionKey]||b&&!b.evented||b&&!b.selectable&&f&&f!==b},_shouldCenterTransform:function(a){if(a){var b= +this._currentTransform,c;"scale"===b.action||"scaleX"===b.action||"scaleY"===b.action?c=this.centeredScaling||a.centeredScaling:"rotate"===b.action&&(c=this.centeredRotation||a.centeredRotation);return c?!b.altKey:b.altKey}},_getOriginFromCorner:function(a,b){var c={x:a.originX,y:a.originY};if("ml"===b||"tl"===b||"bl"===b)c.x="right";else if("mr"===b||"tr"===b||"br"===b)c.x="left";if("tl"===b||"mt"===b||"tr"===b)c.y="bottom";else if("bl"===b||"mb"===b||"br"===b)c.y="top";return c},_getActionFromCorner:function(a, +b,c){if(!b)return"drag";switch(b){case "mtr":return"rotate";case "ml":case "mr":return c[this.altActionKey]?"skewY":"scaleX";case "mt":case "mb":return c[this.altActionKey]?"skewX":"scaleY";default:return"scale"}},_setupCurrentTransform:function(a,c){if(c){var f=this.getPointer(a),d=c._findTargetCorner(this.getPointer(a,!0)),g=this._getActionFromCorner(c,d,a),h=this._getOriginFromCorner(c,d);this._currentTransform={target:c,action:g,corner:d,scaleX:c.scaleX,scaleY:c.scaleY,skewX:c.skewX,skewY:c.skewY, +offsetX:f.x-c.left,offsetY:f.y-c.top,originX:h.x,originY:h.y,ex:f.x,ey:f.y,lastX:f.x,lastY:f.y,left:c.left,top:c.top,theta:b(c.angle),width:c.width*c.scaleX,mouseXSign:1,mouseYSign:1,shiftKey:a.shiftKey,altKey:a[this.centeredKey]};this._currentTransform.original={left:c.left,top:c.top,scaleX:c.scaleX,scaleY:c.scaleY,skewX:c.skewX,skewY:c.skewY,originX:h.x,originY:h.y};this._resetCurrentTransform()}},_translateObject:function(a,b){var c=this._currentTransform,f=c.target,d=a-c.offsetX,c=b-c.offsetY, +g=!f.get("lockMovementX")&&f.left!==d,h=!f.get("lockMovementY")&&f.top!==c;g&&f.set("left",d);h&&f.set("top",c);return g||h},_changeSkewTransformOrigin:function(a,b,c){var f="originX",d={0:"center"},g=b.target.skewX,h="left",e="right",l="mt"===b.corner||"ml"===b.corner?1:-1,k=1;a=0<a?1:-1;"y"===c&&(g=b.target.skewY,h="top",e="bottom",f="originY");d[-1]=h;d[1]=e;b.target.flipX&&(k*=-1);b.target.flipY&&(k*=-1);0===g?(b.skewSign=-l*a*k,b[f]=d[-a]):(g=0<g?1:-1,b.skewSign=g,b[f]=d[g*l*k])},_skewObject:function(a, +b,c){var f=this._currentTransform,d=f.target,g=d.get("lockSkewingX"),h=d.get("lockSkewingY");if(g&&"x"===c||h&&"y"===c)return!1;var h=d.getCenterPoint(),e=d.toLocalPoint(new fabric.Point(a,b),"center","center")[c],l=d.toLocalPoint(new fabric.Point(f.lastX,f.lastY),"center","center")[c],g=d._getTransformedDimensions();this._changeSkewTransformOrigin(e-l,f,c);e=d.toLocalPoint(new fabric.Point(a,b),f.originX,f.originY)[c];h=d.translateToOriginPoint(h,f.originX,f.originY);c=this._setObjectSkew(e,f,c, +g);f.lastX=a;f.lastY=b;d.setPositionByOrigin(h,f.originX,f.originY);return c},_setObjectSkew:function(a,b,c,d){var f=b.target,g=b.skewSign,h,e,l,k;"x"===c?(b="y",l="Y",h="X",e=0,k=f.skewY):(b="x",l="X",h="Y",e=f.skewX,k=0);e=f._getTransformedDimensions(e,k);a=2*Math.abs(a)-e[c];2>=a?c=0:(c=g*Math.atan(a/f["scale"+h]/(e[b]/f["scale"+l])),c=fabric.util.radiansToDegrees(c));a=f["skew"+h]!==c;f.set("skew"+h,c);0!==f["skew"+l]&&(h=f._getTransformedDimensions(),c=d[b]/h[b]*f["scale"+l],f.set("scale"+l, +c));return a},_scaleObject:function(a,b,c){var f=this._currentTransform,d=f.target,g=d.get("lockScalingX"),h=d.get("lockScalingY"),e=d.get("lockScalingFlip");if(g&&h)return!1;var l=d.translateToOriginPoint(d.getCenterPoint(),f.originX,f.originY);a=d.toLocalPoint(new fabric.Point(a,b),f.originX,f.originY);b=d._getTransformedDimensions();this._setLocalMouse(a,f);c=this._setObjectScale(a,f,g,h,c,e,b);d.setPositionByOrigin(l,f.originX,f.originY);return c},_setObjectScale:function(a,b,c,d,g,h,e){var f= +b.target,l=!1,k=!1,m=!1,n,p,q,u;q=a.x*f.scaleX/e.x;u=a.y*f.scaleY/e.y;n=f.scaleX!==q;p=f.scaleY!==u;h&&0>=q&&q<f.scaleX&&(l=!0);h&&0>=u&&u<f.scaleY&&(k=!0);"equally"!==g||c||d?g?"x"!==g||f.get("lockUniScaling")?"y"!==g||f.get("lockUniScaling")||k||d||f.set("scaleY",u)&&(m=m||p):l||c||f.set("scaleX",q)&&(m=m||n):(l||c||f.set("scaleX",q)&&(m=m||n),k||d||f.set("scaleY",u)&&(m=m||p)):l||k||(m=this._scaleObjectEqually(a,f,b,e));b.newScaleX=q;b.newScaleY=u;l||k||this._flipObject(b,g);return m},_scaleObjectEqually:function(a, +b,c,d){var f=a.y+a.x;d=d.y*c.original.scaleY/b.scaleY+d.x*c.original.scaleX/b.scaleX;var g=a.y/Math.abs(a.y);c.newScaleX=a.x/Math.abs(a.x)*Math.abs(c.original.scaleX*f/d);c.newScaleY=g*Math.abs(c.original.scaleY*f/d);a=c.newScaleX!==b.scaleX||c.newScaleY!==b.scaleY;b.set("scaleX",c.newScaleX);b.set("scaleY",c.newScaleY);return a},_flipObject:function(a,b){0>a.newScaleX&&"y"!==b&&("left"===a.originX?a.originX="right":"right"===a.originX&&(a.originX="left"));0>a.newScaleY&&"x"!==b&&("top"===a.originY? +a.originY="bottom":"bottom"===a.originY&&(a.originY="top"))},_setLocalMouse:function(b,c){var d=c.target,f=this.getZoom(),d=d.padding/f;"right"===c.originX?b.x*=-1:"center"===c.originX&&(b.x=2*b.x*c.mouseXSign,0>b.x&&(c.mouseXSign=-c.mouseXSign));"bottom"===c.originY?b.y*=-1:"center"===c.originY&&(b.y=2*b.y*c.mouseYSign,0>b.y&&(c.mouseYSign=-c.mouseYSign));a(b.x)>d?b.x=0>b.x?b.x+d:b.x-d:b.x=0;a(b.y)>d?b.y=0>b.y?b.y+d:b.y-d:b.y=0},_rotateObject:function(a,b){var f=this._currentTransform;if(f.target.get("lockRotation"))return!1; +var g=c(f.ey-f.top,f.ex-f.left),h=c(b-f.top,a-f.left),g=d(h-g+f.theta),h=!0;if(0<f.target.snapAngle){var e=f.target.snapAngle,l=f.target.snapThreshold||e,t=Math.ceil(g/e)*e,e=Math.floor(g/e)*e;Math.abs(g-e)<l?g=e:Math.abs(g-t)<l&&(g=t)}0>g&&(g=360+g);g%=360;f.target.angle===g?h=!1:f.target.angle=g;return h},setCursor:function(a){this.upperCanvasEl.style.cursor=a},_resetObjectTransform:function(a){a.scaleX=1;a.scaleY=1;a.skewX=0;a.skewY=0;a.setAngle(0)},_drawSelection:function(b){var c=this._groupSelector, +d=c.left,f=c.top,h=a(d),e=a(f);this.selectionColor&&(b.fillStyle=this.selectionColor,b.fillRect(c.ex-(0<d?0:-d),c.ey-(0<f?0:-f),h,e));this.selectionLineWidth&&this.selectionBorderColor&&(b.lineWidth=this.selectionLineWidth,b.strokeStyle=this.selectionBorderColor,1<this.selectionDashArray.length&&!g?(d=c.ex+.5-(0<d?0:h),c=c.ey+.5-(0<f?0:e),b.beginPath(),fabric.util.drawDashedLine(b,d,c,d+h,c,this.selectionDashArray),fabric.util.drawDashedLine(b,d,c+e-1,d+h,c+e-1,this.selectionDashArray),fabric.util.drawDashedLine(b, +d,c,d,c+e,this.selectionDashArray),fabric.util.drawDashedLine(b,d+h-1,c,d+h-1,c+e,this.selectionDashArray),b.closePath(),b.stroke()):(fabric.Object.prototype._setLineDash.call(this,b,this.selectionDashArray),b.strokeRect(c.ex+.5-(0<d?0:h),c.ey+.5-(0<f?0:e),h,e)))},findTarget:function(a,b){if(!this.skipTargetFind){var c=this.getPointer(a,!0),d=this.getActiveGroup(),f=this.getActiveObject(),g,h;this.targets=[];if(d&&!b&&d===this._searchPossibleTargets([d],c))return this._fireOverOutEvents(d,a),d;if(f&& +f._findTargetCorner(c))return this._fireOverOutEvents(f,a),f;if(f&&f===this._searchPossibleTargets([f],c))if(this.preserveObjectStacking)g=f,h=this.targets,this.targets=[];else return this._fireOverOutEvents(f,a),f;c=this._searchPossibleTargets(this._objects,c);a[this.altSelectionKey]&&c&&g&&c!==g&&(c=g,this.targets=h);this._fireOverOutEvents(c,a);return c}},_fireOverOutEvents:function(a,b){var c,d,f=this._hoveredTarget;f!==a&&(c={e:b,target:a,previousTarget:this._hoveredTarget},d={e:b,target:this._hoveredTarget, +nextTarget:a},this._hoveredTarget=a);a?f!==a&&(f&&(this.fire("mouse:out",d),f.fire("mouseout",d)),this.fire("mouse:over",c),a.fire("mouseover",c)):f&&(this.fire("mouse:out",d),f.fire("mouseout",d))},_checkTarget:function(a,b){if(b&&b.visible&&b.evented&&this.containsPoint(null,b,a)&&(!this.perPixelTargetFind&&!b.perPixelTargetFind||b.isEditing||!this.isTargetTransparent(b,a.x,a.y)))return!0},_searchPossibleTargets:function(a,b){for(var c,d=a.length;d--;)if(this._checkTarget(b,a[d])){c=a[d];"group"=== +c.type&&c.subTargetCheck&&(d=this._normalizePointer(c,b),(d=this._searchPossibleTargets(c._objects,d))&&this.targets.push(d));break}return c},restorePointerVpt:function(a){return fabric.util.transformPoint(a,fabric.util.invertTransform(this.viewportTransform))},getPointer:function(a,b,c){c||(c=this.upperCanvasEl);a=e(a);var d=c.getBoundingClientRect(),f=d.width||0,g=d.height||0;f&&g||("top"in d&&"bottom"in d&&(g=Math.abs(d.top-d.bottom)),"right"in d&&"left"in d&&(f=Math.abs(d.right-d.left)));this.calcOffset(); +a.x-=this._offset.left;a.y-=this._offset.top;b||(a=this.restorePointerVpt(a));0===f||0===g?c=b=1:(b=c.width/f,c=c.height/g);return{x:a.x*b,y:a.y*c}},_createUpperCanvas:function(){var a=this.lowerCanvasEl.className.replace(/\s*lower-canvas\s*/,"");this.upperCanvasEl?this.upperCanvasEl.className="":this.upperCanvasEl=this._createCanvasElement();fabric.util.addClass(this.upperCanvasEl,"upper-canvas "+a);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(a){var b=this.getWidth()||a.width,c=this.getHeight()||a.height;fabric.util.setStyle(a,{position:"absolute",width:b+"px",height:c+"px",left:0,top:0,"touch-action":"none"});a.width=b;a.height=c;fabric.util.makeElementUnselectable(a)},_copyCanvasStyle:function(a,b){b.style.cssText=a.style.cssText},getSelectionContext:function(){return this.contextTop},getSelectionElement:function(){return this.upperCanvasEl}, +_setActiveObject:function(a){var b=this._activeObject;if(b&&(b.set("active",!1),a!==b&&b.onDeselect&&"function"===typeof b.onDeselect))b.onDeselect();this._activeObject=a;a.set("active",!0)},setActiveObject:function(a,b){var c=this.getActiveObject();c&&c!==a&&c.fire("deselected",{e:b});this._setActiveObject(a);this.fire("object:selected",{target:a,e:b});a.fire("selected",{e:b});this.renderAll();return this},getActiveObject:function(){return this._activeObject},_onObjectRemoved:function(a){this.getActiveObject()=== +a&&(this.fire("before:selection:cleared",{target:a}),this._discardActiveObject(),this.fire("selection:cleared",{target:a}),a.fire("deselected"));this._hoveredTarget===a&&(this._hoveredTarget=null);this.callSuper("_onObjectRemoved",a)},_discardActiveObject:function(){var a=this._activeObject;if(a&&(a.set("active",!1),a.onDeselect&&"function"===typeof a.onDeselect))a.onDeselect();this._activeObject=null},discardActiveObject:function(a){var b=this._activeObject;b&&(this.fire("before:selection:cleared", +{target:b,e:a}),this._discardActiveObject(),this.fire("selection:cleared",{e:a}),b.fire("deselected",{e:a}));return this},_setActiveGroup:function(a){(this._activeGroup=a)&&a.set("active",!0)},setActiveGroup:function(a,b){this._setActiveGroup(a);a&&(this.fire("object:selected",{target:a,e:b}),a.fire("selected",{e:b}));return this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var a=this.getActiveGroup();a&&a.destroy();this.setActiveGroup(null)},discardActiveGroup:function(a){var b= +this.getActiveGroup();b&&(this.fire("before:selection:cleared",{e:a,target:b}),this._discardActiveGroup(),this.fire("selection:cleared",{e:a}));return this},deactivateAll:function(){for(var a=this.getObjects(),b=0,c=a.length,d;b<c;b++)(d=a[b])&&d.set("active",!1);this._discardActiveGroup();this._discardActiveObject();return this},deactivateAllWithDispatch:function(a){for(var b=this.getObjects(),c=0,d=b.length,f;c<d;c++)(f=b[c])&&f.set("active",!1);this.discardActiveGroup(a);this.discardActiveObject(a); +return this},dispose:function(){fabric.StaticCanvas.prototype.dispose.call(this);var a=this.wrapperEl;this.removeListeners();a.removeChild(this.upperCanvasEl);a.removeChild(this.lowerCanvasEl);delete this.upperCanvasEl;a.parentNode&&a.parentNode.replaceChild(this.lowerCanvasEl,this.wrapperEl);delete this.wrapperEl;return this},clear:function(){this.discardActiveGroup();this.discardActiveObject();this.clearContext(this.contextTop);return this.callSuper("clear")},drawControls:function(a){var b=this.getActiveGroup(); +b?b._renderControls(a):this._drawObjectsControls(a)},_drawObjectsControls:function(a){for(var b=0,c=this._objects.length;b<c;++b)this._objects[b]&&this._objects[b].active&&this._objects[b]._renderControls(a)},_toObject:function(a,b,c){var d=this._realizeGroupTransformOnObject(a);b=this.callSuper("_toObject",a,b,c);this._unwindGroupTransformOnObject(a,d);return b},_realizeGroupTransformOnObject:function(a){if(a.group&&a.group===this.getActiveGroup()){var b={};"angle flipX flipY left scaleX scaleY skewX skewY top".split(" ").forEach(function(c){b[c]= +a[c]});this.getActiveGroup().realizeTransform(a);return b}return null},_unwindGroupTransformOnObject:function(a,b){b&&a.set(b)},_setSVGObject:function(a,b,c){var d;d=this._realizeGroupTransformOnObject(b);this.callSuper("_setSVGObject",a,b,c);this._unwindGroupTransformOnObject(b,d)}});for(var h in fabric.StaticCanvas)"prototype"!==h&&(fabric.Canvas[h]=fabric.StaticCanvas[h]);fabric.isTouchSupported&&(fabric.Canvas.prototype._setCursorFromEvent=function(){});fabric.Element=fabric.Canvas})(); +(function(){function e(a,b){return"which"in a?a.which===b:a.button===b-1}var b={mt:0,tr:1,mr:2,br:3,mb:4,bl:5,ml:6,tl:7},d=fabric.util.addListener,c=fabric.util.removeListener;fabric.util.object.extend(fabric.Canvas.prototype,{cursorMap:"n-resize ne-resize e-resize se-resize s-resize sw-resize w-resize nw-resize".split(" "),_initEventListeners:function(){this.removeListeners();this._bindEvents();d(fabric.window,"resize",this._onResize);d(this.upperCanvasEl,"mousedown",this._onMouseDown);d(this.upperCanvasEl, +"mousemove",this._onMouseMove);d(this.upperCanvasEl,"mouseout",this._onMouseOut);d(this.upperCanvasEl,"mouseenter",this._onMouseEnter);d(this.upperCanvasEl,"wheel",this._onMouseWheel);d(this.upperCanvasEl,"contextmenu",this._onContextMenu);d(this.upperCanvasEl,"touchstart",this._onMouseDown,{passive:!1});d(this.upperCanvasEl,"touchmove",this._onMouseMove,{passive:!1});"undefined"!==typeof eventjs&&"add"in eventjs&&(eventjs.add(this.upperCanvasEl,"gesture",this._onGesture),eventjs.add(this.upperCanvasEl, +"drag",this._onDrag),eventjs.add(this.upperCanvasEl,"orientation",this._onOrientationChange),eventjs.add(this.upperCanvasEl,"shake",this._onShake),eventjs.add(this.upperCanvasEl,"longpress",this._onLongPress))},_bindEvents:function(){this.eventsBinded||(this._onMouseDown=this._onMouseDown.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._onMouseUp=this._onMouseUp.bind(this),this._onResize=this._onResize.bind(this),this._onGesture=this._onGesture.bind(this),this._onDrag=this._onDrag.bind(this), +this._onShake=this._onShake.bind(this),this._onLongPress=this._onLongPress.bind(this),this._onOrientationChange=this._onOrientationChange.bind(this),this._onMouseWheel=this._onMouseWheel.bind(this),this._onMouseOut=this._onMouseOut.bind(this),this._onMouseEnter=this._onMouseEnter.bind(this),this._onContextMenu=this._onContextMenu.bind(this),this.eventsBinded=!0)},removeListeners:function(){c(fabric.window,"resize",this._onResize);c(this.upperCanvasEl,"mousedown",this._onMouseDown);c(this.upperCanvasEl, +"mousemove",this._onMouseMove);c(this.upperCanvasEl,"mouseout",this._onMouseOut);c(this.upperCanvasEl,"mouseenter",this._onMouseEnter);c(this.upperCanvasEl,"wheel",this._onMouseWheel);c(this.upperCanvasEl,"contextmenu",this._onContextMenu);c(this.upperCanvasEl,"touchstart",this._onMouseDown);c(this.upperCanvasEl,"touchmove",this._onMouseMove);"undefined"!==typeof eventjs&&"remove"in eventjs&&(eventjs.remove(this.upperCanvasEl,"gesture",this._onGesture),eventjs.remove(this.upperCanvasEl,"drag",this._onDrag), +eventjs.remove(this.upperCanvasEl,"orientation",this._onOrientationChange),eventjs.remove(this.upperCanvasEl,"shake",this._onShake),eventjs.remove(this.upperCanvasEl,"longpress",this._onLongPress))},_onGesture:function(a,b){this.__onTransformGesture&&this.__onTransformGesture(a,b)},_onDrag:function(a,b){this.__onDrag&&this.__onDrag(a,b)},_onMouseWheel:function(a){this.__onMouseWheel(a)},_onMouseOut:function(a){var b=this._hoveredTarget;this.fire("mouse:out",{target:b,e:a});this._hoveredTarget=null; +b&&b.fire("mouseout",{e:a});this._iTextInstances&&this._iTextInstances.forEach(function(a){a.isEditing&&a.hiddenTextarea.focus()})},_onMouseEnter:function(a){this.findTarget(a)||(this.fire("mouse:over",{target:null,e:a}),this._hoveredTarget=null)},_onOrientationChange:function(a,b){this.__onOrientationChange&&this.__onOrientationChange(a,b)},_onShake:function(a,b){this.__onShake&&this.__onShake(a,b)},_onLongPress:function(a,b){this.__onLongPress&&this.__onLongPress(a,b)},_onContextMenu:function(a){this.stopContextMenu&& +(a.stopPropagation(),a.preventDefault());return!1},_onMouseDown:function(a){this.__onMouseDown(a);d(fabric.document,"touchend",this._onMouseUp,{passive:!1});d(fabric.document,"touchmove",this._onMouseMove,{passive:!1});c(this.upperCanvasEl,"mousemove",this._onMouseMove);c(this.upperCanvasEl,"touchmove",this._onMouseMove);"touchstart"===a.type?c(this.upperCanvasEl,"mousedown",this._onMouseDown):(d(fabric.document,"mouseup",this._onMouseUp),d(fabric.document,"mousemove",this._onMouseMove))},_onMouseUp:function(a){this.__onMouseUp(a); +c(fabric.document,"mouseup",this._onMouseUp);c(fabric.document,"touchend",this._onMouseUp);c(fabric.document,"mousemove",this._onMouseMove);c(fabric.document,"touchmove",this._onMouseMove);d(this.upperCanvasEl,"mousemove",this._onMouseMove);d(this.upperCanvasEl,"touchmove",this._onMouseMove,{passive:!1});if("touchend"===a.type){var b=this;setTimeout(function(){d(b.upperCanvasEl,"mousedown",b._onMouseDown)},400)}},_onMouseMove:function(a){!this.allowTouchScrolling&&a.preventDefault&&a.preventDefault(); +this.__onMouseMove(a)},_onResize:function(){this.calcOffset()},_shouldRender:function(a,b){var c=this.getActiveGroup()||this.getActiveObject();return c&&c.isEditing&&a===c?!1:!!(a&&(a.isMoving||a!==c)||!a&&c||!a&&!c&&!this._groupSelector||b&&this._previousPointer&&this.selection&&(b.x!==this._previousPointer.x||b.y!==this._previousPointer.y))},__onMouseUp:function(a){var b;if(e(a,3))this.fireRightClick&&this._handleEvent(a,"up",b,3);else if(e(a,2))this.fireMiddleClick&&this._handleEvent(a,"up",b, +2);else if(this.isDrawingMode&&this._isCurrentlyDrawing)this._onMouseUpInDrawingMode(a);else{b=!0;var c=this._currentTransform,d=this._groupSelector,d=!d||0===d.left&&0===d.top;c&&(this._finalizeCurrentTransform(a),b=!c.actionPerformed);b=b?this.findTarget(a,!0):c.target;c=this._shouldRender(b,this.getPointer(a));b||!d?this._maybeGroupObjects(a):this._currentTransform=this._groupSelector=null;b&&(b.isMoving=!1);this._setCursorFromEvent(a,b);this._handleEvent(a,"up",b?b:null,1,d);b&&(b.__corner=0); +c&&this.renderAll()}},_handleEvent:function(a,b,c,d,e){var f="undefined"===typeof c?this.findTarget(a):c;c=this.targets||[];a={e:a,target:f,subTargets:c,button:d||1,isClick:e||!1};this.fire("mouse:"+b,a);f&&f.fire("mouse"+b,a);for(d=0;d<c.length;d++)c[d].fire("mouse"+b,a)},_finalizeCurrentTransform:function(a){var b=this._currentTransform,c=b.target;c._scaling&&(c._scaling=!1);c.setCoords();this._restoreOriginXY(c);if(b.actionPerformed||this.stateful&&c.hasStateChanged())this.fire("object:modified", +{target:c,e:a}),c.fire("modified",{e:a})},_restoreOriginXY:function(a){if(this._previousOriginX&&this._previousOriginY){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX;a.originY=this._previousOriginY;a.left=b.x;a.top=b.y;this._previousOriginY=this._previousOriginX=null}},_onMouseDownInDrawingMode:function(a){this._isCurrentlyDrawing=!0;this.discardActiveObject(a).renderAll();this.clipTo&&fabric.util.clipContext(this,this.contextTop); +var b=this.getPointer(a);this.freeDrawingBrush.onMouseDown(b);this._handleEvent(a,"down")},_onMouseMoveInDrawingMode:function(a){if(this._isCurrentlyDrawing){var b=this.getPointer(a);this.freeDrawingBrush.onMouseMove(b)}this.setCursor(this.freeDrawingCursor);this._handleEvent(a,"move")},_onMouseUpInDrawingMode:function(a){this._isCurrentlyDrawing=!1;this.clipTo&&this.contextTop.restore();this.freeDrawingBrush.onMouseUp();this._handleEvent(a,"up")},__onMouseDown:function(a){var b=this.findTarget(a); +if(e(a,3))this.fireRightClick&&this._handleEvent(a,"down",b?b:null,3);else if(e(a,2))this.fireMiddleClick&&this._handleEvent(a,"down",b?b:null,2);else if(this.isDrawingMode)this._onMouseDownInDrawingMode(a);else if(!this._currentTransform){var c=this.getPointer(a,!0);this._previousPointer=c;var d=this._shouldRender(b,c),l=this._shouldGroup(a,b);this._shouldClearSelection(a,b)?this.deactivateAllWithDispatch(a):l&&(this._handleGrouping(a,b),b=this.getActiveGroup());!this.selection||b&&(b.selectable|| +b.isEditing)||(this._groupSelector={ex:c.x,ey:c.y,top:0,left:0});b&&(!b.selectable||!b.__corner&&l||(this._beforeTransform(a,b),this._setupCurrentTransform(a,b)),c=this.getActiveObject(),b!==this.getActiveGroup()&&b!==c&&(this.deactivateAll(),b.selectable&&(c&&c.fire("deselected",{e:a}),this.setActiveObject(b,a))));this._handleEvent(a,"down",b?b:null);d&&this.renderAll()}},_beforeTransform:function(a,b){this.stateful&&b.saveState();if(b._findTargetCorner(this.getPointer(a)))this.onBeforeScaleRotate(b)}, +_setOriginToCenter:function(a){this._previousOriginX=this._currentTransform.target.originX;this._previousOriginY=this._currentTransform.target.originY;var b=a.getCenterPoint();a.originX="center";a.originY="center";a.left=b.x;a.top=b.y;this._currentTransform.left=a.left;this._currentTransform.top=a.top},_setCenterToOrigin:function(a){var b=a.translateToOriginPoint(a.getCenterPoint(),this._previousOriginX,this._previousOriginY);a.originX=this._previousOriginX;a.originY=this._previousOriginY;a.left= +b.x;a.top=b.y;this._previousOriginY=this._previousOriginX=null},__onMouseMove:function(a){var b,c;if(this.isDrawingMode)this._onMouseMoveInDrawingMode(a);else if(!("undefined"!==typeof a.touches&&1<a.touches.length)){var d=this._groupSelector;d?(c=this.getPointer(a,!0),d.left=c.x-d.ex,d.top=c.y-d.ey,this.renderTop()):this._currentTransform?this._transformObject(a):(b=this.findTarget(a),this._setCursorFromEvent(a,b));this._handleEvent(a,"move",b?b:null)}},__onMouseWheel:function(a){this._handleEvent(a, +"wheel")},_transformObject:function(a){var b=this.getPointer(a),c=this._currentTransform;c.reset=!1;c.target.isMoving=!0;c.shiftKey=a.shiftKey;c.altKey=a[this.centeredKey];this._beforeScaleTransform(a,c);this._performTransformAction(a,c,b);c.actionPerformed&&this.renderAll()},_performTransformAction:function(a,b,c){var d=c.x,g=c.y;c=b.target;var e=b.action;if("rotate"===e)(d=this._rotateObject(d,g))&&this._fire("rotating",c,a);else if("scale"===e)(d=this._onScale(a,b,d,g))&&this._fire("scaling",c, +a);else if("scaleX"===e)(d=this._scaleObject(d,g,"x"))&&this._fire("scaling",c,a);else if("scaleY"===e)(d=this._scaleObject(d,g,"y"))&&this._fire("scaling",c,a);else if("skewX"===e)(d=this._skewObject(d,g,"x"))&&this._fire("skewing",c,a);else if("skewY"===e)(d=this._skewObject(d,g,"y"))&&this._fire("skewing",c,a);else if(d=this._translateObject(d,g))this._fire("moving",c,a),this.setCursor(c.moveCursor||this.moveCursor);b.actionPerformed=b.actionPerformed||d},_fire:function(a,b,c){this.fire("object:"+ +a,{target:b,e:c});b.fire(a,{e:c})},_beforeScaleTransform:function(a,b){if("scale"===b.action||"scaleX"===b.action||"scaleY"===b.action){var c=this._shouldCenterTransform(b.target);if(c&&("center"!==b.originX||"center"!==b.originY)||!c&&"center"===b.originX&&"center"===b.originY)this._resetCurrentTransform(),b.reset=!0}},_onScale:function(a,b,c,d){if(!a[this.uniScaleKey]&&!this.uniScaleTransform||b.target.get("lockUniScaling"))return b.reset||"scale"!==b.currentAction||this._resetCurrentTransform(), +b.currentAction="scaleEqually",this._scaleObject(c,d,"equally");b.currentAction="scale";return this._scaleObject(c,d)},_setCursorFromEvent:function(a,b){if(!b)return this.setCursor(this.defaultCursor),!1;var c=b.hoverCursor||this.hoverCursor,d=this.getActiveGroup();(d=b._findTargetCorner&&(!d||!d.contains(b))&&b._findTargetCorner(this.getPointer(a,!0)))?this._setCornerCursor(d,b,a):this.setCursor(c);return!0},_setCornerCursor:function(a,c,d){if(a in b)this.setCursor(this._getRotatedCornerCursor(a, +c,d));else if("mtr"===a&&c.hasRotatingPoint)this.setCursor(this.rotationCursor);else return this.setCursor(this.defaultCursor),!1},_getRotatedCornerCursor:function(a,c,d){c=Math.round(c.getAngle()%360/45);0>c&&(c+=8);c+=b[a];d[this.altActionKey]&&0===b[a]%2&&(c+=2);return this.cursorMap[c%8]}})})(); +(function(){var e=Math.min,b=Math.max;fabric.util.object.extend(fabric.Canvas.prototype,{_shouldGroup:function(b,c){var a=this.getActiveObject();return b[this.selectionKey]&&c&&c.selectable&&(this.getActiveGroup()||a&&a!==c)&&this.selection},_handleGrouping:function(b,c){var a=this.getActiveGroup();if(c===a&&(c=this.findTarget(b,!0),!c))return;a?this._updateActiveGroup(c,b):this._createActiveGroup(c,b);this._activeGroup&&this._activeGroup.saveCoords()},_updateActiveGroup:function(b,c){var a=this.getActiveGroup(); +if(a.contains(b)){if(a.removeWithUpdate(b),b.set("active",!1),1===a.size()){this.discardActiveGroup(c);this.setActiveObject(a.item(0),c);return}}else a.addWithUpdate(b);this.fire("selection:created",{target:a,e:c});a.set("active",!0)},_createActiveGroup:function(b,c){if(this._activeObject&&b!==this._activeObject){var a=this._createGroup(b);a.addWithUpdate();this.setActiveGroup(a,c);this._activeObject=null;this.fire("selection:created",{target:a,e:c})}b.set("active",!0)},_createGroup:function(b){var c= +this.getObjects();b=c.indexOf(this._activeObject)<c.indexOf(b)?[this._activeObject,b]:[b,this._activeObject];this._activeObject.isEditing&&this._activeObject.exitEditing();return new fabric.Group(b,{canvas:this})},_groupSelectedObjects:function(b){var c=this._collectObjects();1===c.length?this.setActiveObject(c[0],b):1<c.length&&(c=new fabric.Group(c.reverse(),{canvas:this}),c.addWithUpdate(),this.setActiveGroup(c,b),c.saveCoords(),this.fire("selection:created",{target:c,e:b}),this.renderAll())}, +_collectObjects:function(){var d=[],c;c=this._groupSelector.ex;for(var a=this._groupSelector.ey,g=c+this._groupSelector.left,h=a+this._groupSelector.top,f=new fabric.Point(e(c,g),e(a,h)),l=new fabric.Point(b(c,g),b(a,h)),a=c===g&&a===h,g=this._objects.length;g--&&!((c=this._objects[g])&&c.selectable&&c.visible&&(c.intersectsWithRect(f,l)||c.isContainedWithinRect(f,l)||c.containsPoint(f)||c.containsPoint(l))&&(c.set("active",!0),d.push(c),a)););return d},_maybeGroupObjects:function(b){this.selection&& +this._groupSelector&&this._groupSelectedObjects(b);if(b=this.getActiveGroup())b.setObjectsCoords().setCoords(),b.isMoving=!1,this.setCursor(this.defaultCursor);this._currentTransform=this._groupSelector=null}})})(); +(function(){var e=fabric.StaticCanvas.supports("toDataURLWithQuality");fabric.util.object.extend(fabric.StaticCanvas.prototype,{toDataURL:function(b){b||(b={});return this.__toDataURLWithMultiplier(b.format||"png",b.quality||1,{left:b.left||0,top:b.top||0,width:b.width||0,height:b.height||0},b.multiplier||1)},__toDataURLWithMultiplier:function(b,d,c,a){var g=this.getWidth(),e=this.getHeight(),f=(c.width||this.getWidth())*a,l=(c.height||this.getHeight())*a,k=this.getZoom()*a,m=this.viewportTransform, +n=this.interactive;this.viewportTransform=[k,0,0,k,(m[4]-c.left)*a,(m[5]-c.top)*a];this.interactive&&(this.interactive=!1);g!==f||e!==l?this.setDimensions({width:f,height:l},{backstoreOnly:!0}):this.renderAll();b=this.__toDataURL(b,d,c);n&&(this.interactive=n);this.viewportTransform=m;this.setDimensions({width:g,height:e},{backstoreOnly:!0});return b},__toDataURL:function(b,d){var c=this.contextContainer.canvas;"jpg"===b&&(b="jpeg");return e?c.toDataURL("image/"+b,d):c.toDataURL("image/"+b)},toDataURLWithMultiplier:function(b, +d,c){return this.toDataURL({format:b,multiplier:d,quality:c})}})})(); +fabric.util.object.extend(fabric.StaticCanvas.prototype,{loadFromDatalessJSON:function(e,b,d){return this.loadFromJSON(e,b,d)},loadFromJSON:function(e,b,d){if(e){var c="string"===typeof e?JSON.parse(e):fabric.util.object.clone(e),a=this,g=this.renderOnAddRemove;this.renderOnAddRemove=!1;this._enlivenObjects(c.objects,function(d){a.clear();a._setBgOverlay(c,function(){d.forEach(function(b,c){a.insertAt(b,c)});a.renderOnAddRemove=g;delete c.objects;delete c.backgroundImage;delete c.overlayImage;delete c.background; +delete c.overlay;a._setOptions(c);a.renderAll();b&&b()})},d);return this}},_setBgOverlay:function(e,b){var d={backgroundColor:!1,overlayColor:!1,backgroundImage:!1,overlayImage:!1};if(e.backgroundImage||e.overlayImage||e.background||e.overlay){var c=function(){d.backgroundImage&&d.overlayImage&&d.backgroundColor&&d.overlayColor&&b&&b()};this.__setBgOverlay("backgroundImage",e.backgroundImage,d,c);this.__setBgOverlay("overlayImage",e.overlayImage,d,c);this.__setBgOverlay("backgroundColor",e.background, +d,c);this.__setBgOverlay("overlayColor",e.overlay,d,c)}else b&&b()},__setBgOverlay:function(e,b,d,c){var a=this;if(b)if("backgroundImage"===e||"overlayImage"===e)fabric.util.enlivenObjects([b],function(b){a[e]=b[0];d[e]=!0;c&&c()});else this["set"+fabric.util.string.capitalize(e,!0)](b,function(){d[e]=!0;c&&c()});else d[e]=!0,c&&c()},_enlivenObjects:function(e,b,d){e&&0!==e.length?fabric.util.enlivenObjects(e,function(c){b&&b(c)},null,d):b&&b([])},_toDataURL:function(e,b){this.clone(function(d){b(d.toDataURL(e))})}, +_toDataURLWithMultiplier:function(e,b,d){this.clone(function(c){d(c.toDataURLWithMultiplier(e,b))})},clone:function(e,b){var d=JSON.stringify(this.toJSON(b));this.cloneWithoutData(function(b){b.loadFromJSON(d,function(){e&&e(b)})})},cloneWithoutData:function(e){var b=fabric.document.createElement("canvas");b.width=this.getWidth();b.height=this.getHeight();var d=new fabric.Canvas(b);d.clipTo=this.clipTo;this.backgroundImage?(d.setBackgroundImage(this.backgroundImage.src,function(){d.renderAll();e&& +e(d)}),d.backgroundImageOpacity=this.backgroundImageOpacity,d.backgroundImageStretch=this.backgroundImageStretch):e&&e(d)}}); +(function(e){var b=e.fabric||(e.fabric={});e=b.util.object.extend;var d=b.util.object.clone,c=b.util.toFixed,a=b.util.string.capitalize,g=b.util.degreesToRadians,h=b.StaticCanvas.supports("setLineDash");b.Object||(b.Object=b.util.createClass(b.CommonMethods,{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,objectCaching:!b.isLikelyNode,statefullCache:!1,noScaleCache:!0,dirty:!0,stateProperties:"top left width height scaleX scaleY flipX flipY originX originY transformMatrix stroke strokeWidth strokeDashArray strokeLineCap strokeLineJoin strokeMiterLimit angle opacity fill globalCompositeOperation shadow clipTo visible backgroundColor skewX skewY fillRule".split(" "), +cacheProperties:"fill stroke strokeWidth strokeDashArray width height strokeLineCap strokeLineJoin strokeMiterLimit backgroundColor".split(" "),initialize:function(a){a=a||{};this.setOptions(a)},_createCacheCanvas:function(){this._cacheProperties={};this._cacheCanvas=b.document.createElement("canvas");this._cacheContext=this._cacheCanvas.getContext("2d");this._updateCacheCanvas()},_limitCacheSize:function(a){var c=b.perfLimitSizeTotal,d=a.width,f=a.height,g=b.maxCacheSideLimit,e=b.minCacheSideLimit; +if(d<=g&&f<=g&&d*f<=c)return d<e&&(a.width=e),f<e&&(a.height=e),a;var h=b.util.limitDimsByArea(d/f,c),t=b.util.capValue,c=t(e,h.x,g),g=t(e,h.y,g);d>c&&(a.zoomX/=d/c,a.width=c,a.capped=!0);f>g&&(a.zoomY/=f/g,a.height=g,a.capped=!0);return a},_getCacheCanvasDimensions:function(){var a=this.canvas&&this.canvas.getZoom()||1,c=this.getObjectScaling(),d=this.canvas&&this.canvas._isRetinaScaling()?b.devicePixelRatio:1,g=this._getNonTransformedDimensions(),e=c.scaleX*a*d,a=c.scaleY*a*d;return{width:g.x*e+ +2,height:g.y*a+2,zoomX:e,zoomY:a,x:g.x,y:g.y}},_updateCacheCanvas:function(){if(this.noScaleCache&&this.canvas&&this.canvas._currentTransform){var a=this.canvas._currentTransform.action;if(this===this.canvas._currentTransform.target&&a.slice&&"scale"===a.slice(0,5))return!1}var a=this._cacheCanvas,c=this._limitCacheSize(this._getCacheCanvasDimensions()),d=b.minCacheSideLimit,g=c.width,e=c.height,h=c.zoomX,q=c.zoomY,t=g!==this.cacheWidth||e!==this.cacheHeight,r=this.zoomX!==h||this.zoomY!==q,v=0,A= +0,w=!1;if(t){var w=this._cacheCanvas.width,y=this._cacheCanvas.height,x=g>w||e>y,w=x||(g<.9*w||e<.9*y)&&w>d&&y>d;x&&!c.capped&&(g>d||e>d)&&(v=.1*g,A=.1*e)}return t||r?(w?(a.width=Math.ceil(g+v),a.height=Math.ceil(e+A)):(this._cacheContext.setTransform(1,0,0,1,0,0),this._cacheContext.clearRect(0,0,a.width,a.height)),d=c.x*h/2,c=c.y*q/2,this.cacheTranslationX=Math.round(a.width/2-d)+d,this.cacheTranslationY=Math.round(a.height/2-c)+c,this.cacheWidth=g,this.cacheHeight=e,this._cacheContext.translate(this.cacheTranslationX, +this.cacheTranslationY),this._cacheContext.scale(h,q),this.zoomX=h,this.zoomY=q,!0):!1},setOptions:function(a){this._setOptions(a);this._initGradient(a.fill,"fill");this._initGradient(a.stroke,"stroke");this._initClipping(a);this._initPattern(a.fill,"fill");this._initPattern(a.stroke,"stroke")},transform:function(a,b){this.group&&!this.group._transformDone&&this.group===this.canvas._activeGroup&&this.group.transform(a);var c=b?this._getLeftTopCoords():this.getCenterPoint();a.translate(c.x,c.y);this.angle&& +a.rotate(g(this.angle));a.scale(this.scaleX*(this.flipX?-1:1),this.scaleY*(this.flipY?-1:1));this.skewX&&a.transform(1,0,Math.tan(g(this.skewX)),1,0,0);this.skewY&&a.transform(1,Math.tan(g(this.skewY)),0,1,0,0)},toObject:function(a){var d=b.Object.NUM_FRACTION_DIGITS,d={type:this.type,originX:this.originX,originY:this.originY,left:c(this.left,d),top:c(this.top,d),width:c(this.width,d),height:c(this.height,d),fill:this.fill&&this.fill.toObject?this.fill.toObject():this.fill,stroke:this.stroke&&this.stroke.toObject? +this.stroke.toObject():this.stroke,strokeWidth:c(this.strokeWidth,d),strokeDashArray:this.strokeDashArray?this.strokeDashArray.concat():this.strokeDashArray,strokeLineCap:this.strokeLineCap,strokeLineJoin:this.strokeLineJoin,strokeMiterLimit:c(this.strokeMiterLimit,d),scaleX:c(this.scaleX,d),scaleY:c(this.scaleY,d),angle:c(this.getAngle(),d),flipX:this.flipX,flipY:this.flipY,opacity:c(this.opacity,d),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():null,skewX:c(this.skewX,d),skewY:c(this.skewY,d)};b.util.populateWithProperties(this,d,a);this.includeDefaultValues||(d=this._removeDefaultValues(d));return d},toDatalessObject:function(a){return this.toObject(a)},_removeDefaultValues:function(a){var c=b.util.getKlass(a.type).prototype; +c.stateProperties.forEach(function(b){a[b]===c[b]&&delete a[b];"[object Array]"===Object.prototype.toString.call(a[b])&&"[object Array]"===Object.prototype.toString.call(c[b])&&0===a[b].length&&0===c[b].length&&delete a[b]});return a},toString:function(){return"#<fabric."+a(this.type)+">"},getObjectScaling:function(){var a=this.scaleX,b=this.scaleY;if(this.group)var c=this.group.getObjectScaling(),a=a*c.scaleX,b=b*c.scaleY;return{scaleX:a,scaleY:b}},_set:function(a,c){var d=this[a]!==c;if("scaleX"=== +a||"scaleY"===a)c=this._constrainScale(c);"scaleX"===a&&0>c?(this.flipX=!this.flipX,c*=-1):"scaleY"===a&&0>c?(this.flipY=!this.flipY,c*=-1):"shadow"!==a||!c||c instanceof b.Shadow?"dirty"===a&&this.group&&this.group.set("dirty",c):c=new b.Shadow(c);this[a]=c;d&&-1<this.cacheProperties.indexOf(a)&&(this.group&&this.group.set("dirty",!0),this.dirty=!0);d&&this.group&&-1<this.stateProperties.indexOf(a)&&this.group.set("dirty",!0);if("width"===a||"height"===a)this.minScaleLimit=Math.min(.1,1/Math.max(this.width, +this.height));return this},setOnGroup:function(){},setSourcePath:function(a){this.sourcePath=a;return this},getViewportTransform:function(){return this.canvas&&this.canvas.viewportTransform?this.canvas.viewportTransform:b.iMatrix.concat()},isNotVisible:function(){return 0===this.opacity||0===this.width&&0===this.height||!this.visible},render:function(a,c){this.isNotVisible()||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(a.save(),this._setupCompositeOperation(a),this.drawSelectionBackground(a), +c||this.transform(a),this._setOpacity(a),this._setShadow(a),this.transformMatrix&&a.transform.apply(a,this.transformMatrix),this.clipTo&&b.util.clipContext(this,a),this.shouldCache(c)?(this._cacheCanvas||this._createCacheCanvas(),this.isCacheDirty(c)&&(this.statefullCache&&this.saveState({propertySet:"cacheProperties"}),this.drawObject(this._cacheContext,c),this.dirty=!1),this.drawCacheOnCanvas(a)):(this._removeCacheCanvas(),this.dirty=!1,this.drawObject(a,c),c&&this.objectCaching&&this.statefullCache&& +this.saveState({propertySet:"cacheProperties"})),this.clipTo&&a.restore(),a.restore())},_removeCacheCanvas:function(){this._cacheCanvas=null;this.cacheHeight=this.cacheWidth=0},needsItsOwnCache:function(){return!1},shouldCache:function(a){return!a&&this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching())},willDrawShadow:function(){return!!this.shadow&&(0!==this.shadow.offsetX||0!==this.shadow.offsetY)},drawObject:function(a,b){this._renderBackground(a);this._setStrokeStyles(a); +this._setFillStyles(a);this._render(a,b)},drawCacheOnCanvas:function(a){a.scale(1/this.zoomX,1/this.zoomY);a.drawImage(this._cacheCanvas,-this.cacheTranslationX,-this.cacheTranslationY)},isCacheDirty:function(a){if(this.isNotVisible())return!1;if(this._cacheCanvas&&!a&&this._updateCacheCanvas())return!0;if(this.dirty||this.statefullCache&&this.hasStateChanged("cacheProperties")){if(this._cacheCanvas&&!a){a=this.cacheWidth/this.zoomX;var b=this.cacheHeight/this.zoomY;this._cacheContext.clearRect(-a/ +2,-b/2,a,b)}return!0}return!1},_renderBackground:function(a){if(this.backgroundColor){var b=this._getNonTransformedDimensions();a.fillStyle=this.backgroundColor;a.fillRect(-b.x/2,-b.y/2,b.x,b.y);this._removeShadow(a)}},_setOpacity:function(a){a.globalAlpha*=this.opacity},_setStrokeStyles:function(a){this.stroke&&(a.lineWidth=this.strokeWidth,a.lineCap=this.strokeLineCap,a.lineJoin=this.strokeLineJoin,a.miterLimit=this.strokeMiterLimit,a.strokeStyle=this.stroke.toLive?this.stroke.toLive(a,this):this.stroke)}, +_setFillStyles:function(a){this.fill&&(a.fillStyle=this.fill.toLive?this.fill.toLive(a,this):this.fill)},_setLineDash:function(a,b,c){b&&(1&b.length&&b.push.apply(b,b),h?a.setLineDash(b):c&&c(a))},_renderControls:function(a){if(this.active&&(!this.group||this.group===this.canvas.getActiveGroup())){var c=this.getViewportTransform(),d=this.calcTransformMatrix(),d=b.util.multiplyTransformMatrices(c,d),c=b.util.qrDecompose(d);a.save();a.translate(c.translateX,c.translateY);a.lineWidth=1*this.borderScaleFactor; +this.group||(a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1);this.group&&this.group===this.canvas.getActiveGroup()?(a.rotate(g(c.angle)),this.drawBordersInGroup(a,c)):(a.rotate(g(this.angle)),this.drawBorders(a));this.drawControls(a);a.restore()}},_setShadow:function(a){if(this.shadow){var c=this.canvas&&this.canvas.viewportTransform[0]||1,d=this.canvas&&this.canvas.viewportTransform[3]||1,f=this.getObjectScaling();this.canvas&&this.canvas._isRetinaScaling()&&(c*=b.devicePixelRatio,d*= +b.devicePixelRatio);a.shadowColor=this.shadow.color;a.shadowBlur=this.shadow.blur*(c+d)*(f.scaleX+f.scaleY)/4;a.shadowOffsetX=this.shadow.offsetX*c*f.scaleX;a.shadowOffsetY=this.shadow.offsetY*d*f.scaleY}},_removeShadow:function(a){this.shadow&&(a.shadowColor="",a.shadowBlur=a.shadowOffsetX=a.shadowOffsetY=0)},_applyPatternGradientTransform:function(a,b){if(b.toLive){var c=b.gradientTransform||b.patternTransform;c&&a.transform.apply(a,c);a.translate(-this.width/2+b.offsetX||0,-this.height/2+b.offsetY|| +0)}},_renderFill:function(a){this.fill&&(a.save(),this._applyPatternGradientTransform(a,this.fill),"evenodd"===this.fillRule?a.fill("evenodd"):a.fill(),a.restore())},_renderStroke:function(a){this.stroke&&0!==this.strokeWidth&&(this.shadow&&!this.shadow.affectStroke&&this._removeShadow(a),a.save(),this._setLineDash(a,this.strokeDashArray,this._renderDashedStroke),this._applyPatternGradientTransform(a,this.stroke),a.stroke(),a.restore())},clone:function(a,c){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(c), +a):new b.Object(this.toObject(c))},cloneAsImage:function(a,c){var d=this.toDataURL(c);b.util.loadImage(d,function(c){a&&a(new b.Image(c))});return this},toDataURL:function(a){a||(a={});var c=b.util.createCanvasElement(),d=this.getBoundingRect();c.width=d.width;c.height=d.height;b.util.wrapElement(c,"div");c=new b.StaticCanvas(c,{enableRetinaScaling:a.enableRetinaScaling});"jpg"===a.format&&(a.format="jpeg");"jpeg"===a.format&&(c.backgroundColor="#fff");d={active:this.get("active"),left:this.getLeft(), +top:this.getTop()};this.set("active",!1);this.setPositionByOrigin(new b.Point(c.getWidth()/2,c.getHeight()/2),"center","center");var f=this.canvas;c.add(this);a=c.toDataURL(a);this.set(d).setCoords();this.canvas=f;c.dispose();return a},isType:function(a){return this.type===a},complexity:function(){return 1},toJSON:function(a){return this.toObject(a)},setGradient:function(a,c){c||(c={});var d={colorStops:[]};d.type=c.type||(c.r1||c.r2?"radial":"linear");d.coords={x1:c.x1,y1:c.y1,x2:c.x2,y2:c.y2};if(c.r1|| +c.r2)d.coords.r1=c.r1,d.coords.r2=c.r2;d.gradientTransform=c.gradientTransform;b.Gradient.prototype.addColorStop.call(d,c.colorStops);return this.set(a,b.Gradient.forObject(this,d))},setPatternFill:function(a){return this.set("fill",new b.Pattern(a))},setShadow:function(a){return this.set("shadow",a?new b.Shadow(a):null)},setColor:function(a){this.set("fill",a);return this},setAngle:function(a){var b=("center"!==this.originX||"center"!==this.originY)&&this.centeredRotation;b&&this._setOriginToCenter(); +this.set("angle",a);b&&this._resetOrigin();return this},centerH:function(){this.canvas&&this.canvas.centerObjectH(this);return this},viewportCenterH:function(){this.canvas&&this.canvas.viewportCenterObjectH(this);return this},centerV:function(){this.canvas&&this.canvas.centerObjectV(this);return this},viewportCenterV:function(){this.canvas&&this.canvas.viewportCenterObjectV(this);return this},center:function(){this.canvas&&this.canvas.centerObject(this);return this},viewportCenter:function(){this.canvas&& +this.canvas.viewportCenterObject(this);return this},remove:function(){this.canvas&&(this.group&&this.group===this.canvas._activeGroup&&this.group.remove(this),this.canvas.remove(this));return this},getLocalPointer:function(a,c){c=c||this.canvas.getPointer(a);var d=new b.Point(c.x,c.y),f=this._getLeftTopCoords();this.angle&&(d=b.util.rotatePoint(d,f,g(-this.angle)));return{x:d.x-f.x,y:d.y-f.y}},_setupCompositeOperation:function(a){this.globalCompositeOperation&&(a.globalCompositeOperation=this.globalCompositeOperation)}}), +b.util.createAccessors(b.Object),b.Object.prototype.rotate=b.Object.prototype.setAngle,e(b.Object.prototype,b.Observable),b.Object.NUM_FRACTION_DIGITS=2,b.Object._fromObject=function(a,c,g,e,h){var f=b[a];c=d(c,!0);if(e)b.util.enlivenPatterns([c.fill,c.stroke],function(a){"undefined"!==typeof a[0]&&(c.fill=a[0]);"undefined"!==typeof a[1]&&(c.stroke=a[1]);a=h?new f(c[h],c):new f(c);g&&g(a)});else return a=h?new f(c[h],c):new f(c),g&&g(a),a},b.Object.__uid=0)})("undefined"!==typeof exports?exports: +this); +(function(){var e=fabric.util.degreesToRadians,b={left:-.5,center:0,right:.5},d={top:-.5,center:0,bottom:.5};fabric.util.object.extend(fabric.Object.prototype,{translateToGivenOrigin:function(c,a,g,e,f){var h=c.x,k=c.y;a="string"===typeof a?b[a]:a-.5;e="string"===typeof e?b[e]:e-.5;a=e-a;g="string"===typeof g?d[g]:g-.5;f="string"===typeof f?d[f]:f-.5;g=f-g;if(a||g)k=this._getTransformedDimensions(),h=c.x+a*k.x,k=c.y+g*k.y;return new fabric.Point(h,k)},translateToCenterPoint:function(b,a,d){a=this.translateToGivenOrigin(b, +a,d,"center","center");return this.angle?fabric.util.rotatePoint(a,b,e(this.angle)):a},translateToOriginPoint:function(b,a,d){a=this.translateToGivenOrigin(b,"center","center",a,d);return this.angle?fabric.util.rotatePoint(a,b,e(this.angle)):a},getCenterPoint:function(){var b=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(b,this.originX,this.originY)},getPointByOrigin:function(b,a){var c=this.getCenterPoint();return this.translateToOriginPoint(c,b,a)},toLocalPoint:function(b, +a,d){var c=this.getCenterPoint();a="undefined"!==typeof a&&"undefined"!==typeof d?this.translateToGivenOrigin(c,"center","center",a,d):new fabric.Point(this.left,this.top);b=new fabric.Point(b.x,b.y);this.angle&&(b=fabric.util.rotatePoint(b,c,-e(this.angle)));return b.subtractEquals(a)},setPositionByOrigin:function(b,a,d){b=this.translateToCenterPoint(b,a,d);b=this.translateToOriginPoint(b,this.originX,this.originY);this.set("left",b.x);this.set("top",b.y)},adjustPosition:function(c){var a=e(this.angle), +d=this.getWidth(),h=Math.cos(a)*d,a=Math.sin(a)*d,f,d="string"===typeof this.originX?b[this.originX]:this.originX-.5;f="string"===typeof c?b[c]:c-.5;this.left+=h*(f-d);this.top+=a*(f-d);this.setCoords();this.originX=c},_setOriginToCenter:function(){this._originalOriginX=this.originX;this._originalOriginY=this.originY;var b=this.getCenterPoint();this.originY=this.originX="center";this.left=b.x;this.top=b.y},_resetOrigin:function(){var b=this.translateToOriginPoint(this.getCenterPoint(),this._originalOriginX, +this._originalOriginY);this.originX=this._originalOriginX;this.originY=this._originalOriginY;this.left=b.x;this.top=b.y;this._originalOriginY=this._originalOriginX=null},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),"left","top")},onDeselect:function(){}})})(); +(function(){var e=fabric.util.degreesToRadians,b=fabric.util.multiplyTransformMatrices;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,aCoords:null,getCoords:function(b,c){this.oCoords||this.setCoords();var a=b?this.aCoords:this.oCoords,a=c?this.calcCoords(b):a;return[new fabric.Point(a.tl.x,a.tl.y),new fabric.Point(a.tr.x,a.tr.y),new fabric.Point(a.br.x,a.br.y),new fabric.Point(a.bl.x,a.bl.y)]},intersectsWithRect:function(b,c,a,e){a=this.getCoords(a,e);return"Intersection"===fabric.Intersection.intersectPolygonRectangle(a, +b,c).status},intersectsWithObject:function(b,c,a){return"Intersection"===fabric.Intersection.intersectPolygonPolygon(this.getCoords(c,a),b.getCoords(c,a)).status||b.isContainedWithinObject(this,c,a)||this.isContainedWithinObject(b,c,a)},isContainedWithinObject:function(b,c,a){var d=this.getCoords(c,a),e=0;for(c=b._getImageLines(a?b.calcCoords(c):c?b.aCoords:b.oCoords);4>e;e++)if(!b.containsPoint(d[e],c))return!1;return!0},isContainedWithinRect:function(b,c,a,e){a=this.getBoundingRect(a,e);return a.left>= +b.x&&a.left+a.width<=c.x&&a.top>=b.y&&a.top+a.height<=c.y},containsPoint:function(b,c,a,e){c=c||this._getImageLines(e?this.calcCoords(a):a?this.aCoords:this.oCoords);b=this._findCrossPoints(b,c);return 0!==b&&1===b%2},isOnScreen:function(b){if(!this.canvas)return!1;var c=this.canvas.vptCoords.tl,a=this.canvas.vptCoords.br;b=this.getCoords(!0,b);for(var d,e=0;4>e;e++)if(d=b[e],d.x<=a.x&&d.x>=c.x&&d.y<=a.y&&d.y>=c.y)return!0;return this.intersectsWithRect(c,a,!0)||this.containsPoint({x:(c.x+a.x)/2, +y:(c.y+a.y)/2},null,!0)?!0:!1},_getImageLines:function(b){return{topline:{o:b.tl,d:b.tr},rightline:{o:b.tr,d:b.br},bottomline:{o:b.br,d:b.bl},leftline:{o:b.bl,d:b.tl}}},_findCrossPoints:function(b,c){var a,d,e,f=0,l;for(l in c)if(e=c[l],!(e.o.y<b.y&&e.d.y<b.y||e.o.y>=b.y&&e.d.y>=b.y)&&(e.o.x===e.d.x&&e.o.x>=b.x?a=e.o.x:(a=(e.d.y-e.o.y)/(e.d.x-e.o.x),d=b.y-0*b.x,e=e.o.y-a*e.o.x,a=-(d-e)/(0-a)),a>=b.x&&(f+=1),2===f))break;return f},getBoundingRectWidth:function(){return this.getBoundingRect().width}, +getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(b,c){var a=this.getCoords(b,c);return fabric.util.makeBoundingBoxFromPoints(a)},getWidth:function(){return this._getTransformedDimensions().x},getHeight:function(){return this._getTransformedDimensions().y},_constrainScale:function(b){return Math.abs(b)<this.minScaleLimit?0>b?-this.minScaleLimit:this.minScaleLimit:b!==b?this.minScaleLimit:0===b?1E-4:b},scale:function(b){b=this._constrainScale(b);0>b&&(this.flipX= +!this.flipX,this.flipY=!this.flipY,b*=-1);this.scaleY=this.scaleX=b;return this.setCoords()},scaleToWidth:function(b){var c=this.getBoundingRect().width/this.getWidth();return this.scale(b/this.width/c)},scaleToHeight:function(b){var c=this.getBoundingRect().height/this.getHeight();return this.scale(b/this.height/c)},calcCoords:function(b){var c=e(this.angle),a=this.getViewportTransform(),d=b?this._getTransformedDimensions():this._calculateCurrentDimensions(),h=d.x,f=d.y,d=Math.sin(c),l=Math.cos(c), +k=0<h?Math.atan(f/h):0,m=h/Math.cos(k)/2,n=Math.cos(k+c)*m,c=Math.sin(k+c)*m,k=this.getCenterPoint(),k=b?k:fabric.util.transformPoint(k,a),a=new fabric.Point(k.x-n,k.y-c),h=new fabric.Point(a.x+h*l,a.y+h*d),f=new fabric.Point(a.x-f*d,a.y+f*l),n=new fabric.Point(k.x+n,k.y+c);if(!b)var p=new fabric.Point((a.x+f.x)/2,(a.y+f.y)/2),q=new fabric.Point((h.x+a.x)/2,(h.y+a.y)/2),t=new fabric.Point((n.x+h.x)/2,(n.y+h.y)/2),r=new fabric.Point((n.x+f.x)/2,(n.y+f.y)/2),v=new fabric.Point(q.x+d*this.rotatingPointOffset, +q.y-l*this.rotatingPointOffset);k={tl:a,tr:h,br:n,bl:f};b||(k.ml=p,k.mt=q,k.mr=t,k.mb=r,k.mtr=v);return k},setCoords:function(b,c){this.oCoords=this.calcCoords(b);c||(this.aCoords=this.calcCoords(!0));b||this._setCornerCoords&&this._setCornerCoords();return this},_calcRotateMatrix:function(){if(this.angle){var b=e(this.angle),c=Math.cos(b),b=Math.sin(b);if(6.123233995736766E-17===c||-1.8369701987210297E-16===c)c=0;return[c,b,-b,c,0,0]}return fabric.iMatrix.concat()},calcTransformMatrix:function(d){var c= +this.getCenterPoint(),a=[1,0,0,1,c.x,c.y],c=this._calcDimensionsTransformMatrix(this.skewX,this.skewY,!0),a=this.group&&!d?b(this.group.calcTransformMatrix(),a):a;this.angle&&(d=this._calcRotateMatrix(),a=b(a,d));return a=b(a,c)},_calcDimensionsTransformMatrix:function(d,c,a){a=[this.scaleX*(a&&this.flipX?-1:1),0,0,this.scaleY*(a&&this.flipY?-1:1),0,0];d&&(d=[1,0,Math.tan(e(d)),1],a=b(a,d,!0));c&&(d=[1,Math.tan(e(c)),0,1],a=b(a,d,!0));return a},_getNonTransformedDimensions:function(){var b=this.strokeWidth; +return{x:this.width+b,y:this.height+b}},_getTransformedDimensions:function(b,c){"undefined"===typeof b&&(b=this.skewX);"undefined"===typeof c&&(c=this.skewY);for(var a=this._getNonTransformedDimensions(),d=a.x/2,a=a.y/2,d=[{x:-d,y:-a},{x:d,y:-a},{x:-d,y:a},{x:d,y:a}],e=this._calcDimensionsTransformMatrix(b,c,!1),a=0;a<d.length;a++)d[a]=fabric.util.transformPoint(d[a],e);d=fabric.util.makeBoundingBoxFromPoints(d);return{x:d.width,y:d.height}},_calculateCurrentDimensions:function(){var b=this.getViewportTransform(), +c=this._getTransformedDimensions();return fabric.util.transformPoint(c,b,!0).scalarAdd(2*this.padding)}})})(); +fabric.util.object.extend(fabric.Object.prototype,{sendToBack:function(){this.group?fabric.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this);return this},bringToFront:function(){this.group?fabric.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this);return this},sendBackwards:function(e){this.group?fabric.StaticCanvas.prototype.sendBackwards.call(this.group,this,e):this.canvas.sendBackwards(this,e);return this},bringForward:function(e){this.group? +fabric.StaticCanvas.prototype.bringForward.call(this.group,this,e):this.canvas.bringForward(this,e);return this},moveTo:function(e){this.group?fabric.StaticCanvas.prototype.moveTo.call(this.group,this,e):this.canvas.moveTo(this,e);return this}}); +(function(){function e(b,d){if(d){if(d.toLive)return b+": url(#SVGID_"+d.id+"); ";var c=new fabric.Color(d),a=b+": "+c.toRgb()+"; ",c=c.getAlpha();1!==c&&(a+=b+"-opacity: "+c.toString()+"; ");return a}return b+": none; "}fabric.util.object.extend(fabric.Object.prototype,{getSvgStyles:function(b){var d=this.fillRule,c=this.strokeWidth?this.strokeWidth:"0",a=this.strokeDashArray?this.strokeDashArray.join(" "):"none",g=this.strokeLineCap?this.strokeLineCap:"butt",h=this.strokeLineJoin?this.strokeLineJoin: +"miter",f=this.strokeMiterLimit?this.strokeMiterLimit:"4",l="undefined"!==typeof this.opacity?this.opacity:"1",k=this.visible?"":" visibility: hidden;";b=b?"":this.getSvgFilter();var m=e("fill",this.fill);return[e("stroke",this.stroke),"stroke-width: ",c,"; stroke-dasharray: ",a,"; stroke-linecap: ",g,"; stroke-linejoin: ",h,"; stroke-miterlimit: ",f,"; ",m,"fill-rule: ",d,"; opacity: ",l,";",b,k].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 b=fabric.util.toFixed,d=this.getAngle(),c=this.getSkewX()%360,a=this.getSkewY()%360,e=this.getCenterPoint(),h=fabric.Object.NUM_FRACTION_DIGITS,e="path-group"===this.type?"":"translate("+b(e.x,h)+" "+b(e.y,h)+")",d=0!==d?" rotate("+b(d,h)+")":"",f=1===this.scaleX&&1===this.scaleY?"":" scale("+b(this.scaleX,h)+" "+b(this.scaleY,h)+")",c=0!==c?" skewX("+b(c,h)+")":"",b=0!==a?" skewY("+b(a,h)+ +")":"",a="path-group"===this.type?this.width:0,h="path-group"===this.type?this.height:0;return[e,d,f,this.flipX?" matrix(-1 0 0 1 "+a+" 0) ":"",this.flipY?" matrix(1 0 0 -1 0 "+h+")":"",c,b].join("")},getSvgTransformMatrix:function(){return this.transformMatrix?" matrix("+this.transformMatrix.join(" ")+") ":""},_createBaseSVGMarkup:function(){var b=[];this.fill&&this.fill.toLive&&b.push(this.fill.toSVG(this,!1));this.stroke&&this.stroke.toLive&&b.push(this.stroke.toSVG(this,!1));this.shadow&&b.push(this.shadow.toSVG(this)); +return b}})})(); +(function(){function e(b,a,e){var c={};e.forEach(function(a){c[a]=b[a]});d(b[a],c,!0)}function b(c,a,d){if(c===a)return!0;if(Array.isArray(c)){if(c.length!==a.length)return!1;d=0;for(var e=c.length;d<e;d++)if(!b(c[d],a[d]))return!1;return!0}if(c&&"object"===typeof c){var f=Object.keys(c),g;if(!d&&f.length!==Object.keys(a).length)return!1;d=0;for(e=f.length;d<e;d++)if(g=f[d],!b(c[g],a[g]))return!1;return!0}}var d=fabric.util.object.extend;fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(c){c= +c||"stateProperties";var a="_"+c;return Object.keys(this[a]).length<this[c].length?!0:!b(this[a],this,!0)},saveState:function(b){var a=b&&b.propertySet||"stateProperties",c="_"+a;if(!this[c])return this.setupState(b);e(this,c,this[a]);b&&b.stateProperties&&e(this,c,b.stateProperties);return this},setupState:function(b){b=b||{};var a=b.propertySet||"stateProperties";b.propertySet=a;this["_"+a]={};this.saveState(b);return this}})})(); +(function(){var e=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(b){if(!this.hasControls||!this.active)return!1;var d=b.x;b=b.y;var c;this.__corner=0;for(var a in this.oCoords)if(this.isControlVisible(a)&&("mtr"!==a||this.hasRotatingPoint)&&(!this.get("lockUniScaling")||"mt"!==a&&"mr"!==a&&"mb"!==a&&"ml"!==a)&&(c=this._getImageLines(this.oCoords[a].corner),c=this._findCrossPoints({x:d,y:b},c),0!==c&&1===c%2))return this.__corner= +a;return!1},_setCornerCoords:function(){var b=this.oCoords,d=e(45-this.angle),c=.707106*this.cornerSize,a=c*Math.cos(d),d=c*Math.sin(d),g,h;for(h in b)c=b[h].x,g=b[h].y,b[h].corner={tl:{x:c-d,y:g-a},tr:{x:c+a,y:g-d},bl:{x:c-a,y:g+d},br:{x:c+d,y:g+a}}},drawSelectionBackground:function(b){if(!this.selectionBackgroundColor||this.group||!this.active||this.canvas&&!this.canvas.interactive)return this;b.save();var d=this.getCenterPoint(),c=this._calculateCurrentDimensions(),a=this.canvas.viewportTransform; +b.translate(d.x,d.y);b.scale(1/a[0],1/a[3]);b.rotate(e(this.angle));b.fillStyle=this.selectionBackgroundColor;b.fillRect(-c.x/2,-c.y/2,c.x,c.y);b.restore();return this},drawBorders:function(b){if(!this.hasBorders)return this;var d=this._calculateCurrentDimensions(),c=1/this.borderScaleFactor,a=d.x+c,d=d.y+c;b.save();b.strokeStyle=this.borderColor;this._setLineDash(b,this.borderDashArray,null);b.strokeRect(-a/2,-d/2,a,d);this.hasRotatingPoint&&this.isControlVisible("mtr")&&!this.get("lockRotation")&& +this.hasControls&&(a=-d/2,b.beginPath(),b.moveTo(0,a),b.lineTo(0,a-this.rotatingPointOffset),b.closePath(),b.stroke());b.restore();return this},drawBordersInGroup:function(b,d){if(!this.hasBorders)return this;var c=this._getNonTransformedDimensions(),a=fabric.util.customTransformMatrix(d.scaleX,d.scaleY,d.skewX),a=fabric.util.transformPoint(c,a),e=1/this.borderScaleFactor,c=a.x+e,a=a.y+e;b.save();this._setLineDash(b,this.borderDashArray,null);b.strokeStyle=this.borderColor;b.strokeRect(-c/2,-a/2, +c,a);b.restore();return this},drawControls:function(b){if(!this.hasControls)return this;var d=this._calculateCurrentDimensions(),c=d.x,d=d.y,a=this.cornerSize,e=-(c+a)/2,a=-(d+a)/2,h=this.transparentCorners?"stroke":"fill";b.save();b.strokeStyle=b.fillStyle=this.cornerColor;this.transparentCorners||(b.strokeStyle=this.cornerStrokeColor);this._setLineDash(b,this.cornerDashArray,null);this._drawControl("tl",b,h,e,a);this._drawControl("tr",b,h,e+c,a);this._drawControl("bl",b,h,e,a+d);this._drawControl("br", +b,h,e+c,a+d);this.get("lockUniScaling")||(this._drawControl("mt",b,h,e+c/2,a),this._drawControl("mb",b,h,e+c/2,a+d),this._drawControl("mr",b,h,e+c,a+d/2),this._drawControl("ml",b,h,e,a+d/2));this.hasRotatingPoint&&this._drawControl("mtr",b,h,e+c/2,a-this.rotatingPointOffset);b.restore();return this},_drawControl:function(b,d,c,a,e){if(this.isControlVisible(b)){b=this.cornerSize;var g=!this.transparentCorners&&this.cornerStrokeColor;switch(this.cornerStyle){case "circle":d.beginPath();d.arc(a+b/2, +e+b/2,b/2,0,2*Math.PI,!1);d[c]();g&&d.stroke();break;default:"undefined"!==typeof G_vmlCanvasManager||this.transparentCorners||d.clearRect(a,e,b,b),d[c+"Rect"](a,e,b,b),g&&d.strokeRect(a,e,b,b)}}},isControlVisible:function(b){return this._getControlsVisibility()[b]},setControlVisible:function(b,d){this._getControlsVisibility()[b]=d;return this},setControlsVisibility:function(b){b||(b={});for(var d in b)this.setControlVisible(d,b[d]);return this},_getControlsVisibility:function(){this._controlsVisibility|| +(this._controlsVisibility={tl:!0,tr:!0,br:!0,bl:!0,ml:!0,mt:!0,mr:!0,mb:!0,mtr:!0});return this._controlsVisibility}})})(); +fabric.util.object.extend(fabric.StaticCanvas.prototype,{FX_DURATION:500,fxCenterObjectH:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("left"),endValue:this.getCenter().left,duration:this.FX_DURATION,onChange:function(b){e.set("left",b);g.renderAll();a()},onComplete:function(){e.setCoords();c()}});return this},fxCenterObjectV:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("top"), +endValue:this.getCenter().top,duration:this.FX_DURATION,onChange:function(b){e.set("top",b);g.renderAll();a()},onComplete:function(){e.setCoords();c()}});return this},fxRemove:function(e,b){b=b||{};var d=function(){},c=b.onComplete||d,a=b.onChange||d,g=this;fabric.util.animate({startValue:e.get("opacity"),endValue:0,duration:this.FX_DURATION,onStart:function(){e.set("active",!1)},onChange:function(b){e.set("opacity",b);g.renderAll();a()},onComplete:function(){g.remove(e);c()}});return this}}); +fabric.util.object.extend(fabric.Object.prototype,{animate:function(){if(arguments[0]&&"object"===typeof arguments[0]){var e=[],b,d;for(b in arguments[0])e.push(b);for(var c=0,a=e.length;c<a;c++)b=e[c],d=c!==a-1,this._animate(b,arguments[0][b],arguments[1],d)}else this._animate.apply(this,arguments);return this},_animate:function(e,b,d,c){var a=this,g;b=b.toString();d=d?fabric.util.object.clone(d):{};~e.indexOf(".")&&(g=e.split("."));var h=g?this.get(g[0])[g[1]]:this.get(e);"from"in d||(d.from=h); +b=~b.indexOf("=")?h+parseFloat(b.replace("=","")):parseFloat(b);fabric.util.animate({startValue:d.from,endValue:b,byValue:d.by,easing:d.easing,duration:d.duration,abort:d.abort&&function(){return d.abort.call(a)},onChange:function(b,h,k){g?a[g[0]][g[1]]=b:a.set(e,b);c||d.onChange&&d.onChange(b,h,k)},onComplete:function(b,e,g){c||(a.setCoords(),d.onComplete&&d.onComplete(b,e,g))}})}}); +(function(e){function b(a,b){var c=a.origin,d=a.axis1,f=a.axis2,e=a.dimension,g=b.nearest,h=b.center,l=b.farthest;return function(){switch(this.get(c)){case g:return Math.min(this.get(d),this.get(f));case h:return Math.min(this.get(d),this.get(f))+.5*this.get(e);case l:return Math.max(this.get(d),this.get(f))}}}var d=e.fabric||(e.fabric={}),c=d.util.object.extend,a=d.util.object.clone,g={x1:1,x2:1,y1:1,y2:1},h=d.StaticCanvas.supports("setLineDash");d.Line?d.warn("fabric.Line is already defined"): +(d.Line=d.util.createClass(d.Object,{type:"line",x1:0,y1:0,x2:0,y2:0,cacheProperties:d.Object.prototype.cacheProperties.concat("x1","x2","y1","y2"),initialize:function(a,b){a||(a=[0,0,0,0]);this.callSuper("initialize",b);this.set("x1",a[0]);this.set("y1",a[1]);this.set("x2",a[2]);this.set("y2",a[3]);this._setWidthHeight(b)},_setWidthHeight:function(a){a||(a={});this.width=Math.abs(this.x2-this.x1);this.height=Math.abs(this.y2-this.y1);this.left="left"in a?a.left:this._getLeftToOriginX();this.top= +"top"in a?a.top:this._getTopToOriginY()},_set:function(a,b){this.callSuper("_set",a,b);"undefined"!==typeof g[a]&&this._setWidthHeight();return this},_getLeftToOriginX:b({origin:"originX",axis1:"x1",axis2:"x2",dimension:"width"},{nearest:"left",center:"center",farthest:"right"}),_getTopToOriginY:b({origin:"originY",axis1:"y1",axis2:"y2",dimension:"height"},{nearest:"top",center:"center",farthest:"bottom"}),_render:function(a,b){a.beginPath();if(b){var c=this.getCenterPoint(),d=this.strokeWidth/2; +a.translate(c.x-("butt"===this.strokeLineCap&&0===this.height?0:d),c.y-("butt"===this.strokeLineCap&&0===this.width?0:d))}if(!this.strokeDashArray||this.strokeDashArray&&h)c=this.calcLinePoints(),a.moveTo(c.x1,c.y1),a.lineTo(c.x2,c.y2);a.lineWidth=this.strokeWidth;c=a.strokeStyle;a.strokeStyle=this.stroke||a.fillStyle;this.stroke&&this._renderStroke(a);a.strokeStyle=c},_renderDashedStroke:function(a){var b=this.calcLinePoints();a.beginPath();d.util.drawDashedLine(a,b.x1,b.y1,b.x2,b.y2,this.strokeDashArray); +a.closePath()},toObject:function(a){return c(this.callSuper("toObject",a),this.calcLinePoints())},_getNonTransformedDimensions:function(){var a=this.callSuper("_getNonTransformedDimensions");"butt"===this.strokeLineCap&&(0===this.width&&(a.y-=this.strokeWidth),0===this.height&&(a.x-=this.strokeWidth));return a},calcLinePoints:function(){var a=this.x1<=this.x2?-1:1,b=this.y1<=this.y2?-1:1;return{x1:a*this.width*.5,x2:a*this.width*-.5,y1:b*this.height*.5,y2:b*this.height*-.5}},toSVG:function(a){var b= +this._createBaseSVGMarkup(),c={x1:this.x1,x2:this.x2,y1:this.y1,y2:this.y2};this.group&&"path-group"===this.group.type||(c=this.calcLinePoints());b.push("<line ",this.getSvgId(),'x1="',c.x1,'" y1="',c.y1,'" x2="',c.x2,'" y2="',c.y2,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")}}),d.Line.ATTRIBUTE_NAMES=d.SHARED_ATTRIBUTES.concat(["x1","y1","x2","y2"]),d.Line.fromElement=function(a,b){b=b||{};var f=d.parseAttributes(a, +d.Line.ATTRIBUTE_NAMES),e=[f.x1||0,f.y1||0,f.x2||0,f.y2||0];b.originX="left";b.originY="top";return new d.Line(e,c(f,b))},d.Line.fromObject=function(b,c,e){var f=a(b,!0);f.points=[b.x1,b.y1,b.x2,b.y2];(b=d.Object._fromObject("Line",f,function(a){delete a.points;c&&c(a)},e,"points"))&&delete b.points;return b})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=Math.PI,c=b.util.object.extend;b.Circle?b.warn("fabric.Circle is already defined."):(b.Circle=b.util.createClass(b.Object,{type:"circle",radius:0,startAngle:0,endAngle:2*d,cacheProperties:b.Object.prototype.cacheProperties.concat("radius"),initialize:function(a){this.callSuper("initialize",a);this.set("radius",a&&a.radius||0)},_set:function(a,b){this.callSuper("_set",a,b);"radius"===a&&this.setRadius(b);return this},toObject:function(a){return this.callSuper("toObject", +["radius","startAngle","endAngle"].concat(a))},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=0,f=0,e=(this.endAngle-this.startAngle)%(2*d);0===e?(this.group&&"path-group"===this.group.type&&(c=this.left+this.radius,f=this.top+this.radius),b.push("<circle ",this.getSvgId(),'cx="'+c+'" cy="'+f+'" ','r="',this.radius,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n')):b.push('<path d="M '+Math.cos(this.startAngle)*this.radius+" "+ +Math.sin(this.startAngle)*this.radius," A "+this.radius+" "+this.radius," 0 ",+(e>d?1:0)+" 1"," "+Math.cos(this.endAngle)*this.radius+" "+Math.sin(this.endAngle)*this.radius,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")},_render:function(a,b){a.beginPath();a.arc(b?this.left+this.radius:0,b?this.top+this.radius:0,this.radius,this.startAngle,this.endAngle,!1);this._renderFill(a);this._renderStroke(a)}, +getRadiusX:function(){return this.get("radius")*this.get("scaleX")},getRadiusY:function(){return this.get("radius")*this.get("scaleY")},setRadius:function(a){this.radius=a;return this.set("width",2*a).set("height",2*a)}}),b.Circle.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["cx","cy","r"]),b.Circle.fromElement=function(a,d){d||(d={});var e=b.parseAttributes(a,b.Circle.ATTRIBUTE_NAMES);if(!("radius"in e&&0<=e.radius))throw Error("value of `r` attribute is required and can not be negative");e.left= +e.left||0;e.top=e.top||0;e=new b.Circle(c(e,d));e.left-=e.radius;e.top-=e.radius;return e},b.Circle.fromObject=function(a,c,d){return b.Object._fromObject("Circle",a,c,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});b.Triangle?b.warn("fabric.Triangle is already defined"):(b.Triangle=b.util.createClass(b.Object,{type:"triangle",initialize:function(b){this.callSuper("initialize",b);this.set("width",b&&b.width||100).set("height",b&&b.height||100)},_render:function(b){var c=this.width/2,a=this.height/2;b.beginPath();b.moveTo(-c,a);b.lineTo(0,-a);b.lineTo(c,a);b.closePath();this._renderFill(b);this._renderStroke(b)},_renderDashedStroke:function(d){var c=this.width/2,a=this.height/ +2;d.beginPath();b.util.drawDashedLine(d,-c,a,0,-a,this.strokeDashArray);b.util.drawDashedLine(d,0,-a,c,a,this.strokeDashArray);b.util.drawDashedLine(d,c,a,-c,a,this.strokeDashArray);d.closePath()},toSVG:function(b){var c=this._createBaseSVGMarkup(),a=this.width/2,d=this.height/2,a=[-a+" "+d,"0 "+-d,a+" "+d].join();c.push("<polygon ",this.getSvgId(),'points="',a,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),'"/>');return b?b(c.join("")):c.join("")}}),b.Triangle.fromObject= +function(d,c,a){return b.Object._fromObject("Triangle",d,c,a)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=2*Math.PI,c=b.util.object.extend;b.Ellipse?b.warn("fabric.Ellipse is already defined."):(b.Ellipse=b.util.createClass(b.Object,{type:"ellipse",rx:0,ry:0,cacheProperties:b.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(a){this.callSuper("initialize",a);this.set("rx",a&&a.rx||0);this.set("ry",a&&a.ry||0)},_set:function(a,b){this.callSuper("_set",a,b);switch(a){case "rx":this.rx=b;this.set("width",2*b);break;case "ry":this.ry=b,this.set("height", +2*b)}return this},getRx:function(){return this.get("rx")*this.get("scaleX")},getRy:function(){return this.get("ry")*this.get("scaleY")},toObject:function(a){return this.callSuper("toObject",["rx","ry"].concat(a))},toSVG:function(a){var b=this._createBaseSVGMarkup(),c=0,d=0;this.group&&"path-group"===this.group.type&&(c=this.left+this.rx,d=this.top+this.ry);b.push("<ellipse ",this.getSvgId(),'cx="',c,'" cy="',d,'" ','rx="',this.rx,'" ry="',this.ry,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(), +this.getSvgTransformMatrix(),'"/>\n');return a?a(b.join("")):b.join("")},_render:function(a,b){a.beginPath();a.save();a.transform(1,0,0,this.ry/this.rx,0,0);a.arc(b?this.left+this.rx:0,b?(this.top+this.ry)*this.rx/this.ry:0,this.rx,0,d,!1);a.restore();this._renderFill(a);this._renderStroke(a)}}),b.Ellipse.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["cx","cy","rx","ry"]),b.Ellipse.fromElement=function(a,d){d||(d={});var e=b.parseAttributes(a,b.Ellipse.ATTRIBUTE_NAMES);e.left=e.left||0;e.top=e.top|| +0;e=new b.Ellipse(c(e,d));e.top-=e.ry;e.left-=e.rx;return e},b.Ellipse.fromObject=function(a,c,d){return b.Object._fromObject("Ellipse",a,c,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.Rect?b.warn("fabric.Rect is already defined"):(b.Rect=b.util.createClass(b.Object,{stateProperties:b.Object.prototype.stateProperties.concat("rx","ry"),type:"rect",rx:0,ry:0,cacheProperties:b.Object.prototype.cacheProperties.concat("rx","ry"),initialize:function(b){this.callSuper("initialize",b);this._initRxRy()},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(b,a){if(1=== +this.width&&1===this.height)b.fillRect(-.5,-.5,1,1);else{var c=this.rx?Math.min(this.rx,this.width/2):0,d=this.ry?Math.min(this.ry,this.height/2):0,f=this.width,e=this.height,k=a?this.left:-this.width/2,m=a?this.top:-this.height/2,n=0!==c||0!==d;b.beginPath();b.moveTo(k+c,m);b.lineTo(k+f-c,m);n&&b.bezierCurveTo(k+f-.4477152502*c,m,k+f,m+.4477152502*d,k+f,m+d);b.lineTo(k+f,m+e-d);n&&b.bezierCurveTo(k+f,m+e-.4477152502*d,k+f-.4477152502*c,m+e,k+f-c,m+e);b.lineTo(k+c,m+e);n&&b.bezierCurveTo(k+.4477152502* +c,m+e,k,m+e-.4477152502*d,k,m+e-d);b.lineTo(k,m+d);n&&b.bezierCurveTo(k,m+.4477152502*d,k+.4477152502*c,m,k+c,m);b.closePath();this._renderFill(b);this._renderStroke(b)}},_renderDashedStroke:function(c){var a=-this.width/2,d=-this.height/2,e=this.width,f=this.height;c.beginPath();b.util.drawDashedLine(c,a,d,a+e,d,this.strokeDashArray);b.util.drawDashedLine(c,a+e,d,a+e,d+f,this.strokeDashArray);b.util.drawDashedLine(c,a+e,d+f,a,d+f,this.strokeDashArray);b.util.drawDashedLine(c,a,d+f,a,d,this.strokeDashArray); +c.closePath()},toObject:function(b){return this.callSuper("toObject",["rx","ry"].concat(b))},toSVG:function(b){var a=this._createBaseSVGMarkup(),c=this.left,d=this.top;this.group&&"path-group"===this.group.type||(c=-this.width/2,d=-this.height/2);a.push("<rect ",this.getSvgId(),'x="',c,'" y="',d,'" rx="',this.get("rx"),'" ry="',this.get("ry"),'" width="',this.width,'" height="',this.height,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'"/>\n'); +return b?b(a.join("")):a.join("")}}),b.Rect.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),b.Rect.fromElement=function(c,a){if(!c)return null;a=a||{};var e=b.parseAttributes(c,b.Rect.ATTRIBUTE_NAMES);e.left=e.left||0;e.top=e.top||0;e=new b.Rect(d(a?b.util.object.clone(a):{},e));e.visible=e.visible&&0<e.width&&0<e.height;return e},b.Rect.fromObject=function(c,a,d){return b.Object._fromObject("Rect",c,a,d)})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend,c=b.util.array.min,a=b.util.array.max,g=b.util.toFixed,h=b.Object.NUM_FRACTION_DIGITS;b.Polyline?b.warn("fabric.Polyline is already defined"):(b.Polyline=b.util.createClass(b.Object,{type:"polyline",points:null,minX:0,minY:0,cacheProperties:b.Object.prototype.cacheProperties.concat("points"),initialize:function(a,b){b=b||{};this.points=a||[];this.callSuper("initialize",b);this._calcDimensions();"top"in b||(this.top=this.minY);"left"in +b||(this.left=this.minX);this.pathOffset={x:this.minX+this.width/2,y:this.minY+this.height/2}},_calcDimensions:function(){var b=this.points,d=c(b,"x"),e=c(b,"y"),g=a(b,"x"),b=a(b,"y");this.width=g-d||0;this.height=b-e||0;this.minX=d||0;this.minY=e||0},toObject:function(a){return d(this.callSuper("toObject",a),{points:this.points.concat()})},toSVG:function(a){var b=[],c=0,d=0,f=this._createBaseSVGMarkup();this.group&&"path-group"===this.group.type||(c=this.pathOffset.x,d=this.pathOffset.y);for(var e= +0,q=this.points.length;e<q;e++)b.push(g(this.points[e].x-c,h),",",g(this.points[e].y-d,h)," ");f.push("<",this.type," ",this.getSvgId(),'points="',b.join(""),'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform()," ",this.getSvgTransformMatrix(),'"/>\n');return a?a(f.join("")):f.join("")},commonRender:function(a,b){var c,d=this.points.length,f=b?0:this.pathOffset.x,e=b?0:this.pathOffset.y;if(!d||isNaN(this.points[d-1].y))return!1;a.beginPath();a.moveTo(this.points[0].x-f,this.points[0].y- +e);for(var g=0;g<d;g++)c=this.points[g],a.lineTo(c.x-f,c.y-e);return!0},_render:function(a,b){this.commonRender(a,b)&&(this._renderFill(a),this._renderStroke(a))},_renderDashedStroke:function(a){var c,d;a.beginPath();for(var f=0,e=this.points.length;f<e;f++)c=this.points[f],d=this.points[f+1]||c,b.util.drawDashedLine(a,c.x,c.y,d.x,d.y,this.strokeDashArray)},complexity:function(){return this.get("points").length}}),b.Polyline.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polyline.fromElement=function(a, +c){if(!a)return null;c||(c={});var d=b.parsePointsAttribute(a.getAttribute("points")),f=b.parseAttributes(a,b.Polyline.ATTRIBUTE_NAMES);return new b.Polyline(d,b.util.object.extend(f,c))},b.Polyline.fromObject=function(a,c,d){return b.Object._fromObject("Polyline",a,c,d,"points")})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.Polygon?b.warn("fabric.Polygon is already defined"):(b.Polygon=b.util.createClass(b.Polyline,{type:"polygon",_render:function(b,a){this.commonRender(b,a)&&(b.closePath(),this._renderFill(b),this._renderStroke(b))},_renderDashedStroke:function(b){this.callSuper("_renderDashedStroke",b);b.closePath()}}),b.Polygon.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(),b.Polygon.fromElement=function(c,a){if(!c)return null;a||(a={});var e=b.parsePointsAttribute(c.getAttribute("points")), +h=b.parseAttributes(c,b.Polygon.ATTRIBUTE_NAMES);return new b.Polygon(e,d(h,a))},b.Polygon.fromObject=function(c,a,d){return b.Object._fromObject("Polygon",c,a,d,"points")})})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.array.min,c=b.util.array.max,a=b.util.object.extend,g=Object.prototype.toString,h=b.util.drawArc,f={m:2,l:2,h:1,v:1,c:6,s:4,q:4,t:2,a:7},l={m:"l",M:"L"};b.Path?b.warn("fabric.Path is already defined"):(b.Path=b.util.createClass(b.Object,{type:"path",path:null,minX:0,minY:0,cacheProperties:b.Object.prototype.cacheProperties.concat("path","fillRule"),stateProperties:b.Object.prototype.stateProperties.concat("path"),initialize:function(a,b){b=b||{}; +this.callSuper("initialize",b);a||(a=[]);var c="[object Array]"===g.call(a);if(this.path=c?a:a.match&&a.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi))c||(this.path=this._parsePath()),this._setPositionDimensions(b)},_setPositionDimensions:function(a){var b=this._parseDimensions();this.minX=b.left;this.minY=b.top;this.width=b.width;this.height=b.height;"undefined"===typeof a.left&&(this.left=b.left+("center"===this.originX?this.width/2:"right"===this.originX?this.width:0));"undefined"===typeof a.top&&(this.top= +b.top+("center"===this.originY?this.height/2:"bottom"===this.originY?this.height:0));this.pathOffset=this.pathOffset||{x:this.minX+this.width/2,y:this.minY+this.height/2}},_renderPathCommands:function(a){var b,c=null,d=0,f=0,e=0,g=0,l=0,k=0,w,y,x=-this.pathOffset.x,u=-this.pathOffset.y;this.group&&"path-group"===this.group.type&&(u=x=0);a.beginPath();for(var C=0,D=this.path.length;C<D;++C){b=this.path[C];switch(b[0]){case "l":e+=b[1];g+=b[2];a.lineTo(e+x,g+u);break;case "L":e=b[1];g=b[2];a.lineTo(e+ +x,g+u);break;case "h":e+=b[1];a.lineTo(e+x,g+u);break;case "H":e=b[1];a.lineTo(e+x,g+u);break;case "v":g+=b[1];a.lineTo(e+x,g+u);break;case "V":g=b[1];a.lineTo(e+x,g+u);break;case "m":e+=b[1];g+=b[2];d=e;f=g;a.moveTo(e+x,g+u);break;case "M":e=b[1];g=b[2];d=e;f=g;a.moveTo(e+x,g+u);break;case "c":w=e+b[5];y=g+b[6];l=e+b[3];k=g+b[4];a.bezierCurveTo(e+b[1]+x,g+b[2]+u,l+x,k+u,w+x,y+u);e=w;g=y;break;case "C":e=b[5];g=b[6];l=b[3];k=b[4];a.bezierCurveTo(b[1]+x,b[2]+u,l+x,k+u,e+x,g+u);break;case "s":w=e+b[3]; +y=g+b[4];null===c[0].match(/[CcSs]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.bezierCurveTo(l+x,k+u,e+b[1]+x,g+b[2]+u,w+x,y+u);l=e+b[1];k=g+b[2];e=w;g=y;break;case "S":w=b[3];y=b[4];null===c[0].match(/[CcSs]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.bezierCurveTo(l+x,k+u,b[1]+x,b[2]+u,w+x,y+u);e=w;g=y;l=b[1];k=b[2];break;case "q":w=e+b[3];y=g+b[4];l=e+b[1];k=g+b[2];a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "Q":w=b[3];y=b[4];a.quadraticCurveTo(b[1]+x,b[2]+u,w+x,y+u);e=w;g=y;l=b[1];k=b[2];break;case "t":w= +e+b[1];y=g+b[2];null===c[0].match(/[QqTt]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "T":w=b[1];y=b[2];null===c[0].match(/[QqTt]/)?(l=e,k=g):(l=2*e-l,k=2*g-k);a.quadraticCurveTo(l+x,k+u,w+x,y+u);e=w;g=y;break;case "a":h(a,e+x,g+u,[b[1],b[2],b[3],b[4],b[5],b[6]+e+x,b[7]+g+u]);e+=b[6];g+=b[7];break;case "A":h(a,e+x,g+u,[b[1],b[2],b[3],b[4],b[5],b[6]+x,b[7]+u]);e=b[6];g=b[7];break;case "z":case "Z":e=d,g=f,a.closePath()}c=b}},_render:function(a){this._renderPathCommands(a); +this._renderFill(a);this._renderStroke(a)},toString:function(){return"#<fabric.Path ("+this.complexity()+'): { "top": '+this.top+', "left": '+this.left+" }>"},toObject:function(b){return a(this.callSuper("toObject",["sourcePath","pathOffset"].concat(b)),{path:this.path.map(function(a){return a.slice()}),top:this.top,left:this.left})},toDatalessObject:function(a){a=this.toObject(a);this.sourcePath&&(a.path=this.sourcePath);delete a.sourcePath;return a},toSVG:function(a){for(var b=[],c=this._createBaseSVGMarkup(), +d="",f=0,e=this.path.length;f<e;f++)b.push(this.path[f].join(" "));b=b.join(" ");this.group&&"path-group"===this.group.type||(d=" translate("+-this.pathOffset.x+", "+-this.pathOffset.y+") ");c.push("<path ",this.getSvgId(),'d="',b,'" style="',this.getSvgStyles(),'" transform="',this.getSvgTransform(),d,this.getSvgTransformMatrix(),'" stroke-linecap="round" ',"/>\n");return a?a(c.join("")):c.join("")},complexity:function(){return this.path.length},_parsePath:function(){for(var a=[],b=[],c,d,e=/([-+]?((\d+\.\d+)|((\d+)|(\.\d+)))(?:e[-+]?\d+)?)/ig, +g,h=0,v=this.path.length;h<v;h++){c=this.path[h];g=c.slice(1).trim();for(b.length=0;d=e.exec(g);)b.push(d[0]);c=[c.charAt(0)];g=0;for(var A=b.length;g<A;g++)d=parseFloat(b[g]),isNaN(d)||c.push(d);d=c[0];g=f[d.toLowerCase()];A=l[d]||d;if(c.length-1>g)for(var w=1,y=c.length;w<y;w+=g)a.push([d].concat(c.slice(w,w+g))),d=A;else a.push(c)}return a},_parseDimensions:function(){for(var a=[],f=[],e,g=null,h=0,l=0,r=0,v=0,A=0,w=0,y,x,u,C=0,D=this.path.length;C<D;++C){e=this.path[C];switch(e[0]){case "l":r+= +e[1];v+=e[2];u=[];break;case "L":r=e[1];v=e[2];u=[];break;case "h":r+=e[1];u=[];break;case "H":r=e[1];u=[];break;case "v":v+=e[1];u=[];break;case "V":v=e[1];u=[];break;case "m":r+=e[1];v+=e[2];h=r;l=v;u=[];break;case "M":r=e[1];v=e[2];h=r;l=v;u=[];break;case "c":y=r+e[5];x=v+e[6];A=r+e[3];w=v+e[4];u=b.util.getBoundsOfCurve(r,v,r+e[1],v+e[2],A,w,y,x);r=y;v=x;break;case "C":A=e[3];w=e[4];u=b.util.getBoundsOfCurve(r,v,e[1],e[2],A,w,e[5],e[6]);r=e[5];v=e[6];break;case "s":y=r+e[3];x=v+e[4];null===g[0].match(/[CcSs]/)? +(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,r+e[1],v+e[2],y,x);A=r+e[1];w=v+e[2];r=y;v=x;break;case "S":y=e[3];x=e[4];null===g[0].match(/[CcSs]/)?(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,e[1],e[2],y,x);r=y;v=x;A=e[1];w=e[2];break;case "q":y=r+e[3];x=v+e[4];A=r+e[1];w=v+e[2];u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "Q":A=e[1];w=e[2];u=b.util.getBoundsOfCurve(r,v,A,w,A,w,e[3],e[4]);r=e[3];v=e[4];break;case "t":y=r+e[1];x=v+e[2];null===g[0].match(/[QqTt]/)? +(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "T":y=e[1];x=e[2];null===g[0].match(/[QqTt]/)?(A=r,w=v):(A=2*r-A,w=2*v-w);u=b.util.getBoundsOfCurve(r,v,A,w,A,w,y,x);r=y;v=x;break;case "a":u=b.util.getBoundsOfArc(r,v,e[1],e[2],e[3],e[4],e[5],e[6]+r,e[7]+v);r+=e[6];v+=e[7];break;case "A":u=b.util.getBoundsOfArc(r,v,e[1],e[2],e[3],e[4],e[5],e[6],e[7]);r=e[6];v=e[7];break;case "z":case "Z":r=h,v=l}g=e;u.forEach(function(b){a.push(b.x);f.push(b.y)});a.push(r); +f.push(v)}e=d(a)||0;g=d(f)||0;h=c(a)||0;l=c(f)||0;return{left:e,top:g,width:h-e,height:l-g}}}),b.Path.fromObject=function(a,c,d){var e;if("string"===typeof a.path)b.loadSVGFromURL(a.path,function(b){var d=a.path;e=b[0];delete a.path;e.setOptions(a);e.setSourcePath(d);c&&c(e)});else return b.Object._fromObject("Path",a,c,d,"path")},b.Path.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat(["d"]),b.Path.fromElement=function(c,d,e){c=b.parseAttributes(c,b.Path.ATTRIBUTE_NAMES);d&&d(new b.Path(c.d,a(c,e)))}, +b.Path.async=!0)})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;b.PathGroup?b.warn("fabric.PathGroup is already defined"):(b.PathGroup=b.util.createClass(b.Object,{type:"path-group",fill:"",cacheProperties:[],initialize:function(b,a){a=a||{};this.paths=b||[];for(var c=this.paths.length;c--;)this.paths[c].group=this;a.toBeParsed&&(this.parseDimensionsFromPaths(a),delete a.toBeParsed);this.setOptions(a);this.setCoords()},parseDimensionsFromPaths:function(c){for(var a,d,e=[],f=[],l,k=this.paths.length;k--;){a= +this.paths[k];d=a.height+a.strokeWidth;l=a.width+a.strokeWidth;a=[{x:a.left,y:a.top},{x:a.left+l,y:a.top},{x:a.left,y:a.top+d},{x:a.left+l,y:a.top+d}];l=this.paths[k].transformMatrix;for(var m=0;m<a.length;m++)d=a[m],l&&(d=b.util.transformPoint(d,l,!1)),e.push(d.x),f.push(d.y)}c.width=Math.max.apply(null,e);c.height=Math.max.apply(null,f)},drawObject:function(b){b.save();b.translate(-this.width/2,-this.height/2);for(var a=0,c=this.paths.length;a<c;++a)this.paths[a].render(b,!0);b.restore()},shouldCache:function(){var b= +this.objectCaching&&(!this.group||this.needsItsOwnCache()||!this.group.isCaching());if(this.caching=b)for(var a=0,d=this.paths.length;a<d;a++)if(this.paths[a].willDrawShadow())return this.caching=!1;return b},willDrawShadow:function(){if(this.shadow)return!0;for(var b=0,a=this.paths.length;b<a;b++)if(this.paths[b].willDrawShadow())return!0;return!1},isCaching:function(){return this.caching||this.group&&this.group.isCaching()},isCacheDirty:function(){if(this.callSuper("isCacheDirty"))return!0;if(!this.statefullCache)return!1; +for(var b=0,a=this.paths.length;b<a;b++)if(this.paths[b].isCacheDirty(!0))return this._cacheCanvas&&(b=this.cacheWidth/this.zoomX,a=this.cacheHeight/this.zoomY,this._cacheContext.clearRect(-b/2,-a/2,b,a)),!0;return!1},_set:function(b,a){if("fill"===b&&a&&this.isSameColor())for(var c=this.paths.length;c--;)this.paths[c]._set(b,a);return this.callSuper("_set",b,a)},toObject:function(b){var a=this.paths.map(function(a){var c=a.includeDefaultValues;a.includeDefaultValues=a.group.includeDefaultValues; +var d=a.toObject(b);a.includeDefaultValues=c;return d});return d(this.callSuper("toObject",["sourcePath"].concat(b)),{paths:a})},toDatalessObject:function(b){b=this.toObject(b);this.sourcePath&&(b.paths=this.sourcePath);return b},toSVG:function(b){var a=this.getObjects(),c=this.getPointByOrigin("left","top"),d="translate("+c.x+" "+c.y+")",c=this._createBaseSVGMarkup();c.push("<g ",this.getSvgId(),'style="',this.getSvgStyles(),'" ','transform="',this.getSvgTransformMatrix(),d,this.getSvgTransform(), +'" ',">\n");for(var d=0,e=a.length;d<e;d++)c.push("\t",a[d].toSVG(b));c.push("</g>\n");return b?b(c.join("")):c.join("")},toString:function(){return"#<fabric.PathGroup ("+this.complexity()+"): { top: "+this.top+", left: "+this.left+" }>"},isSameColor:function(){var b=this.getObjects()[0].get("fill")||"";if("string"!==typeof b)return!1;b=b.toLowerCase();return this.getObjects().every(function(a){a=a.get("fill")||"";return"string"===typeof a&&a.toLowerCase()===b})},complexity:function(){return this.paths.reduce(function(b, +a){return b+(a&&a.complexity?a.complexity():0)},0)},getObjects:function(){return this.paths}}),b.PathGroup.fromObject=function(c,a){var d=c.paths;delete c.paths;"string"===typeof d?b.loadSVGFromURL(d,function(e){e=b.util.groupSVGElements(e,c,d);c.paths=d;a(e)}):b.util.enlivenObjects(d,function(e){e=new b.PathGroup(e,c);c.paths=d;a(e)})},b.PathGroup.async=!0)})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend,c=b.util.array.min,a=b.util.array.max;if(!b.Group){var g={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};b.Group=b.util.createClass(b.Object,b.Collection,{type:"group",strokeWidth:0,subTargetCheck:!1,cacheProperties:[],initialize:function(a,b,c){b=b||{};this._objects=[];c&&this.callSuper("initialize",b);this._objects=a||[];for(a=this._objects.length;a--;)this._objects[a].group=this; +b.originX&&(this.originX=b.originX);b.originY&&(this.originY=b.originY);c?(this._updateObjectsCoords(!0),this._updateObjectsACoords()):(this._calcBounds(),this._updateObjectsCoords(),this.callSuper("initialize",b));this.setCoords();this.saveCoords()},_updateObjectsACoords:function(){for(var a=this._objects.length;a--;)this._objects[a].setCoords(!0,!0)},_updateObjectsCoords:function(a){for(var b=this.getCenterPoint(),c=this._objects.length;c--;)this._updateObjectCoords(this._objects[c],b,a)},_updateObjectCoords:function(a, +b,c){a.__origHasControls=a.hasControls;a.hasControls=!1;if(!c){c=a.getLeft();var d=a.getTop();a.set({left:c-b.x,top:d-b.y});a.setCoords(!0,!0)}},toString:function(){return"#<fabric.Group: ("+this.complexity()+")>"},addWithUpdate:function(a){this._restoreObjectsState();b.util.resetObjectTransform(this);a&&(this._objects.push(a),a.group=this,a._set("canvas",this.canvas));this.forEachObject(this._setObjectActive,this);this._calcBounds();this._updateObjectsCoords();this.setCoords();this.dirty=!0;return this}, +_setObjectActive:function(a){a.set("active",!0);a.group=this},removeWithUpdate:function(a){this._restoreObjectsState();b.util.resetObjectTransform(this);this.forEachObject(this._setObjectActive,this);this.remove(a);this._calcBounds();this._updateObjectsCoords();this.setCoords();this.dirty=!0;return this},_onObjectAdded:function(a){this.dirty=!0;a.group=this;a._set("canvas",this.canvas)},_onObjectRemoved:function(a){this.dirty=!0;delete a.group;a.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(a,b){var c=this._objects.length;if(this.delegatedProperties[a]||"canvas"===a)for(;c--;)this._objects[c].set(a,b);else for(;c--;)this._objects[c].setOnGroup(a,b);this.callSuper("_set",a,b)},toObject:function(a){var b=this.getObjects().map(function(b){var c=b.includeDefaultValues;b.includeDefaultValues=b.group.includeDefaultValues;var d=b.toObject(a);b.includeDefaultValues= +c;return d});return d(this.callSuper("toObject",a),{objects:b})},toDatalessObject:function(a){var b=this.getObjects().map(function(b){var c=b.includeDefaultValues;b.includeDefaultValues=b.group.includeDefaultValues;var d=b.toDatalessObject(a);b.includeDefaultValues=c;return d});return d(this.callSuper("toDatalessObject",a),{objects:b})},render:function(a){this._transformDone=!0;this.callSuper("render",a);this._transformDone=!1},shouldCache:function(){var a=this.objectCaching&&(!this.group||this.needsItsOwnCache()|| +!this.group.isCaching());if(this.caching=a)for(var b=0,c=this._objects.length;b<c;b++)if(this._objects[b].willDrawShadow())return this.caching=!1;return a},willDrawShadow:function(){if(this.callSuper("willDrawShadow"))return!0;for(var a=0,b=this._objects.length;a<b;a++)if(this._objects[a].willDrawShadow())return!0;return!1},isCaching:function(){return this.caching||this.group&&this.group.isCaching()},drawObject:function(a){for(var b=0,c=this._objects.length;b<c;b++)this._renderObject(this._objects[b], +a)},isCacheDirty:function(){if(this.callSuper("isCacheDirty"))return!0;if(!this.statefullCache)return!1;for(var a=0,b=this._objects.length;a<b;a++)if(this._objects[a].isCacheDirty(!0))return this._cacheCanvas&&(a=this.cacheWidth/this.zoomX,b=this.cacheHeight/this.zoomY,this._cacheContext.clearRect(-a/2,-b/2,a,b)),!0;return!1},_renderControls:function(a,b){a.save();a.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1;this.callSuper("_renderControls",a,b);for(var c=0,d=this._objects.length;c< +d;c++)this._objects[c]._renderControls(a);a.restore()},_renderObject:function(a,b){if(a.visible){var c=a.hasRotatingPoint;a.hasRotatingPoint=!1;a.render(b);a.hasRotatingPoint=c}},_restoreObjectsState:function(){this._objects.forEach(this._restoreObjectState,this);return this},realizeTransform:function(a){var c=a.calcTransformMatrix(),c=b.util.qrDecompose(c),d=new b.Point(c.translateX,c.translateY);a.flipX=!1;a.flipY=!1;a.set("scaleX",c.scaleX);a.set("scaleY",c.scaleY);a.skewX=c.skewX;a.skewY=c.skewY; +a.angle=c.angle;a.setPositionByOrigin(d,"center","center");return a},_restoreObjectState:function(a){this.realizeTransform(a);a.setCoords();a.hasControls=a.__origHasControls;delete a.__origHasControls;a.set("active",!1);delete a.group;return this},destroy:function(){this._objects.forEach(function(a){a.set("dirty",!0)});return this._restoreObjectsState()},saveCoords:function(){this._originalLeft=this.get("left");this._originalTop=this.get("top");return this},hasMoved:function(){return this._originalLeft!== +this.get("left")||this._originalTop!==this.get("top")},setObjectsCoords:function(){this.forEachObject(function(a){a.setCoords(!0,!0)});return this},_calcBounds:function(a){for(var b=[],c=[],d,e,g=["tr","br","bl","tl"],h=0,q=this._objects.length,t,r=g.length;h<q;++h)for(d=this._objects[h],d.setCoords(!0),t=0;t<r;t++)e=g[t],b.push(d.oCoords[e].x),c.push(d.oCoords[e].y);this.set(this._getBounds(b,c,a))},_getBounds:function(d,e,g){var f=new b.Point(c(d),c(e));d=new b.Point(a(d),a(e));d={width:d.x-f.x|| +0,height:d.y-f.y||0};g||(d.left=f.x||0,d.top=f.y||0,"center"===this.originX&&(d.left+=d.width/2),"right"===this.originX&&(d.left+=d.width),"center"===this.originY&&(d.top+=d.height/2),"bottom"===this.originY&&(d.top+=d.height));return d},toSVG:function(a){var b=this._createBaseSVGMarkup();b.push("<g ",this.getSvgId(),'transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'" style="',this.getSvgFilter(),'">\n');for(var c=0,d=this._objects.length;c<d;c++)b.push("\t",this._objects[c].toSVG(a)); +b.push("</g>\n");return a?a(b.join("")):b.join("")},get:function(a){if(a in g){if(this[a])return this[a];for(var b=0,c=this._objects.length;b<c;b++)if(this._objects[b][a])return!0;return!1}return a in this.delegatedProperties?this._objects[0]&&this._objects[0].get(a):this[a]}});b.Group.fromObject=function(a,c){b.util.enlivenObjects(a.objects,function(d){var e=b.util.object.clone(a,!0);delete e.objects;c&&c(new b.Group(d,e,!0))})};b.Group.async=!0}})("undefined"!==typeof exports?exports:this); +(function(e){var b=fabric.util.object.extend;e.fabric||(e.fabric={});e.fabric.Image?fabric.warn("fabric.Image is already defined."):(fabric.Image=fabric.util.createClass(fabric.Object,{type:"image",crossOrigin:"",alignX:"none",alignY:"none",meetOrSlice:"meet",strokeWidth:0,_lastScaleX:1,_lastScaleY:1,minimumScaleTrigger:.5,stateProperties:fabric.Object.prototype.stateProperties.concat("alignX","alignY","meetOrSlice"),objectCaching:!1,initialize:function(b,c,a){c||(c={});this.filters=[];this.resizeFilters= +[];this.callSuper("initialize",c);this._initElement(b,c,a)},getElement:function(){return this._element},setElement:function(b,c,a){var d;this._originalElement=this._element=b;this._initConfig(a);0===this.resizeFilters.length?b=c:(d=this,b=function(){d.applyFilters(c,d.resizeFilters,d._filteredEl||d._originalElement,!0)});0!==this.filters.length?this.applyFilters(b):b&&b(this);return this},setCrossOrigin:function(b){this.crossOrigin=b;this._element.crossOrigin=b;return this},getOriginalSize:function(){var b= +this.getElement();return{width:b.width,height:b.height}},_stroke:function(b){if(this.stroke&&0!==this.strokeWidth){var c=this.width/2,a=this.height/2;b.beginPath();b.moveTo(-c,-a);b.lineTo(c,-a);b.lineTo(c,a);b.lineTo(-c,a);b.lineTo(-c,-a);b.closePath()}},_renderDashedStroke:function(b){var c=-this.width/2,a=-this.height/2,d=this.width,e=this.height;b.save();this._setStrokeStyles(b);b.beginPath();fabric.util.drawDashedLine(b,c,a,c+d,a,this.strokeDashArray);fabric.util.drawDashedLine(b,c+d,a,c+d,a+ +e,this.strokeDashArray);fabric.util.drawDashedLine(b,c+d,a+e,c,a+e,this.strokeDashArray);fabric.util.drawDashedLine(b,c,a+e,c,a,this.strokeDashArray);b.closePath();b.restore()},toObject:function(d){var c=[],a=[],e=1,h=1;this.filters.forEach(function(a){a&&("Resize"===a.type&&(e*=a.scaleX,h*=a.scaleY),c.push(a.toObject()))});this.resizeFilters.forEach(function(b){b&&a.push(b.toObject())});d=b(this.callSuper("toObject",["crossOrigin","alignX","alignY","meetOrSlice"].concat(d)),{src:this.getSrc(),filters:c, +resizeFilters:a});d.width/=e;d.height/=h;return d},toSVG:function(b){var c=this._createBaseSVGMarkup(),a=-this.width/2,d=-this.height/2,e="none";this.group&&"path-group"===this.group.type&&(a=this.left,d=this.top);"none"!==this.alignX&&"none"!==this.alignY&&(e="x"+this.alignX+"Y"+this.alignY+" "+this.meetOrSlice);c.push('<g transform="',this.getSvgTransform(),this.getSvgTransformMatrix(),'">\n',"<image ",this.getSvgId(),'xlink:href="',this.getSvgSrc(!0),'" x="',a,'" y="',d,'" style="',this.getSvgStyles(), +'" width="',this.width,'" height="',this.height,'" preserveAspectRatio="',e,'"',"></image>\n");if(this.stroke||this.strokeDashArray)e=this.fill,this.fill=null,c.push("<rect ",'x="',a,'" y="',d,'" width="',this.width,'" height="',this.height,'" style="',this.getSvgStyles(),'"/>\n'),this.fill=e;c.push("</g>\n");return b?b(c.join("")):c.join("")},getSrc:function(b){return(b=b?this._element:this._originalElement)?fabric.isLikelyNode?b._src:b.src:this.src||""},setSrc:function(b,c,a){fabric.util.loadImage(b, +function(b){return this.setElement(b,c,a)},this,a&&a.crossOrigin)},toString:function(){return'#<fabric.Image: { src: "'+this.getSrc()+'" }>'},applyFilters:function(b,c,a,e){c=c||this.filters;if(a=a||this._originalElement){var d=fabric.util.createImage(),f=this.canvas?this.canvas.getRetinaScaling():fabric.devicePixelRatio,g=this.minimumScaleTrigger/f,k=this,m,n;if(0===c.length)return this._element=a,b&&b(this),a;var p=fabric.util.createCanvasElement();p.width=a.width;p.height=a.height;p.getContext("2d").drawImage(a, +0,0,a.width,a.height);c.forEach(function(a){a&&(e?(m=k.scaleX<g?k.scaleX:1,n=k.scaleY<g?k.scaleY:1,1>m*f&&(m*=f),1>n*f&&(n*=f)):(m=a.scaleX,n=a.scaleY),a.applyTo(p,m,n),e||"Resize"!==a.type||(k.width*=a.scaleX,k.height*=a.scaleY))});d.width=p.width;d.height=p.height;fabric.isLikelyNode?(d.src=p.toBuffer(void 0,fabric.Image.pngCompression),k._element=d,!e&&(k._filteredEl=d),b&&b(k)):(d.onload=function(){k._element=d;!e&&(k._filteredEl=d);b&&b(k);d.onload=p=null},d.src=p.toDataURL("image/png"));return p}}, +_render:function(b,c){var a,d,e=this._findMargins(),f;a=c?this.left:-this.width/2;d=c?this.top:-this.height/2;"slice"===this.meetOrSlice&&(b.beginPath(),b.rect(a,d,this.width,this.height),b.clip());!1===this.isMoving&&this.resizeFilters.length&&this._needsResize()?(this._lastScaleX=this.scaleX,this._lastScaleY=this.scaleY,f=this.applyFilters(null,this.resizeFilters,this._filteredEl||this._originalElement,!0)):f=this._element;f&&b.drawImage(f,a+e.marginX,d+e.marginY,e.width,e.height);this._stroke(b); +this._renderStroke(b)},_needsResize:function(){return this.scaleX!==this._lastScaleX||this.scaleY!==this._lastScaleY},_findMargins:function(){var b=this.width,c=this.height,a=0,e=0;if("none"!==this.alignX||"none"!==this.alignY)b=[this.width/this._element.width,this.height/this._element.height],c="meet"===this.meetOrSlice?Math.min.apply(null,b):Math.max.apply(null,b),b=this._element.width*c,c*=this._element.height,"Mid"===this.alignX&&(a=(this.width-b)/2),"Max"===this.alignX&&(a=this.width-b),"Mid"=== +this.alignY&&(e=(this.height-c)/2),"Max"===this.alignY&&(e=this.height-c);return{width:b,height:c,marginX:a,marginY:e}},_resetWidthHeight:function(){var b=this.getElement();this.set("width",b.width);this.set("height",b.height)},_initElement:function(b,c,a){this.setElement(fabric.util.getById(b),a,c);fabric.util.addClass(this.getElement(),fabric.Image.CSS_CANVAS)},_initConfig:function(b){b||(b={});this.setOptions(b);this._setWidthHeight(b);this._element&&this.crossOrigin&&(this._element.crossOrigin= +this.crossOrigin)},_initFilters:function(b,c){b&&b.length?fabric.util.enlivenObjects(b,function(a){c&&c(a)},"fabric.Image.filters"):c&&c()},_setWidthHeight:function(b){this.width="width"in b?b.width:this.getElement()?this.getElement().width||0:0;this.height="height"in b?b.height:this.getElement()?this.getElement().height||0:0}}),fabric.Image.CSS_CANVAS="canvas-img",fabric.Image.prototype.getSvgSrc=fabric.Image.prototype.getSrc,fabric.Image.fromObject=function(b,c){fabric.util.loadImage(b.src,function(a, +d){d?c&&c(null,d):fabric.Image.prototype._initFilters.call(b,b.filters,function(d){b.filters=d||[];fabric.Image.prototype._initFilters.call(b,b.resizeFilters,function(d){b.resizeFilters=d||[];return new fabric.Image(a,b,c)})})},null,b.crossOrigin)},fabric.Image.fromURL=function(b,c,a){fabric.util.loadImage(b,function(b){c&&c(new fabric.Image(b,a))},null,a&&a.crossOrigin)},fabric.Image.ATTRIBUTE_NAMES=fabric.SHARED_ATTRIBUTES.concat("x y width height preserveAspectRatio xlink:href crossOrigin".split(" ")), +fabric.Image.fromElement=function(d,c,a){d=fabric.parseAttributes(d,fabric.Image.ATTRIBUTE_NAMES);var e;d.preserveAspectRatio&&(e=fabric.util.parsePreserveAspectRatioAttribute(d.preserveAspectRatio),b(d,e));fabric.Image.fromURL(d["xlink:href"],c,b(a?fabric.util.object.clone(a):{},d))},fabric.Image.async=!0,fabric.Image.pngCompression=1)})("undefined"!==typeof exports?exports:this); +fabric.util.object.extend(fabric.Object.prototype,{_getAngleValueForStraighten:function(){var e=this.getAngle()%360;return 0<e?90*Math.round((e-1)/90):90*Math.round(e/90)},straighten:function(){this.setAngle(this._getAngleValueForStraighten());return this},fxStraighten:function(e){e=e||{};var b=function(){},d=e.onComplete||b,c=e.onChange||b,a=this;fabric.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(b){a.setAngle(b); +c()},onComplete:function(){a.setCoords();d()},onStart:function(){a.set("active",!1)}});return this}});fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(e){e.straighten();this.renderAll();return this},fxStraightenObject:function(e){e.fxStraighten({onChange:this.renderAll.bind(this)});return this}});fabric.Image.filters=fabric.Image.filters||{}; +fabric.Image.filters.BaseFilter=fabric.util.createClass({type:"BaseFilter",initialize:function(e){e&&this.setOptions(e)},setOptions:function(e){for(var b in e)this[b]=e[b]},toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}});fabric.Image.filters.BaseFilter.fromObject=function(e,b){var d=new fabric.Image.filters[e.type](e);b&&b(d);return d}; +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Brightness=c(d.BaseFilter,{type:"Brightness",initialize:function(a){a=a||{};this.brightness=a.brightness||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.brightness,e=0,k=c.length;e<k;e+=4)c[e]+=d,c[e+1]+=d,c[e+2]+=d;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{brightness:this.brightness})}});e.Image.filters.Brightness.fromObject= +e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Convolute=c(d.BaseFilter,{type:"Convolute",initialize:function(a){a=a||{};this.opaque=a.opaque;this.matrix=a.matrix||[0,0,0,0,1,0,0,0,0]},applyTo:function(a){var b=this.matrix,c=a.getContext("2d"),d=c.getImageData(0,0,a.width,a.height);a=Math.round(Math.sqrt(b.length));for(var e=Math.floor(a/2),k=d.data,m=d.width,d=d.height,n=c.createImageData(m,d),p=n.data,q=this.opaque?1:0,t,r,v,A,w,y,x,u= +0;u<d;u++)for(var C=0;C<m;C++){w=4*(u*m+C);for(var D=A=v=r=t=0;D<a;D++)for(var z=0;z<a;z++)x=u+D-e,y=C+z-e,0>x||x>d||0>y||y>m||(y=4*(x*m+y),x=b[D*a+z],t+=k[y]*x,r+=k[y+1]*x,v+=k[y+2]*x,A+=k[y+3]*x);p[w]=t;p[w+1]=r;p[w+2]=v;p[w+3]=A+q*(255-A)}c.putImageData(n,0,0)},toObject:function(){return b(this.callSuper("toObject"),{opaque:this.opaque,matrix:this.matrix})}});e.Image.filters.Convolute.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.GradientTransparency=c(d.BaseFilter,{type:"GradientTransparency",initialize:function(a){a=a||{};this.threshold=a.threshold||100},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.threshold,e=c.length,k=0,m=c.length;k<m;k+=4)c[k+3]=d+255*(e-k)/e;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{threshold:this.threshold})}}); +e.Image.filters.GradientTransparency.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Grayscale=d(e.BaseFilter,{type:"Grayscale",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);for(var c=b.data,d=b.width*b.height*4,e=0,l;e<d;)l=(c[e]+c[e+1]+c[e+2])/3,c[e]=l,c[e+1]=l,c[e+2]=l,e+=4;a.putImageData(b,0,0)}});b.Image.filters.Grayscale.fromObject=function(c,a){c=c||{};c.type="Grayscale";return b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports? +exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Invert=d(e.BaseFilter,{type:"Invert",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e;for(e=0;e<d;e+=4)c[e]=255-c[e],c[e+1]=255-c[e+1],c[e+2]=255-c[e+2];a.putImageData(b,0,0)}});b.Image.filters.Invert.fromObject=function(c,a){c=c||{};c.type="Invert";return b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Mask=c(e.BaseFilter,{type:"Mask",initialize:function(a){a=a||{};this.mask=a.mask;this.channel=-1<[0,1,2,3].indexOf(a.channel)?a.channel:0},applyTo:function(a){if(this.mask){var c=a.getContext("2d"),d=c.getImageData(0,0,a.width,a.height),e=d.data,l=this.mask.getElement(),k=b.util.createCanvasElement(),m=this.channel,n=d.width*d.height*4;k.width=a.width;k.height=a.height;k.getContext("2d").drawImage(l, +0,0,a.width,a.height);l=k.getContext("2d").getImageData(0,0,a.width,a.height).data;for(a=0;a<n;a+=4)e[a+3]=l[a+m];c.putImageData(d,0,0)}},toObject:function(){return d(this.callSuper("toObject"),{mask:this.mask.toObject(),channel:this.channel})}});b.Image.filters.Mask.fromObject=function(a,c){b.util.loadImage(a.mask.src,function(d){a.mask=new b.Image(d,a.mask);return b.Image.filters.BaseFilter.fromObject(a,c)})};b.Image.filters.Mask.async=!0})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Noise=c(d.BaseFilter,{type:"Noise",initialize:function(a){a=a||{};this.noise=a.noise||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.noise,e,k=0,m=c.length;k<m;k+=4)e=(.5-Math.random())*d,c[k]+=e,c[k+1]+=e,c[k+2]+=e;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{noise:this.noise})}});e.Image.filters.Noise.fromObject= +e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Pixelate=c(d.BaseFilter,{type:"Pixelate",initialize:function(a){a=a||{};this.blocksize=a.blocksize||4},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);var c=a.data,d=a.height,e=a.width,k,m,n,p,q,t,r;for(m=0;m<d;m+=this.blocksize)for(n=0;n<e;n+=this.blocksize){k=4*m*e+4*n;p=c[k];q=c[k+1];t=c[k+2];r=c[k+3];for(var v=m,A=m+this.blocksize;v<A;v++)for(var w=n,y= +n+this.blocksize;w<y;w++)k=4*v*e+4*w,c[k]=p,c[k+1]=q,c[k+2]=t,c[k+3]=r}b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{blocksize:this.blocksize})}});e.Image.filters.Pixelate.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.RemoveWhite=c(d.BaseFilter,{type:"RemoveWhite",initialize:function(a){a=a||{};this.threshold=a.threshold||30;this.distance=a.distance||20},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=this.distance,e=255-this.threshold,k=Math.abs,m,n,p,q=0,t=c.length;q<t;q+=4)m=c[q],n=c[q+1],p=c[q+2],m>e&&n>e&&p>e&&k(m-n)<d&&k(m-p)<d&&k(n-p)<d&&(c[q+3]= +0);b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{threshold:this.threshold,distance:this.distance})}});e.Image.filters.RemoveWhite.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Sepia=d(e.BaseFilter,{type:"Sepia",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e,l;for(e=0;e<d;e+=4)l=.3*c[e]+.59*c[e+1]+.11*c[e+2],c[e]=l+100,c[e+1]=l+50,c[e+2]=l+255;a.putImageData(b,0,0)}});b.Image.filters.Sepia.fromObject=function(c,a){c=c||{};c.type="Sepia";return new b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!==typeof exports? +exports:this); +(function(e){var b=e.fabric||(e.fabric={});e=b.Image.filters;var d=b.util.createClass;e.Sepia2=d(e.BaseFilter,{type:"Sepia2",applyTo:function(b){var a=b.getContext("2d");b=a.getImageData(0,0,b.width,b.height);var c=b.data,d=c.length,e,l,k,m;for(e=0;e<d;e+=4)l=c[e],k=c[e+1],m=c[e+2],c[e]=(.393*l+.769*k+.189*m)/1.351,c[e+1]=(.349*l+.686*k+.168*m)/1.203,c[e+2]=(.272*l+.534*k+.131*m)/2.14;a.putImageData(b,0,0)}});b.Image.filters.Sepia2.fromObject=function(c,a){c=c||{};c.type="Sepia2";return new b.Image.filters.BaseFilter.fromObject(c,a)}})("undefined"!== +typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Tint=c(e.BaseFilter,{type:"Tint",initialize:function(a){a=a||{};this.color=a.color||"#000000";this.opacity="undefined"!==typeof a.opacity?a.opacity:(new b.Color(this.color)).getAlpha()},applyTo:function(a){var c=a.getContext("2d");a=c.getImageData(0,0,a.width,a.height);var d=a.data,e=d.length,l,k,m,n,p,q,t,r;l=(new b.Color(this.color)).getSource();k=l[0]*this.opacity;m=l[1]*this.opacity; +n=l[2]*this.opacity;r=1-this.opacity;for(l=0;l<e;l+=4)p=d[l],q=d[l+1],t=d[l+2],d[l]=k+p*r,d[l+1]=m+q*r,d[l+2]=n+t*r;c.putImageData(a,0,0)},toObject:function(){return d(this.callSuper("toObject"),{color:this.color,opacity:this.opacity})}});b.Image.filters.Tint.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.object.extend;e=b.Image.filters;var c=b.util.createClass;e.Multiply=c(e.BaseFilter,{type:"Multiply",initialize:function(a){a=a||{};this.color=a.color||"#000000"},applyTo:function(a){var c=a.getContext("2d");a=c.getImageData(0,0,a.width,a.height);var d=a.data,e=d.length,l,k;k=(new b.Color(this.color)).getSource();for(l=0;l<e;l+=4)d[l]*=k[0]/255,d[l+1]*=k[1]/255,d[l+2]*=k[2]/255;c.putImageData(a,0,0)},toObject:function(){return d(this.callSuper("toObject"), +{color:this.color})}});b.Image.filters.Multiply.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric;e=b.Image.filters;var d=b.util.createClass;e.Blend=d(e.BaseFilter,{type:"Blend",initialize:function(b){b=b||{};this.color=b.color||"#000";this.image=b.image||!1;this.mode=b.mode||"multiply";this.alpha=b.alpha||1},applyTo:function(c){var a=c.getContext("2d");c=a.getImageData(0,0,c.width,c.height);var d=c.data,e,f,l,k,m,n,p,q=!1;this.image?(q=!0,p=b.util.createCanvasElement(),p.width=this.image.width,p.height=this.image.height,p=new b.StaticCanvas(p),p.add(this.image),p= +p.getContext("2d").getImageData(0,0,p.width,p.height).data):(p=(new b.Color(this.color)).getSource(),e=p[0]*this.alpha,f=p[1]*this.alpha,l=p[2]*this.alpha);for(var t=0,r=d.length;t<r;t+=4)switch(k=d[t],m=d[t+1],n=d[t+2],q&&(e=p[t]*this.alpha,f=p[t+1]*this.alpha,l=p[t+2]*this.alpha),this.mode){case "multiply":d[t]=k*e/255;d[t+1]=m*f/255;d[t+2]=n*l/255;break;case "screen":d[t]=1-(1-k)*(1-e);d[t+1]=1-(1-m)*(1-f);d[t+2]=1-(1-n)*(1-l);break;case "add":d[t]=Math.min(255,k+e);d[t+1]=Math.min(255,m+f);d[t+ +2]=Math.min(255,n+l);break;case "diff":case "difference":d[t]=Math.abs(k-e);d[t+1]=Math.abs(m-f);d[t+2]=Math.abs(n-l);break;case "subtract":k-=e;m-=f;n-=l;d[t]=0>k?0:k;d[t+1]=0>m?0:m;d[t+2]=0>n?0:n;break;case "darken":d[t]=Math.min(k,e);d[t+1]=Math.min(m,f);d[t+2]=Math.min(n,l);break;case "lighten":d[t]=Math.max(k,e),d[t+1]=Math.max(m,f),d[t+2]=Math.max(n,l)}a.putImageData(c,0,0)},toObject:function(){return{color:this.color,image:this.image,mode:this.mode,alpha:this.alpha}}});b.Image.filters.Blend.fromObject= +b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=Math.pow,c=Math.floor,a=Math.sqrt,g=Math.abs,h=Math.max,f=Math.round,l=Math.sin,k=Math.ceil;e=b.Image.filters;var m=b.util.createClass;e.Resize=m(e.BaseFilter,{type:"Resize",resizeType:"hermite",scaleX:0,scaleY:0,lanczosLobes:3,applyTo:function(a,b,c){if(1!==b||1!==c){this.rcpScaleX=1/b;this.rcpScaleY=1/c;var d=a.width,e=a.height;b=f(d*b);c=f(e*c);var g;"sliceHack"===this.resizeType&&(g=this.sliceByTwo(a,d,e,b,c));"hermite"===this.resizeType&&(g=this.hermiteFastResize(a, +d,e,b,c));"bilinear"===this.resizeType&&(g=this.bilinearFiltering(a,d,e,b,c));"lanczos"===this.resizeType&&(g=this.lanczosResize(a,d,e,b,c));a.width=b;a.height=c;a.getContext("2d").putImageData(g,0,0)}},sliceByTwo:function(a,d,e,f,g){var k=a.getContext("2d"),l,m=.5,n=.5,p=1,q=1,t=!1,r=!1,z=d,E=e,B=b.util.createCanvasElement(),F=B.getContext("2d");f=c(f);g=c(g);B.width=h(f,d);B.height=h(g,e);f>d&&(m=2,p=-1);g>e&&(n=2,q=-1);l=k.getImageData(0,0,d,e);a.width=h(f,d);a.height=h(g,e);for(k.putImageData(l, +0,0);!t||!r;)d=z,e=E,f*p<c(z*m*p)?z=c(z*m):(z=f,t=!0),g*q<c(E*n*q)?E=c(E*n):(E=g,r=!0),l=k.getImageData(0,0,d,e),F.putImageData(l,0,0),k.clearRect(0,0,z,E),k.drawImage(B,0,0,d,e,0,0,z,E);return k.getImageData(0,0,f,g)},lanczosResize:function(b,e,f,h,m){var n,p,q,t;function r(b){var k,l,u,v,w,x,A,y,J,M;q=(b+.5)*B;n=c(q);for(k=0;k<m;k++){t=(k+.5)*F;p=c(t);J=y=A=x=w=0;for(l=n-L;l<=n+L;l++)if(!(0>l||l>=e)){M=c(1E3*g(l-q));H[M]||(H[M]={});for(var N=p-O;N<=p+O;N++)0>N||N>=f||(u=c(1E3*g(N-t)),H[M][u]||(H[M][u]= +E(a(d(M*G,2)+d(u*K,2))/1E3)),u=H[M][u],0<u&&(v=4*(N*e+l),w+=u,x+=u*D[v],A+=u*D[v+1],y+=u*D[v+2],J+=u*D[v+3]))}v=4*(k*h+b);z[v]=x/w;z[v+1]=A/w;z[v+2]=y/w;z[v+3]=J/w}return++b<h?r(b):C}b=b.getContext("2d");var u=b.getImageData(0,0,e,f),C=b.getImageData(0,0,h,m),D=u.data,z=C.data,E=function(a){return function(b){if(b>a)return 0;b*=Math.PI;if(1E-16>g(b))return 1;var c=b/a;return l(b)*l(c)/b/c}}(this.lanczosLobes),B=this.rcpScaleX,F=this.rcpScaleY,G=2/this.rcpScaleX,K=2/this.rcpScaleY,L=k(B*this.lanczosLobes/ +2),O=k(F*this.lanczosLobes/2),H={};p=n=t=q=void 0;return r(0)},bilinearFiltering:function(a,b,d,e,f){var g,h,k,l,m,n,p,q,t,r,B=0,F=this.rcpScaleX,G=this.rcpScaleY;p=a.getContext("2d");a=4*(b-1);d=p.getImageData(0,0,b,d).data;var K=p.getImageData(0,0,e,f),L=K.data;for(p=0;p<f;p++)for(q=0;q<e;q++)for(m=c(F*q),n=c(G*p),t=F*q-m,r=G*p-n,n=4*(n*b+m),m=0;4>m;m++)g=d[n+m],h=d[n+4+m],k=d[n+a+m],l=d[n+a+4+m],g=g*(1-t)*(1-r)+h*t*(1-r)+k*r*(1-t)+l*t*r,L[B++]=g;return K},hermiteFastResize:function(b,d,e,f,h){var l= +this.rcpScaleX,m=this.rcpScaleY,n=k(l/2),p=k(m/2);b=b.getContext("2d");e=b.getImageData(0,0,d,e).data;b=b.getImageData(0,0,f,h);for(var q=b.data,t=0;t<h;t++)for(var r=0;r<f;r++){for(var D=4*(r+t*f),z,E=0,B=0,F=0,G=0,K=0,L=0,O=(t+.5)*m,H=c(t*m);H<(t+1)*m;H++)for(var J=g(O-(H+.5))/p,Q=(r+.5)*l,J=J*J,P=c(r*l);P<(r+1)*l;P++){var I=g(Q-(P+.5))/n;z=a(J+I*I);1<z&&-1>z||(z=2*z*z*z-3*z*z+1,0<z&&(I=4*(P+H*d),L+=z*e[I+3],B+=z,255>e[I+3]&&(z=z*e[I+3]/250),F+=z*e[I],G+=z*e[I+1],K+=z*e[I+2],E+=z))}q[D]=F/E;q[D+ +1]=G/E;q[D+2]=K/E;q[D+3]=L/B}return b},toObject:function(){return{type:this.type,scaleX:this.scaleX,scaleY:this.scaleY,resizeType:this.resizeType,lanczosLobes:this.lanczosLobes}}});b.Image.filters.Resize.fromObject=b.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.ColorMatrix=c(d.BaseFilter,{type:"ColorMatrix",initialize:function(a){a||(a={});this.matrix=a.matrix||[1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0]},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);var c=a.data,d=c.length,e,k,m,n,p,q=this.matrix;for(e=0;e<d;e+=4)k=c[e],m=c[e+1],n=c[e+2],p=c[e+3],c[e]=k*q[0]+m*q[1]+n*q[2]+p*q[3]+q[4],c[e+1]=k*q[5]+m*q[6]+n*q[7]+ +p*q[8]+q[9],c[e+2]=k*q[10]+m*q[11]+n*q[12]+p*q[13]+q[14],c[e+3]=k*q[15]+m*q[16]+n*q[17]+p*q[18]+q[19];b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"),{type:this.type,matrix:this.matrix})}});e.Image.filters.ColorMatrix.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Contrast=c(d.BaseFilter,{type:"Contrast",initialize:function(a){a=a||{};this.contrast=a.contrast||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d=259*(this.contrast+255)/(255*(259-this.contrast)),e=0,k=c.length;e<k;e+=4)c[e]=d*(c[e]-128)+128,c[e+1]=d*(c[e+1]-128)+128,c[e+2]=d*(c[e+2]-128)+128;b.putImageData(a,0,0)},toObject:function(){return b(this.callSuper("toObject"), +{contrast:this.contrast})}});e.Image.filters.Contrast.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){e=e.fabric||(e.fabric={});var b=e.util.object.extend,d=e.Image.filters,c=e.util.createClass;d.Saturate=c(d.BaseFilter,{type:"Saturate",initialize:function(a){a=a||{};this.saturate=a.saturate||0},applyTo:function(a){var b=a.getContext("2d");a=b.getImageData(0,0,a.width,a.height);for(var c=a.data,d,e=.01*-this.saturate,k=0,m=c.length;k<m;k+=4)d=Math.max(c[k],c[k+1],c[k+2]),c[k]+=d!==c[k]?(d-c[k])*e:0,c[k+1]+=d!==c[k+1]?(d-c[k+1])*e:0,c[k+2]+=d!==c[k+2]?(d-c[k+2])*e:0;b.putImageData(a,0, +0)},toObject:function(){return b(this.callSuper("toObject"),{saturate:this.saturate})}});e.Image.filters.Saturate.fromObject=e.Image.filters.BaseFilter.fromObject})("undefined"!==typeof exports?exports:this); +(function(e){var b=e.fabric||(e.fabric={}),d=b.util.toFixed,c=b.Object.NUM_FRACTION_DIGITS;b.Text?b.warn("fabric.Text is already defined"):(b.Text=b.util.createClass(b.Object,{_dimensionAffectingProps:"fontSize fontWeight fontFamily fontStyle lineHeight text charSpacing textAlign".split(" "),_reNewline:/\r?\n/,_reSpacesAndTabs:/[ \t\r]+/g,type:"text",fontSize:40,fontWeight:"normal",fontFamily:"Times New Roman",textDecoration:"",textAlign:"left",fontStyle:"",lineHeight:1.16,textBackgroundColor:"", +stateProperties:b.Object.prototype.stateProperties.concat("fontFamily","fontWeight","fontSize","text","textDecoration","textAlign","fontStyle","lineHeight","textBackgroundColor","charSpacing"),cacheProperties:b.Object.prototype.cacheProperties.concat("fontFamily","fontWeight","fontSize","text","textDecoration","textAlign","fontStyle","lineHeight","textBackgroundColor","charSpacing","styles"),stroke:null,shadow:null,_fontSizeFraction:.25,_fontSizeMult:1.13,charSpacing:0,initialize:function(a,b){b= +b||{};this.text=a;this.__skipDimension=!0;this.callSuper("initialize",b);this.__skipDimension=!1;this._initDimensions();this.setCoords();this.setupState({propertySet:"_dimensionAffectingProps"})},_initDimensions:function(a){this.__skipDimension||(a||(a=b.util.createCanvasElement().getContext("2d"),this._setTextStyles(a)),this._textLines=this._splitTextIntoLines(),this._clearCache(),this.width=this._getTextWidth(a)||this.cursorWidth||2,this.height=this._getTextHeight(a),this.setCoords())},toString:function(){return"#<fabric.Text ("+ +this.complexity()+'): { "text": "'+this.text+'", "fontFamily": "'+this.fontFamily+'" }>'},_getCacheCanvasDimensions:function(){var a=this.callSuper("_getCacheCanvasDimensions"),b=this.fontSize;a.width+=b*a.zoomX;a.height+=b*a.zoomY;return a},_render:function(a){this._setTextStyles(a);this.group&&"path-group"===this.group.type&&a.translate(this.left,this.top);this._renderTextLinesBackground(a);this._renderText(a);this._renderTextDecoration(a)},_renderText:function(a){this._renderTextFill(a);this._renderTextStroke(a)}, +_setTextStyles:function(a){a.textBaseline="alphabetic";a.font=this._getFontDeclaration()},_getTextHeight:function(){return this._getHeightOfSingleLine()+(this._textLines.length-1)*this._getHeightOfLine()},_getTextWidth:function(a){for(var b=this._getLineWidth(a,0),c=1,d=this._textLines.length;c<d;c++){var e=this._getLineWidth(a,c);e>b&&(b=e)}return b},_renderChars:function(a,b,c,d,e){var f=a.slice(0,-4),g,h;this[f].toLive&&(g=-this.width/2+this[f].offsetX||0,h=-this.height/2+this[f].offsetY||0,b.save(), +b.translate(g,h),d-=g,e-=h);if(0!==this.charSpacing){var l=this._getWidthOfCharSpacing();c=c.split("");for(var q=0,t=c.length;q<t;q++)g=c[q],h=b.measureText(g).width+l,b[a](g,d,e),d+=0<h?h:0}else b[a](c,d,e);this[f].toLive&&b.restore()},_renderTextLine:function(a,b,c,d,e,k){e-=this.fontSize*this._fontSizeFraction;var f=this._getLineWidth(b,k);if("justify"!==this.textAlign||this.width<f)this._renderChars(a,b,c,d,e,k);else for(var f=c.split(/\s+/),g=0,h=this._getWidthOfWords(b,f.join(" "),k,0),h=this.width- +h,l=f.length-1,h=0<l?h/l:0,l=0,t,r=0,v=f.length;r<v;r++){for(;" "===c[g]&&g<c.length;)g++;t=f[r];this._renderChars(a,b,t,d+l,e,k,g);l+=this._getWidthOfWords(b,t,k,g)+h;g+=t.length}},_getWidthOfWords:function(a,b){var c=a.measureText(b).width,d;0!==this.charSpacing&&(d=b.split("").length,d*=this._getWidthOfCharSpacing(),c+=d);return 0<c?c:0},_getLeftOffset:function(){return-this.width/2},_getTopOffset:function(){return-this.height/2},isEmptyStyles:function(){return!0},_renderTextCommon:function(a, +b){for(var c=0,d=this._getLeftOffset(),e=this._getTopOffset(),g=0,m=this._textLines.length;g<m;g++){var n=this._getHeightOfLine(a,g),p=n/this.lineHeight,q=this._getLineWidth(a,g),q=this._getLineLeftOffset(q);this._renderTextLine(b,a,this._textLines[g],d+q,e+c+p,g);c+=n}},_renderTextFill:function(a){!this.fill&&this.isEmptyStyles()||this._renderTextCommon(a,"fillText")},_renderTextStroke:function(a){if(this.stroke&&0!==this.strokeWidth||!this.isEmptyStyles())this.shadow&&!this.shadow.affectStroke&& +this._removeShadow(a),a.save(),this._setLineDash(a,this.strokeDashArray),a.beginPath(),this._renderTextCommon(a,"strokeText"),a.closePath(),a.restore()},_getHeightOfLine:function(){return this._getHeightOfSingleLine()*this.lineHeight},_getHeightOfSingleLine:function(){return this.fontSize*this._fontSizeMult},_renderTextLinesBackground:function(a){if(this.textBackgroundColor){var b=0,c,d,e,k=a.fillStyle;a.fillStyle=this.textBackgroundColor;for(var m=0,n=this._textLines.length;m<n;m++)c=this._getHeightOfLine(a, +m),d=this._getLineWidth(a,m),0<d&&(e=this._getLineLeftOffset(d),a.fillRect(this._getLeftOffset()+e,this._getTopOffset()+b,d,c/this.lineHeight)),b+=c;a.fillStyle=k;this._removeShadow(a)}},_getLineLeftOffset:function(a){return"center"===this.textAlign?(this.width-a)/2:"right"===this.textAlign?this.width-a:0},_clearCache:function(){this.__lineWidths=[];this.__lineHeights=[]},_shouldClearDimensionCache:function(){var a=this._forceClearCache;a||(a=this.hasStateChanged("_dimensionAffectingProps"));a&&(this.saveState({propertySet:"_dimensionAffectingProps"}), +this.dirty=!0);return a},_getLineWidth:function(a,b){if(this.__lineWidths[b])return-1===this.__lineWidths[b]?this.width:this.__lineWidths[b];var c,d;d=this._textLines[b];c=""===d?0:this._measureLine(a,b);(this.__lineWidths[b]=c)&&"justify"===this.textAlign&&(d=d.split(/\s+/),1<d.length&&(this.__lineWidths[b]=-1));return c},_getWidthOfCharSpacing:function(){return 0!==this.charSpacing?this.fontSize*this.charSpacing/1E3:0},_measureLine:function(a,b){var c=this._textLines[b],d=a.measureText(c).width, +e=0;0!==this.charSpacing&&(c=c.split("").length,e=(c-1)*this._getWidthOfCharSpacing());d+=e;return 0<d?d:0},_renderTextDecoration:function(a){if(this.textDecoration){var b=this.height/2,c=[];-1<this.textDecoration.indexOf("underline")&&c.push(.85);-1<this.textDecoration.indexOf("line-through")&&c.push(.43);-1<this.textDecoration.indexOf("overline")&&c.push(-.12);if(0<c.length){var d,e=0,k,m,n,p,q,t;d=0;for(k=this._textLines.length;d<k;d++){p=this._getLineWidth(a,d);q=this._getLineLeftOffset(p);t= +this._getHeightOfLine(a,d);m=0;for(n=c.length;m<n;m++)a.fillRect(this._getLeftOffset()+q,e+(this._fontSizeMult-1+c[m])*this.fontSize-b,p,this.fontSize/15);e+=t}}}},_getFontDeclaration:function(){return[b.isLikelyNode?this.fontWeight:this.fontStyle,b.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+"px",b.isLikelyNode?'"'+this.fontFamily+'"':this.fontFamily].join(" ")},render:function(a,b){!this.visible||this.canvas&&this.canvas.skipOffscreen&&!this.group&&!this.isOnScreen()||(this._shouldClearDimensionCache()&& +(this._setTextStyles(a),this._initDimensions(a)),this.callSuper("render",a,b))},_splitTextIntoLines:function(){return this.text.split(this._reNewline)},toObject:function(a){a="text fontSize fontWeight fontFamily fontStyle lineHeight textDecoration textAlign textBackgroundColor charSpacing".split(" ").concat(a);return this.callSuper("toObject",a)},toSVG:function(a){this.ctx||(this.ctx=b.util.createCanvasElement().getContext("2d"));var c=this._createBaseSVGMarkup(),d=this._getSVGLeftTopOffsets(this.ctx), +d=this._getSVGTextAndBg(d.textTop,d.textLeft);this._wrapSVGTextAndBg(c,d);return a?a(c.join("")):c.join("")},_getSVGLeftTopOffsets:function(a){a=this._getHeightOfLine(a,0);return{textLeft:-this.width/2+(this.group&&"path-group"===this.group.type?this.left:0),textTop:0+(this.group&&"path-group"===this.group.type?-this.top:0),lineTop:a}},_wrapSVGTextAndBg:function(a,b){var c=this.getSvgFilter(),c=""===c?"":' style="'+c+'"';a.push("\t<g ",this.getSvgId(),'transform="',this.getSvgTransform(),this.getSvgTransformMatrix(), +'"',c,">\n",b.textBgRects.join(""),'\t\t<text xml:space="preserve" ',this.fontFamily?'font-family="'+this.fontFamily.replace(/"/g,"'")+'" ':"",this.fontSize?'font-size="'+this.fontSize+'" ':"",this.fontStyle?'font-style="'+this.fontStyle+'" ':"",this.fontWeight?'font-weight="'+this.fontWeight+'" ':"",this.textDecoration?'text-decoration="'+this.textDecoration+'" ':"",'style="',this.getSvgStyles(!0),'" >\n',b.textSpans.join(""),"\t\t</text>\n","\t</g>\n")},getSvgStyles:function(a){return b.Object.prototype.getSvgStyles.call(this, +a)+" white-space: pre;"},_getSVGTextAndBg:function(a,b){var c=[],d=[],e=0;this._setSVGBg(d);for(var g=0,m=this._textLines.length;g<m;g++)this.textBackgroundColor&&this._setSVGTextLineBg(d,g,b,a,e),this._setSVGTextLineText(g,c,e,b,a,d),e+=this._getHeightOfLine(this.ctx,g);return{textSpans:c,textBgRects:d}},_setSVGTextLineText:function(a,e,h,f,l){h=this.fontSize*(this._fontSizeMult-this._fontSizeFraction)-l+h-this.height/2;"justify"===this.textAlign?this._setSVGTextLineJustifed(a,e,h,f):e.push('\t\t\t<tspan x="', +d(f+this._getLineLeftOffset(this._getLineWidth(this.ctx,a)),c),'" ','y="',d(h,c),'" ',this._getFillAttributes(this.fill),">",b.util.string.escapeXml(this._textLines[a]),"</tspan>\n")},_setSVGTextLineJustifed:function(a,e,h,f){var g=b.util.createCanvasElement().getContext("2d");this._setTextStyles(g);var k=this._textLines[a].split(/\s+/),m=this._getWidthOfWords(g,k.join("")),m=this.width-m,n=k.length-1,m=0<n?m/n:0,p=this._getFillAttributes(this.fill),q;f+=this._getLineLeftOffset(this._getLineWidth(g, +a));a=0;for(q=k.length;a<q;a++)n=k[a],e.push('\t\t\t<tspan x="',d(f,c),'" ','y="',d(h,c),'" ',p,">",b.util.string.escapeXml(n),"</tspan>\n"),f+=this._getWidthOfWords(g,n)+m},_setSVGTextLineBg:function(a,b,e,f,l){a.push("\t\t<rect ",this._getFillAttributes(this.textBackgroundColor),' x="',d(e+this._getLineLeftOffset(this._getLineWidth(this.ctx,b)),c),'" y="',d(l-this.height/2,c),'" width="',d(this._getLineWidth(this.ctx,b),c),'" height="',d(this._getHeightOfLine(this.ctx,b)/this.lineHeight,c),'"></rect>\n')}, +_setSVGBg:function(a){this.backgroundColor&&a.push("\t\t<rect ",this._getFillAttributes(this.backgroundColor),' x="',d(-this.width/2,c),'" y="',d(-this.height/2,c),'" width="',d(this.width,c),'" height="',d(this.height,c),'"></rect>\n')},_getFillAttributes:function(a){var c=a&&"string"===typeof a?new b.Color(a):"";return c&&c.getSource()&&1!==c.getAlpha()?'opacity="'+c.getAlpha()+'" fill="'+c.setAlpha(1).toRgb()+'"':'fill="'+a+'"'},_set:function(a,b){this.callSuper("_set",a,b);-1<this._dimensionAffectingProps.indexOf(a)&& +(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),b.Text.ATTRIBUTE_NAMES=b.SHARED_ATTRIBUTES.concat("x y dx dy font-family font-style font-weight font-size text-decoration text-anchor".split(" ")),b.Text.DEFAULT_SVG_FONT_SIZE=16,b.Text.fromElement=function(a,c){if(!a)return null;var d=b.parseAttributes(a,b.Text.ATTRIBUTE_NAMES);c=b.util.object.extend(c?b.util.object.clone(c):{},d);c.top=c.top||0;c.left=c.left||0;"dx"in d&&(c.left+=d.dx);"dy"in d&&(c.top+=d.dy);"fontSize"in +c||(c.fontSize=b.Text.DEFAULT_SVG_FONT_SIZE);c.originX||(c.originX="left");d="";"textContent"in a?d=a.textContent:"firstChild"in a&&null!==a.firstChild&&"data"in a.firstChild&&null!==a.firstChild.data&&(d=a.firstChild.data);var d=d.replace(/^\s+|\s+$|\n+/g,"").replace(/\s+/g," "),d=new b.Text(d,c),e=d.getHeight()/d.height,e=((d.height+d.strokeWidth)*d.lineHeight-d.height)*e,e=d.getHeight()+e,g=0;"left"===d.originX&&(g=d.getWidth()/2);"right"===d.originX&&(g=-d.getWidth()/2);d.set({left:d.getLeft()+ +g,top:d.getTop()-e/2+d.fontSize*(.18+d._fontSizeFraction)/d.lineHeight});return d},b.Text.fromObject=function(a,c,d){return b.Object._fromObject("Text",a,c,d,"text")},b.util.createAccessors(b.Text))})("undefined"!==typeof exports?exports:this); +(function(){var e=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(b,d){this.styles= +d?d.styles||{}:{};this.callSuper("initialize",b,d);this.initBehavior()},_clearCache:function(){this.callSuper("_clearCache");this.__widthOfSpace=[]},isEmptyStyles:function(){if(!this.styles)return!0;var b=this.styles,d;for(d in b)for(var c in b[d])for(var a in b[d][c])return!1;return!0},setSelectionStart:function(b){b=Math.max(b,0);this._updateAndFire("selectionStart",b)},setSelectionEnd:function(b){b=Math.min(b,this.text.length);this._updateAndFire("selectionEnd",b)},_updateAndFire:function(b,d){this[b]!== +d&&(this._fireSelectionChanged(),this[b]=d);this._updateTextarea()},_fireSelectionChanged:function(){this.fire("selection:changed");this.canvas&&this.canvas.fire("text:selection:changed",{target:this})},getSelectionStyles:function(b,d){if(2===arguments.length){for(var c=[],a=b;a<d;a++)c.push(this.getSelectionStyles(a));return c}c=this.get2DCursorLocation(b);return this._getStyleDeclaration(c.lineIndex,c.charIndex)||{}},setSelectionStyles:function(b){if(this.selectionStart===this.selectionEnd)this._extendStyles(this.selectionStart, +b);else for(var d=this.selectionStart;d<this.selectionEnd;d++)this._extendStyles(d,b);this._forceClearCache=!0;return this},_extendStyles:function(b,d){var c=this.get2DCursorLocation(b);this._getLineStyle(c.lineIndex)||this._setLineStyle(c.lineIndex,{});this._getStyleDeclaration(c.lineIndex,c.charIndex)||this._setStyleDeclaration(c.lineIndex,c.charIndex,{});fabric.util.object.extend(this._getStyleDeclaration(c.lineIndex,c.charIndex),d)},_initDimensions:function(b){b||this.clearContextTop();this.callSuper("_initDimensions", +b)},render:function(b,d){this.clearContextTop();this.callSuper("render",b,d);this.cursorOffsetCache={};this.renderCursorOrSelection()},_render:function(b){this.callSuper("_render",b);this.ctx=b},clearContextTop:function(){if(this.active&&this.isEditing&&this.canvas&&this.canvas.contextTop){var b=this.canvas.contextTop;b.save();b.transform.apply(b,this.canvas.viewportTransform);this.transform(b);this.transformMatrix&&b.transform.apply(b,this.transformMatrix);this._clearTextArea(b);b.restore()}},renderCursorOrSelection:function(){if(this.active&& +this.isEditing){var b=this.text.split(""),d,c;this.canvas&&this.canvas.contextTop?(c=this.canvas.contextTop,c.save(),c.transform.apply(c,this.canvas.viewportTransform),this.transform(c),this.transformMatrix&&c.transform.apply(c,this.transformMatrix),this._clearTextArea(c)):(c=this.ctx,c.save());this.selectionStart===this.selectionEnd?(d=this._getCursorBoundaries(b,"cursor"),this.renderCursor(d,c)):(d=this._getCursorBoundaries(b,"selection"),this.renderSelection(b,d,c));c.restore()}},_clearTextArea:function(b){var d= +this.width+4,c=this.height+4;b.clearRect(-d/2,-c/2,d,c)},get2DCursorLocation:function(b){"undefined"===typeof b&&(b=this.selectionStart);for(var d=this._textLines.length,c=0;c<d;c++){if(b<=this._textLines[c].length)return{lineIndex:c,charIndex:b};b-=this._textLines[c].length+1}return{lineIndex:c-1,charIndex:this._textLines[c-1].length<b?this._textLines[c-1].length:b}},getCurrentCharStyle:function(b,d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return{fontSize:c&&c.fontSize||this.fontSize,fill:c&& +c.fill||this.fill,textBackgroundColor:c&&c.textBackgroundColor||this.textBackgroundColor,textDecoration:c&&c.textDecoration||this.textDecoration,fontFamily:c&&c.fontFamily||this.fontFamily,fontWeight:c&&c.fontWeight||this.fontWeight,fontStyle:c&&c.fontStyle||this.fontStyle,stroke:c&&c.stroke||this.stroke,strokeWidth:c&&c.strokeWidth||this.strokeWidth}},getCurrentCharFontSize:function(b,d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return c&&c.fontSize?c.fontSize:this.fontSize},getCurrentCharColor:function(b, +d){var c=this._getStyleDeclaration(b,0===d?0:d-1);return c&&c.fill?c.fill:this.cursorColor},_getCursorBoundaries:function(b,d){var c=Math.round(this._getLeftOffset()),a=this._getTopOffset(),e=this._getCursorBoundariesOffsets(b,d);return{left:c,top:a,leftOffset:e.left+e.lineLeft,topOffset:e.top}},_getCursorBoundariesOffsets:function(b,d){if(this.cursorOffsetCache&&"top"in this.cursorOffsetCache)return this.cursorOffsetCache;for(var c=0,a=0,e=0,h=0,f=0,l=0;l<this.selectionStart;l++)"\n"===b[l]?(f=0, +h+=this._getHeightOfLine(this.ctx,a),a++,e=0):(f+=this._getWidthOfChar(this.ctx,b[l],a,e),e++),c=this._getLineLeftOffset(this._getLineWidth(this.ctx,a));"cursor"===d&&(h+=(1-this._fontSizeFraction)*this._getHeightOfLine(this.ctx,a)/this.lineHeight-this.getCurrentCharFontSize(a,e)*(1-this._fontSizeFraction));0!==this.charSpacing&&e===this._textLines[a].length&&(f-=this._getWidthOfCharSpacing());return this.cursorOffsetCache={top:h,left:0<f?f:0,lineLeft:c}},renderCursor:function(b,d){var c=this.get2DCursorLocation(), +a=c.lineIndex,c=c.charIndex,e=this.getCurrentCharFontSize(a,c),h=b.leftOffset,f=this.scaleX*this.canvas.getZoom(),f=this.cursorWidth/f;d.fillStyle=this.getCurrentCharColor(a,c);d.globalAlpha=this.__isMousedown?1:this._currentCursorOpacity;d.fillRect(b.left+h-f/2,b.top+b.topOffset,f,e)},renderSelection:function(b,d,c){c.fillStyle=this.selectionColor;b=this.get2DCursorLocation(this.selectionStart);for(var a=this.get2DCursorLocation(this.selectionEnd),e=b.lineIndex,h=a.lineIndex,f=e;f<=h;f++){var l= +this._getLineLeftOffset(this._getLineWidth(c,f))||0,k=this._getHeightOfLine(this.ctx,f),m,n=0;m=this._textLines[f];if(f===e){for(var p=0,q=m.length;p<q;p++)p>=b.charIndex&&(f!==h||p<a.charIndex)&&(n+=this._getWidthOfChar(c,m[p],f,p)),p<b.charIndex&&(l+=this._getWidthOfChar(c,m[p],f,p));p===m.length&&(n-=this._getWidthOfCharSpacing())}else if(f>e&&f<h)n+=this._getLineWidth(c,f)||5;else if(f===h){p=0;for(q=a.charIndex;p<q;p++)n+=this._getWidthOfChar(c,m[p],f,p);a.charIndex===m.length&&(n-=this._getWidthOfCharSpacing())}m= +k;if(1>this.lineHeight||f===h&&1<this.lineHeight)k/=this.lineHeight;c.fillRect(d.left+l,d.top+d.topOffset,0<n?n:0,k);d.topOffset+=m}},_renderChars:function(b,d,c,a,e,h,f){if(this.isEmptyStyles())return this._renderCharsFast(b,d,c,a,e);f=f||0;var g=this._getHeightOfLine(d,h),k,m,n="";d.save();e-=g/this.lineHeight*this._fontSizeFraction;for(var p=f,q=c.length+f;p<=q;p++){k=k||this.getCurrentCharStyle(h,p);m=this.getCurrentCharStyle(h,p+1);if(this._hasStyleChanged(k,m)||p===q)this._renderChar(b,d,h, +p-1,n,a,e,g),n="",k=m;n+=c[p-f]}d.restore()},_renderCharsFast:function(b,d,c,a,e){"fillText"===b&&this.fill&&this.callSuper("_renderChars",b,d,c,a,e);"strokeText"===b&&(this.stroke&&0<this.strokeWidth||this.skipFillStrokeCheck)&&this.callSuper("_renderChars",b,d,c,a,e)},_renderChar:function(b,d,c,a,e,h,f,l){var g,m,n,p=this._getStyleDeclaration(c,a),q,t;p?(g=this._getHeightOfChar(d,e,c,a),n=p.stroke,m=p.fill,q=p.textDecoration):g=this.fontSize;n=(n||this.stroke)&&"strokeText"===b;m=(m||this.fill)&& +"fillText"===b;p&&d.save();b=this._applyCharStylesGetWidth(d,e,c,a,p||null);q=q||this.textDecoration;p&&p.textBackgroundColor&&this._removeShadow(d);if(0!==this.charSpacing){c=this._getWidthOfCharSpacing();e=e.split("");a=b=0;for(var r=e.length;a<r;a++)t=e[a],m&&d.fillText(t,h+b,f),n&&d.strokeText(t,h+b,f),t=d.measureText(t).width+c,b+=0<t?t:0}else m&&d.fillText(e,h,f),n&&d.strokeText(e,h,f);if(q||""!==q)l=this._fontSizeFraction*l/this.lineHeight,this._renderCharDecoration(d,q,h,f,l,b,g);p&&d.restore(); +d.translate(b,0)},_hasStyleChanged:function(b,d){return b.fill!==d.fill||b.fontSize!==d.fontSize||b.textBackgroundColor!==d.textBackgroundColor||b.textDecoration!==d.textDecoration||b.fontFamily!==d.fontFamily||b.fontWeight!==d.fontWeight||b.fontStyle!==d.fontStyle||b.stroke!==d.stroke||b.strokeWidth!==d.strokeWidth},_renderCharDecoration:function(b,d,c,a,e,h,f){if(d){e=f/15;a={underline:a+f/10,"line-through":a-f*(this._fontSizeFraction+this._fontSizeMult-1)+e,overline:a-(this._fontSizeMult-this._fontSizeFraction)* +f};f=["underline","line-through","overline"];var g,k;for(g=0;g<f.length;g++)k=f[g],-1<d.indexOf(k)&&b.fillRect(c,a[k],h,e)}},_renderTextLine:function(b,d,c,a,e,h){this.isEmptyStyles()||(e+=this.fontSize*(this._fontSizeFraction+.03));this.callSuper("_renderTextLine",b,d,c,a,e,h)},_renderTextDecoration:function(b){if(this.isEmptyStyles())return this.callSuper("_renderTextDecoration",b)},_renderTextLinesBackground:function(b){this.callSuper("_renderTextLinesBackground",b);var d=0,c,a,e=this._getLeftOffset(), +h=this._getTopOffset(),f="",l,k,m,n,p,q,t;b.save();for(var r=0,v=this._textLines.length;r<v;r++){c=this._getHeightOfLine(b,r);l=this._textLines[r];if(""!==l&&this.styles&&this._getLineStyle(r)){a=this._getLineWidth(b,r);a=this._getLineLeftOffset(a);for(var A=n=p=q=t=0,w=l.length;A<w;A++)m=this._getStyleDeclaration(r,A)||{},f!==m.textBackgroundColor&&(t&&q&&(b.fillStyle=f,b.fillRect(n,p,q,t)),n=p=q=t=0,f=m.textBackgroundColor||""),m.textBackgroundColor?(k=l[A],f===m.textBackgroundColor&&(f=m.textBackgroundColor, +n||(n=e+a+this._getWidthOfCharsAt(b,r,A)),p=h+d,q+=this._getWidthOfChar(b,k,r,A),t=c/this.lineHeight)):f="";t&&q&&(b.fillStyle=f,b.fillRect(n,p,q,t))}d+=c}b.restore()},_getCacheProp:function(b,d){return b+d.fontSize+d.fontWeight+d.fontStyle},_getFontCache:function(b){fabric.charWidthsCache[b]||(fabric.charWidthsCache[b]={});return fabric.charWidthsCache[b]},_applyCharStylesGetWidth:function(b,d,c,a,g){var h=g||this._getStyleDeclaration(c,a);g=e(h);this._applyFontStyles(g);a=this._getFontCache(g.fontFamily); +c=this._getCacheProp(d,g);if(!h&&a[c]&&this.caching)return a[c];"string"===typeof g.shadow&&(g.shadow=new fabric.Shadow(g.shadow));h=g.fill||this.fill;b.fillStyle=h.toLive?h.toLive(b,this):h;g.stroke&&(b.strokeStyle=g.stroke&&g.stroke.toLive?g.stroke.toLive(b,this):g.stroke);b.lineWidth=g.strokeWidth||this.strokeWidth;b.font=this._getFontDeclaration.call(g);g.shadow&&(g.scaleX=this.scaleX,g.scaleY=this.scaleY,g.canvas=this.canvas,g.getObjectScaling=this.getObjectScaling,this._setShadow.call(g,b)); +return this.caching&&a[c]?a[c]:(b=b.measureText(d).width,this.caching&&(a[c]=b),b)},_applyFontStyles:function(b){b.fontFamily||(b.fontFamily=this.fontFamily);b.fontSize||(b.fontSize=this.fontSize);b.fontWeight||(b.fontWeight=this.fontWeight);b.fontStyle||(b.fontStyle=this.fontStyle)},_getStyleDeclaration:function(b,d,c){return c?this.styles[b]&&this.styles[b][d]?e(this.styles[b][d]):{}:this.styles[b]&&this.styles[b][d]?this.styles[b][d]:null},_setStyleDeclaration:function(b,d,c){this.styles[b][d]= +c},_deleteStyleDeclaration:function(b,d){delete this.styles[b][d]},_getLineStyle:function(b){return this.styles[b]},_setLineStyle:function(b,d){this.styles[b]=d},_deleteLineStyle:function(b){delete this.styles[b]},_getWidthOfChar:function(b,d,c,a){if(!this._isMeasuring&&"justify"===this.textAlign&&this._reSpacesAndTabs.test(d))return this._getWidthOfSpace(b,c);b.save();d=this._applyCharStylesGetWidth(b,d,c,a);0!==this.charSpacing&&(d+=this._getWidthOfCharSpacing());b.restore();return 0<d?d:0},_getHeightOfChar:function(b, +d,c){return(b=this._getStyleDeclaration(d,c))&&b.fontSize?b.fontSize:this.fontSize},_getWidthOfCharsAt:function(b,d,c){var a=0,e,h;for(e=0;e<c;e++)h=this._textLines[d][e],a+=this._getWidthOfChar(b,h,d,e);return a},_measureLine:function(b,d){this._isMeasuring=!0;var c=this._getWidthOfCharsAt(b,d,this._textLines[d].length);0!==this.charSpacing&&(c-=this._getWidthOfCharSpacing());this._isMeasuring=!1;return 0<c?c:0},_getWidthOfSpace:function(b,d){if(this.__widthOfSpace[d])return this.__widthOfSpace[d]; +var c=this._textLines[d],a=this._getWidthOfWords(b,c,d,0),a=this.width-a,c=c.length-c.replace(this._reSpacesAndTabs,"").length,c=Math.max(a/c,b.measureText(" ").width);return this.__widthOfSpace[d]=c},_getWidthOfWords:function(b,d,c,a){for(var e=0,h=0;h<d.length;h++){var f=d[h];f.match(/\s/)||(e+=this._getWidthOfChar(b,f,c,h+a))}return e},_getHeightOfLine:function(b,d){if(this.__lineHeights[d])return this.__lineHeights[d];for(var c=this._textLines[d],a=this._getHeightOfChar(b,d,0),e=1,c=c.length;e< +c;e++){var h=this._getHeightOfChar(b,d,e);h>a&&(a=h)}this.__lineHeights[d]=a*this.lineHeight*this._fontSizeMult;return this.__lineHeights[d]},_getTextHeight:function(b){for(var d,c=0,a=0,e=this._textLines.length;a<e;a++)d=this._getHeightOfLine(b,a),c+=a===e-1?d/this.lineHeight:d;return c},toObject:function(b){return fabric.util.object.extend(this.callSuper("toObject",b),{styles:e(this.styles,!0)})}});fabric.IText.fromObject=function(b,d,c){return fabric.Object._fromObject("IText",b,d,c,"text")}})(); +(function(){var e=fabric.util.object.clone;fabric.util.object.extend(fabric.IText.prototype,{initBehavior:function(){this.initAddedHandler();this.initRemovedHandler();this.initCursorSelectionHandlers();this.initDoubleClickSimulation();this.mouseMoveHandler=this.mouseMoveHandler.bind(this)},onDeselect:function(){this.isEditing&&this.exitEditing();this.selected=!1;this.callSuper("onDeselect")},initAddedHandler:function(){var b=this;this.on("added",function(){var d=b.canvas;d&&(d._hasITextHandlers|| +(d._hasITextHandlers=!0,b._initCanvasHandlers(d)),d._iTextInstances=d._iTextInstances||[],d._iTextInstances.push(b))})},initRemovedHandler:function(){var b=this;this.on("removed",function(){var d=b.canvas;d&&(d._iTextInstances=d._iTextInstances||[],fabric.util.removeFromArray(d._iTextInstances,b),0===d._iTextInstances.length&&(d._hasITextHandlers=!1,b._removeCanvasHandlers(d)))})},_initCanvasHandlers:function(b){b._mouseUpITextHandler=function(){b._iTextInstances&&b._iTextInstances.forEach(function(b){b.__isMousedown= +!1})}.bind(this);b.on("mouse:up",b._mouseUpITextHandler)},_removeCanvasHandlers:function(b){b.off("mouse:up",b._mouseUpITextHandler)},_tick:function(){this._currentTickState=this._animateCursor(this,1,this.cursorDuration,"_onTickComplete")},_animateCursor:function(b,d,c,a){var e;e={isAborted:!1,abort:function(){this.isAborted=!0}};b.animate("_currentCursorOpacity",d,{duration:c,onComplete:function(){if(!e.isAborted)b[a]()},onChange:function(){b.canvas&&b.selectionStart===b.selectionEnd&&b.renderCursorOrSelection()}, +abort:function(){return e.isAborted}});return e},_onTickComplete:function(){var b=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1);this._cursorTimeout1=setTimeout(function(){b._currentTickCompleteState=b._animateCursor(b,0,this.cursorDuration/2,"_tick")},100)},initDelayedCursor:function(b){var d=this;b=b?0:this.cursorDelay;this.abortCursorAnimation();this._currentCursorOpacity=1;this._cursorTimeout2=setTimeout(function(){d._tick()},b)},abortCursorAnimation:function(){var b=this._currentTickState|| +this._currentTickCompleteState;this._currentTickState&&this._currentTickState.abort();this._currentTickCompleteState&&this._currentTickCompleteState.abort();clearTimeout(this._cursorTimeout1);clearTimeout(this._cursorTimeout2);this._currentCursorOpacity=0;b&&this.canvas&&this.canvas.clearContext(this.canvas.contextTop||this.ctx)},selectAll:function(){this.selectionStart=0;this.selectionEnd=this.text.length;this._fireSelectionChanged();this._updateTextarea()},getSelectedText:function(){return this.text.slice(this.selectionStart, +this.selectionEnd)},findWordBoundaryLeft:function(b){var d=0,c=b-1;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)d++,c--;for(;/\S/.test(this.text.charAt(c))&&-1<c;)d++,c--;return b-d},findWordBoundaryRight:function(b){var d=0,c=b;if(this._reSpace.test(this.text.charAt(c)))for(;this._reSpace.test(this.text.charAt(c));)d++,c++;for(;/\S/.test(this.text.charAt(c))&&c<this.text.length;)d++,c++;return b+d},findLineBoundaryLeft:function(b){for(var d=0,c=b-1;!/\n/.test(this.text.charAt(c))&& +-1<c;)d++,c--;return b-d},findLineBoundaryRight:function(b){for(var d=0,c=b;!/\n/.test(this.text.charAt(c))&&c<this.text.length;)d++,c++;return b+d},getNumNewLinesInSelectedText:function(){for(var b=this.getSelectedText(),d=0,c=0,a=b.length;c<a;c++)"\n"===b[c]&&d++;return d},searchWordBoundary:function(b,d){for(var c=this._reSpace.test(this.text.charAt(b))?b-1:b,a=this.text.charAt(c),e=/[ \n\.,;!\?\-]/;!e.test(a)&&0<c&&c<this.text.length;)c+=d,a=this.text.charAt(c);e.test(a)&&"\n"!==a&&(c+=1===d? +0:1);return c},selectWord:function(b){b=b||this.selectionStart;var d=this.searchWordBoundary(b,-1);b=this.searchWordBoundary(b,1);this.selectionStart=d;this.selectionEnd=b;this._fireSelectionChanged();this._updateTextarea();this.renderCursorOrSelection()},selectLine:function(b){b=b||this.selectionStart;var d=this.findLineBoundaryLeft(b);b=this.findLineBoundaryRight(b);this.selectionStart=d;this.selectionEnd=b;this._fireSelectionChanged();this._updateTextarea()},enterEditing:function(b){if(!this.isEditing&& +this.editable){this.canvas&&this.exitEditingOnOthers(this.canvas);this.selected=this.isEditing=!0;this.initHiddenTextarea(b);this.hiddenTextarea.focus();this._updateTextarea();this._saveEditingProps();this._setEditingProps();this._textBeforeEdit=this.text;this._tick();this.fire("editing:entered");this._fireSelectionChanged();if(!this.canvas)return this;this.canvas.fire("text:editing:entered",{target:this});this.initMouseMoveHandler();this.canvas.renderAll();return this}},exitEditingOnOthers:function(b){b._iTextInstances&& +b._iTextInstances.forEach(function(b){b.selected=!1;b.isEditing&&b.exitEditing()})},initMouseMoveHandler:function(){this.canvas.on("mouse:move",this.mouseMoveHandler)},mouseMoveHandler:function(b){if(this.__isMousedown&&this.isEditing){b=this.getSelectionStartFromPointer(b.e);var d=this.selectionStart,c=this.selectionEnd;if(b===this.__selectionStartOnMouseDown&&d!==c||d!==b&&c!==b)if(b>this.__selectionStartOnMouseDown?(this.selectionStart=this.__selectionStartOnMouseDown,this.selectionEnd=b):(this.selectionStart= +b,this.selectionEnd=this.__selectionStartOnMouseDown),this.selectionStart!==d||this.selectionEnd!==c)this.restartCursorIfNeeded(),this._fireSelectionChanged(),this._updateTextarea(),this.renderCursorOrSelection()}},_setEditingProps:function(){this.hoverCursor="text";this.canvas&&(this.canvas.defaultCursor=this.canvas.moveCursor="text");this.borderColor=this.editingBorderColor;this.hasControls=this.selectable=!1;this.lockMovementX=this.lockMovementY=!0},_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 b=this._calcTextareaPosition();this.hiddenTextarea.style.left=b.left;this.hiddenTextarea.style.top=b.top;this.hiddenTextarea.style.fontSize=b.fontSize}},_calcTextareaPosition:function(){if(!this.canvas)return{x:1,y:1};var b=this.text.split(""),d=this._getCursorBoundaries(b, +"cursor"),b=this.get2DCursorLocation(),b=this.getCurrentCharFontSize(b.lineIndex,b.charIndex),c=d.leftOffset,a=this.calcTransformMatrix(),d={x:d.left+c,y:d.top+d.topOffset+b},e=this.canvas.upperCanvasEl,c=e.width-b,e=e.height-b,d=fabric.util.transformPoint(d,a),d=fabric.util.transformPoint(d,this.canvas.viewportTransform);0>d.x&&(d.x=0);d.x>c&&(d.x=c);0>d.y&&(d.y=0);d.y>e&&(d.y=e);d.x+=this.canvas._offset.left;d.y+=this.canvas._offset.top;return{left:d.x+"px",top:d.y+"px",fontSize:b}},_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 b=this._textBeforeEdit!==this.text;this.isEditing=this.selected=!1;this.selectable=!0;this.selectionEnd=this.selectionStart;this.hiddenTextarea&&(this.hiddenTextarea.blur&&this.hiddenTextarea.blur(),this.canvas&&this.hiddenTextarea.parentNode.removeChild(this.hiddenTextarea),this.hiddenTextarea=null);this.abortCursorAnimation(); +this._restoreEditingProps();this._currentCursorOpacity=0;this.fire("editing:exited");b&&this.fire("modified");this.canvas&&(this.canvas.off("mouse:move",this.mouseMoveHandler),this.canvas.fire("text:editing:exited",{target:this}),b&&this.canvas.fire("object:modified",{target:this}));return this},_removeExtraneousStyles:function(){for(var b in this.styles)this._textLines[b]||delete this.styles[b]},_removeCharsFromTo:function(b,d){for(;d!==b;)this._removeSingleCharAndStyle(b+1),d--;this.selectionEnd= +this.selectionStart=b},_removeSingleCharAndStyle:function(b){var d="\n"===this.text[b-1];this.removeStyleObject(d,d?b:b-1);this.text=this.text.slice(0,b-1)+this.text.slice(b);this._textLines=this._splitTextIntoLines()},insertChars:function(b,d){var c;1<this.selectionEnd-this.selectionStart&&this._removeCharsFromTo(this.selectionStart,this.selectionEnd);if(!d&&this.isEmptyStyles())this.insertChar(b,!1);else for(var a=0,e=b.length;a<e;a++)d&&(c=fabric.util.object.clone(fabric.copiedTextStyle[a],!0)), +this.insertChar(b[a],a<e-1,c)},insertChar:function(b,d,c){var a="\n"===this.text[this.selectionStart];this.text=this.text.slice(0,this.selectionStart)+b+this.text.slice(this.selectionEnd);this._textLines=this._splitTextIntoLines();this.insertStyleObjects(b,a,c);this.selectionEnd=this.selectionStart+=b.length;d||(this._updateTextarea(),this.setCoords(),this._fireSelectionChanged(),this.fire("changed"),this.restartCursorIfNeeded(),this.canvas&&(this.canvas.fire("text:changed",{target:this}),this.canvas.renderAll()))}, +restartCursorIfNeeded:function(){this._currentTickState&&!this._currentTickState.isAborted&&this._currentTickCompleteState&&!this._currentTickCompleteState.isAborted||this.initDelayedCursor()},insertNewlineStyleObject:function(b,d,c){this.shiftLineStyles(b,1);var a={},g={};this.styles[b]&&this.styles[b][d-1]&&(a=this.styles[b][d-1]);if(c&&a)g[0]=e(a),this.styles[b+1]=g;else{c=!1;for(var h in this.styles[b])a=parseInt(h,10),a>=d&&(c=!0,g[a-d]=this.styles[b][h],delete this.styles[b][h]);c&&(this.styles[b+ +1]=g)}this._forceClearCache=!0},insertCharStyleObject:function(b,d,c){var a=this.styles[b],g=e(a);0!==d||c||(d=1);for(var h in g){var f=parseInt(h,10);f>=d&&(a[f+1]=g[f],g[f-1]||delete a[f])}(c=c||e(a[d-1]))&&(this.styles[b][d]=c);this._forceClearCache=!0},insertStyleObjects:function(b,d,c){var a=this.get2DCursorLocation(),e=a.lineIndex,a=a.charIndex;this._getLineStyle(e)||this._setLineStyle(e,{});"\n"===b?this.insertNewlineStyleObject(e,a,d):this.insertCharStyleObject(e,a,c)},shiftLineStyles:function(b, +d){var c=e(this.styles),a;for(a in c){var g=parseInt(a,10);g<=b&&delete c[g]}for(a in this.styles)g=parseInt(a,10),g>b&&(this.styles[g+d]=c[g],c[g-d]||delete this.styles[g])},removeStyleObject:function(b,d){var c=this.get2DCursorLocation(d);this._removeStyleObject(b,c,c.lineIndex,c.charIndex)},_getTextOnPreviousLine:function(b){return this._textLines[b-1]},_removeStyleObject:function(b,d,c,a){if(b){var g=this._getTextOnPreviousLine(d.lineIndex),g=g?g.length:0;this.styles[c-1]||(this.styles[c-1]={}); +for(a in this.styles[c])this.styles[c-1][parseInt(a,10)+g]=this.styles[c][a];this.shiftLineStyles(d.lineIndex,-1)}else for(g in(d=this.styles[c])&&delete d[a],c=e(d),c)b=parseInt(g,10),b>=a&&0!==b&&(d[b-1]=c[b],delete d[b])},insertNewline:function(){this.insertChars("\n")},setSelectionStartEndWithShift:function(b,d,c){c<=b?(d===b?this._selectionDirection="left":"right"===this._selectionDirection&&(this._selectionDirection="left",this.selectionEnd=b),this.selectionStart=c):c>b&&c<d?"right"===this._selectionDirection? +this.selectionEnd=c:this.selectionStart=c:(d===b?this._selectionDirection="right":"left"===this._selectionDirection&&(this._selectionDirection="right",this.selectionStart=d),this.selectionEnd=c)},setSelectionInBoundaries:function(){var b=this.text.length;this.selectionStart>b?this.selectionStart=b:0>this.selectionStart&&(this.selectionStart=0);this.selectionEnd>b?this.selectionEnd=b:0>this.selectionEnd&&(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(e){this.__newClickTime=+new Date;var b=this.canvas.getPointer(e.e);this.isTripleClick(b,e.e)?(this.fire("tripleclick",e),this._stopEvent(e.e)):this.isDoubleClick(b)&&(this.fire("dblclick",e),this._stopEvent(e.e));this.__lastLastClickTime=this.__lastClickTime; +this.__lastClickTime=this.__newClickTime;this.__lastPointer=b;this.__lastIsEditing=this.isEditing;this.__lastSelected=this.selected},isDoubleClick:function(e){return 500>this.__newClickTime-this.__lastClickTime&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y&&this.__lastIsEditing},isTripleClick:function(e){return 500>this.__newClickTime-this.__lastClickTime&&500>this.__lastClickTime-this.__lastLastClickTime&&this.__lastPointer.x===e.x&&this.__lastPointer.y===e.y},_stopEvent:function(e){e.preventDefault&& +e.preventDefault();e.stopPropagation&&e.stopPropagation()},initCursorSelectionHandlers:function(){this.initMousedownHandler();this.initMouseupHandler();this.initClicks()},initClicks:function(){this.on("dblclick",function(e){this.selectWord(this.getSelectionStartFromPointer(e.e))});this.on("tripleclick",function(e){this.selectLine(this.getSelectionStartFromPointer(e.e))})},initMousedownHandler:function(){this.on("mousedown",function(e){if(this.editable&&(!e.e.button||1===e.e.button)){var b=this.canvas.getPointer(e.e); +this.__mousedownX=b.x;this.__mousedownY=b.y;this.__isMousedown=!0;this.selected&&this.setCursorByClick(e.e);this.isEditing&&(this.__selectionStartOnMouseDown=this.selectionStart,this.selectionStart===this.selectionEnd&&this.abortCursorAnimation(),this.renderCursorOrSelection())}})},_isObjectMoved:function(e){e=this.canvas.getPointer(e);return this.__mousedownX!==e.x||this.__mousedownY!==e.y},initMouseupHandler:function(){this.on("mouseup",function(e){this.__isMousedown=!1;!this.editable||this._isObjectMoved(e.e)|| +e.e.button&&1!==e.e.button||(this.__lastSelected&&!this.__corner&&(this.enterEditing(e.e),this.selectionStart===this.selectionEnd?this.initDelayedCursor(!0):this.renderCursorOrSelection()),this.selected=!0)})},setCursorByClick:function(e){var b=this.getSelectionStartFromPointer(e),d=this.selectionStart,c=this.selectionEnd;e.shiftKey?this.setSelectionStartEndWithShift(d,c,b):this.selectionEnd=this.selectionStart=b;this.isEditing&&(this._fireSelectionChanged(),this._updateTextarea())},getSelectionStartFromPointer:function(e){e= +this.getLocalPointer(e);for(var b=0,d,c=0,a=0,g,h=0,f=this._textLines.length;h<f;h++){g=this._textLines[h];c+=this._getHeightOfLine(this.ctx,h)*this.scaleY;d=this._getLineWidth(this.ctx,h);d=this._getLineLeftOffset(d)*this.scaleX;for(var l=0,k=g.length;l<k;l++)if(b=d,d+=this._getWidthOfChar(this.ctx,g[l],h,this.flipX?k-l:l)*this.scaleX,c<=e.y||d<=e.x)a++;else return this._getNewSelectionStartFromOffset(e,b,d,a+h,k);if(e.y<c)return this._getNewSelectionStartFromOffset(e,b,d,a+h-1,k)}return this.text.length}, +_getNewSelectionStartFromOffset:function(e,b,d,c,a){e=c+(d-e.x>e.x-b?0:1);this.flipX&&(e=a-e);e>this.text.length&&(e=this.text.length);return e}}); +fabric.util.object.extend(fabric.IText.prototype,{initHiddenTextarea:function(){this.hiddenTextarea=fabric.document.createElement("textarea");this.hiddenTextarea.setAttribute("autocapitalize","off");this.hiddenTextarea.setAttribute("autocorrect","off");this.hiddenTextarea.setAttribute("autocomplete","off");this.hiddenTextarea.setAttribute("spellcheck","false");this.hiddenTextarea.setAttribute("data-fabric-hiddentextarea","");this.hiddenTextarea.setAttribute("wrap","off");var e=this._calcTextareaPosition(); +this.hiddenTextarea.style.cssText="position: absolute; top: "+e.top+"; left: "+e.left+"; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px; line-height: 1px; padding\uff70top: "+e.fontSize+";";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(e){if(this.isEditing){if(e.keyCode in this.keysMap)this[this.keysMap[e.keyCode]](e);else if(e.keyCode in this.ctrlKeysMapDown&&(e.ctrlKey||e.metaKey))this[this.ctrlKeysMapDown[e.keyCode]](e);else return;e.stopImmediatePropagation();e.preventDefault();33<=e.keyCode&&40>=e.keyCode?(this.clearContextTop(),this.renderCursorOrSelection()):this.canvas&&this.canvas.renderAll()}},onKeyUp:function(e){!this.isEditing||this._copyDone?this._copyDone=!1:e.keyCode in this.ctrlKeysMapUp&&(e.ctrlKey|| +e.metaKey)&&(this[this.ctrlKeysMapUp[e.keyCode]](e),e.stopImmediatePropagation(),e.preventDefault(),this.canvas&&this.canvas.renderAll())},onInput:function(e){if(this.isEditing&&!this.inCompositionMode){var b=this.selectionStart||0,d=this.selectionEnd||0,c=this.text.length,a=this.hiddenTextarea.value.length;a>c?(b="left"===this._selectionDirection?d:b,c=this.hiddenTextarea.value.slice(b,b+(a-c))):c=this.hiddenTextarea.value.slice(b,b+(a-c+d-b));this.insertChars(c);e.stopPropagation()}},onCompositionStart:function(){this.inCompositionMode= +!0;this.prevCompositionLength=0;this.compositionStart=this.selectionStart},onCompositionEnd:function(){this.inCompositionMode=!1},onCompositionUpdate:function(e){e=e.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(e){if(this.selectionStart===this.selectionEnd){if(this.selectionStart===this.text.length)return; +this.moveCursorRight(e)}this.removeChars(e)},copy:function(e){if(this.selectionStart!==this.selectionEnd){var b=this.getSelectedText(),d=this._getClipboardData(e);d&&d.setData("text",b);fabric.copiedText=b;fabric.copiedTextStyle=this.getSelectionStyles(this.selectionStart,this.selectionEnd);e.stopImmediatePropagation();e.preventDefault();this._copyDone=!0}},paste:function(e){var b;b=this._getClipboardData(e);var d=!0;b?(b=b.getData("text").replace(/\r/g,""),fabric.copiedTextStyle&&fabric.copiedText=== +b||(d=!1)):b=fabric.copiedText;b&&this.insertChars(b,d);e.stopImmediatePropagation();e.preventDefault()},cut:function(e){this.selectionStart!==this.selectionEnd&&(this.copy(e),this.removeChars(e))},_getClipboardData:function(e){return e&&e.clipboardData||fabric.window.clipboardData},_getWidthBeforeCursor:function(e,b){for(var d=this._textLines[e].slice(0,b),c=this._getLineWidth(this.ctx,e),c=this._getLineLeftOffset(c),a,g=0,h=d.length;g<h;g++)a=d[g],c+=this._getWidthOfChar(this.ctx,a,e,g);return c}, +getDownCursorOffset:function(e,b){var d=this._getSelectionForOffset(e,b),c=this.get2DCursorLocation(d),a=c.lineIndex;if(a===this._textLines.length-1||e.metaKey||34===e.keyCode)return this.text.length-d;d=c.charIndex;c=this._getWidthBeforeCursor(a,d);c=this._getIndexOnLine(a+1,c);return this._textLines[a].slice(d).length+c+2},_getSelectionForOffset:function(e,b){return e.shiftKey&&this.selectionStart!==this.selectionEnd&&b?this.selectionEnd:this.selectionStart},getUpCursorOffset:function(e,b){var d= +this._getSelectionForOffset(e,b),c=this.get2DCursorLocation(d),a=c.lineIndex;if(0===a||e.metaKey||33===e.keyCode)return-d;d=c.charIndex;c=this._getWidthBeforeCursor(a,d);c=this._getIndexOnLine(a-1,c);d=this._textLines[a].slice(0,d);return-this._textLines[a-1].length+c-d.length},_getIndexOnLine:function(e,b){for(var d=this._getLineWidth(this.ctx,e),c=this._textLines[e],d=this._getLineLeftOffset(d),a=0,g,h=0,f=c.length;h<f;h++){var l=this._getWidthOfChar(this.ctx,c[h],e,h),d=d+l;if(d>b){g=!0;a=Math.abs(d- +b)<Math.abs(d-l-b)?h:h-1;break}}g||(a=c.length-1);return a},moveCursorDown:function(e){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorUpOrDown("Down",e)},moveCursorUp:function(e){0===this.selectionStart&&0===this.selectionEnd||this._moveCursorUpOrDown("Up",e)},_moveCursorUpOrDown:function(e,b){var d=this["get"+e+"CursorOffset"](b,"right"===this._selectionDirection);b.shiftKey?this.moveCursorWithShift(d):this.moveCursorWithoutShift(d);0!==d&&(this.setSelectionInBoundaries(), +this.abortCursorAnimation(),this._currentCursorOpacity=1,this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorWithShift:function(e){this.setSelectionStartEndWithShift(this.selectionStart,this.selectionEnd,"left"===this._selectionDirection?this.selectionStart+e:this.selectionEnd+e);return 0!==e},moveCursorWithoutShift:function(e){0>e?this.selectionEnd=this.selectionStart+=e:this.selectionStart=this.selectionEnd+=e;return 0!==e},moveCursorLeft:function(e){0===this.selectionStart&& +0===this.selectionEnd||this._moveCursorLeftOrRight("Left",e)},_move:function(e,b,d){if(e.altKey)e=this["findWordBoundary"+d](this[b]);else if(e.metaKey||35===e.keyCode||36===e.keyCode)e=this["findLineBoundary"+d](this[b]);else return this[b]+="Left"===d?-1:1,!0;if(this[b]!==e)return this[b]=e,!0},_moveLeft:function(e,b){return this._move(e,b,"Left")},_moveRight:function(e,b){return this._move(e,b,"Right")},moveCursorLeftWithoutShift:function(e){var b=!0;this._selectionDirection="left";this.selectionEnd=== +this.selectionStart&&0!==this.selectionStart&&(b=this._moveLeft(e,"selectionStart"));this.selectionEnd=this.selectionStart;return b},moveCursorLeftWithShift:function(e){if("right"===this._selectionDirection&&this.selectionStart!==this.selectionEnd)return this._moveLeft(e,"selectionEnd");if(0!==this.selectionStart)return this._selectionDirection="left",this._moveLeft(e,"selectionStart")},moveCursorRight:function(e){this.selectionStart>=this.text.length&&this.selectionEnd>=this.text.length||this._moveCursorLeftOrRight("Right", +e)},_moveCursorLeftOrRight:function(e,b){var d="moveCursor"+e+"With";this._currentCursorOpacity=1;d=b.shiftKey?d+"Shift":d+"outShift";this[d](b)&&(this.abortCursorAnimation(),this.initDelayedCursor(),this._fireSelectionChanged(),this._updateTextarea())},moveCursorRightWithShift:function(e){if("left"===this._selectionDirection&&this.selectionStart!==this.selectionEnd)return this._moveRight(e,"selectionStart");if(this.selectionEnd!==this.text.length)return this._selectionDirection="right",this._moveRight(e, +"selectionEnd")},moveCursorRightWithoutShift:function(e){var b=!0;this._selectionDirection="right";this.selectionStart===this.selectionEnd?(b=this._moveRight(e,"selectionStart"),this.selectionEnd=this.selectionStart):this.selectionStart=this.selectionEnd;return b},removeChars:function(e){this.selectionStart===this.selectionEnd?this._removeCharsNearCursor(e):this._removeCharsFromTo(this.selectionStart,this.selectionEnd);this.set("dirty",!0);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(e){0!==this.selectionStart&&(e.metaKey?(e=this.findLineBoundaryLeft(this.selectionStart),this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)):e.altKey?(e=this.findWordBoundaryLeft(this.selectionStart),this._removeCharsFromTo(e,this.selectionStart),this.setSelectionStart(e)):(this._removeSingleCharAndStyle(this.selectionStart), +this.setSelectionStart(this.selectionStart-1)))}}); +(function(){var e=fabric.util.toFixed,b=fabric.Object.NUM_FRACTION_DIGITS;fabric.util.object.extend(fabric.IText.prototype,{_setSVGTextLineText:function(b,c,a,e,h,f){this._getLineStyle(b)?this._setSVGTextLineChars(b,c,a,e,f):fabric.Text.prototype._setSVGTextLineText.call(this,b,c,a,e,h)},_setSVGTextLineChars:function(b,c,a,e,h){a=this._textLines[b];e=0;for(var d=this._getLineLeftOffset(this._getLineWidth(this.ctx,b))-this.width/2,g=this._getSVGLineTopOffset(b),k=this._getHeightOfLine(this.ctx,b), +m=0,n=a.length;m<n;m++){var p=this._getStyleDeclaration(b,m)||{};c.push(this._createTextCharSpan(a[m],p,d,g.lineTop+g.offset,e));var q=this._getWidthOfChar(this.ctx,a[m],b,m);p.textBackgroundColor&&h.push(this._createTextCharBg(p,d,g.lineTop,k,q,e));e+=q}},_getSVGLineTopOffset:function(b){for(var c=0,a=0;a<b;a++)c+=this._getHeightOfLine(this.ctx,a);b=this._getHeightOfLine(this.ctx,a);return{lineTop:c,offset:(this._fontSizeMult-this._fontSizeFraction)*b/(this.lineHeight*this._fontSizeMult)}},_createTextCharBg:function(d, +c,a,g,h,f){return['\t\t<rect fill="',d.textBackgroundColor,'" x="',e(c+f,b),'" y="',e(a-this.height/2,b),'" width="',e(h,b),'" height="',e(g/this.lineHeight,b),'"></rect>\n'].join("")},_createTextCharSpan:function(d,c,a,g,h){var f=this.getSvgStyles.call(fabric.util.object.extend({visible:!0,fill:this.fill,stroke:this.stroke,type:"text",getSvgFilter:fabric.Object.prototype.getSvgFilter},c));return['\t\t\t<tspan x="',e(a+h,b),'" y="',e(g-this.height/2,b),'" ',c.fontFamily?'font-family="'+c.fontFamily.replace(/"/g, +"'")+'" ':"",c.fontSize?'font-size="'+c.fontSize+'" ':"",c.fontStyle?'font-style="'+c.fontStyle+'" ':"",c.fontWeight?'font-weight="'+c.fontWeight+'" ':"",c.textDecoration?'text-decoration="'+c.textDecoration+'" ':"",'style="',f,'">',fabric.util.string.escapeXml(d),"</tspan>\n"].join("")}})})(); +(function(e){var b=e.fabric||(e.fabric={});b.Textbox=b.util.createClass(b.IText,b.Observable,{type:"textbox",minWidth:20,dynamicMinWidth:2,__cachedLines:null,lockScalingY:!0,lockScalingFlip:!0,noScaleCache:!1,_dimensionAffectingProps:b.Text.prototype._dimensionAffectingProps.concat("width"),initialize:function(d,c){this.callSuper("initialize",d,c);this.setControlsVisibility(b.Textbox.getTextboxControlVisibility());this.ctx=this.objectCaching?this._cacheContext:b.util.createCanvasElement().getContext("2d")}, +_initDimensions:function(d){this.__skipDimension||(d||(d=b.util.createCanvasElement().getContext("2d"),this._setTextStyles(d),this.clearContextTop()),this.dynamicMinWidth=0,this._textLines=this._splitTextIntoLines(d),this.dynamicMinWidth>this.width&&this._set("width",this.dynamicMinWidth),this._clearCache(),this.height=this._getTextHeight(d),this.setCoords())},_generateStyleMap:function(){for(var b=0,c=0,a=0,e={},h=0;h<this._textLines.length;h++)"\n"===this.text[a]&&0<h?(c=0,a++,b++):" "===this.text[a]&& +0<h&&(c++,a++),e[h]={line:b,offset:c},a+=this._textLines[h].length,c+=this._textLines[h].length;return e},_getStyleDeclaration:function(b,c,a){if(this._styleMap){var d=this._styleMap[b];if(!d)return a?{}:null;b=d.line;c=d.offset+c}return this.callSuper("_getStyleDeclaration",b,c,a)},_setStyleDeclaration:function(b,c,a){var d=this._styleMap[b];b=d.line;c=d.offset+c;this.styles[b][c]=a},_deleteStyleDeclaration:function(b,c){var a=this._styleMap[b];b=a.line;c=a.offset+c;delete this.styles[b][c]},_getLineStyle:function(b){return this.styles[this._styleMap[b].line]}, +_setLineStyle:function(b,c){this.styles[this._styleMap[b].line]=c},_deleteLineStyle:function(b){delete this.styles[this._styleMap[b].line]},_wrapText:function(b,c){var a=c.split(this._reNewline),d=[],e;for(e=0;e<a.length;e++)d=d.concat(this._wrapLine(b,a[e],e));return d},_measureText:function(b,c,a,e){var d=0;e=e||0;for(var f=0,g=c.length;f<g;f++)d+=this._getWidthOfChar(b,c[f],a,f+e);return d},_wrapLine:function(b,c,a){var d=0,e=[],f="";c=c.split(" ");for(var l,k=0,m,n=0,p=0,q=!0,t=this._getWidthOfCharSpacing(), +r=0;r<c.length;r++)l=c[r],m=this._measureText(b,l,a,k),k+=l.length,d+=n+m-t,d>=this.width&&!q?(e.push(f),f="",d=m,q=!0):d+=t,q||(f+=" "),f+=l,n=this._measureText(b," ",a,k),k++,q=!1,m>p&&(p=m);r&&e.push(f);p>this.dynamicMinWidth&&(this.dynamicMinWidth=p-t);return e},_splitTextIntoLines:function(b){b=b||this.ctx;var c=this.textAlign;this._styleMap=null;b.save();this._setTextStyles(b);this.textAlign="left";var a=this._wrapText(b,this.text);this.textAlign=c;b.restore();this._textLines=a;this._styleMap= +this._generateStyleMap();return a},setOnGroup:function(b,c){"scaleX"===b&&(this.set("scaleX",Math.abs(1/c)),this.set("width",this.get("width")*c/("undefined"===typeof this.__oldScaleX?1:this.__oldScaleX)),this.__oldScaleX=c)},get2DCursorLocation:function(b){"undefined"===typeof b&&(b=this.selectionStart);for(var c=this._textLines.length,a=0,d=0;d<c;d++){var e=this._textLines[d].length;if(b<=a+e)return{lineIndex:d,charIndex:b-a};a+=e;"\n"!==this.text[a]&&" "!==this.text[a]||a++}return{lineIndex:c- +1,charIndex:this._textLines[c-1].length}},_getCursorBoundariesOffsets:function(b,c){for(var a=0,d=0,e=this.get2DCursorLocation(),f=this._textLines[e.lineIndex].split(""),l=this._getLineLeftOffset(this._getLineWidth(this.ctx,e.lineIndex)),k=0;k<e.charIndex;k++)d+=this._getWidthOfChar(this.ctx,f[k],e.lineIndex,k);for(k=0;k<e.lineIndex;k++)a+=this._getHeightOfLine(this.ctx,k);"cursor"===c&&(a+=(1-this._fontSizeFraction)*this._getHeightOfLine(this.ctx,e.lineIndex)/this.lineHeight-this.getCurrentCharFontSize(e.lineIndex, +e.charIndex)*(1-this._fontSizeFraction));return{top:a,left:d,lineLeft:l}},getMinWidth:function(){return Math.max(this.minWidth,this.dynamicMinWidth)},toObject:function(b){return this.callSuper("toObject",["minWidth"].concat(b))}});b.Textbox.fromObject=function(d,c,a){return b.Object._fromObject("Textbox",d,c,a,"text")};b.Textbox.getTextboxControlVisibility=function(){return{tl:!1,tr:!1,br:!1,bl:!1,ml:!0,mt:!1,mr:!0,mb:!1,mtr:!0}}})("undefined"!==typeof exports?exports:this); +(function(){var e=fabric.Canvas.prototype._setObjectScale;fabric.Canvas.prototype._setObjectScale=function(b,d,c,a,g,h,f){var l=d.target;if(l instanceof fabric.Textbox){if(b=b.x/d.scaleX/(l.width+l.strokeWidth)*l.width,b>=l.getMinWidth())return l.set("width",b),!0}else return e.call(fabric.Canvas.prototype,b,d,c,a,g,h,f)};fabric.Group.prototype._refreshControlsVisibility=function(){if("undefined"!==typeof fabric.Textbox)for(var b=this._objects.length;b--;)if(this._objects[b]instanceof fabric.Textbox){this.setControlsVisibility(fabric.Textbox.getTextboxControlVisibility()); +break}};fabric.util.object.extend(fabric.Textbox.prototype,{_removeExtraneousStyles:function(){for(var b in this._styleMap)this._textLines[b]||delete this.styles[this._styleMap[b].line]},insertCharStyleObject:function(b,d,c){var a=this._styleMap[b];b=a.line;d=a.offset+d;fabric.IText.prototype.insertCharStyleObject.apply(this,[b,d,c])},insertNewlineStyleObject:function(b,d,c){var a=this._styleMap[b];b=a.line;d=a.offset+d;fabric.IText.prototype.insertNewlineStyleObject.apply(this,[b,d,c])},shiftLineStyles:function(b, +d){b=this._styleMap[b].line;fabric.IText.prototype.shiftLineStyles.call(this,b,d)},_getTextOnPreviousLine:function(b){for(var d=this._textLines[b-1];this._styleMap[b-2]&&this._styleMap[b-2].line===this._styleMap[b-1].line;)d=this._textLines[b-2]+d,b--;return d},removeStyleObject:function(b,d){var c=this.get2DCursorLocation(d),a=this._styleMap[c.lineIndex];this._removeStyleObject(b,c,a.line,a.offset+c.charIndex)}})})(); +(function(){var e=fabric.IText.prototype._getNewSelectionStartFromOffset;fabric.IText.prototype._getNewSelectionStartFromOffset=function(b,d,c,a,g){a=e.call(this,b,d,c,a,g);for(c=d=b=0;c<this._textLines.length;c++){b+=this._textLines[c].length;if(b+d>=a)break;"\n"!==this.text[b+d]&&" "!==this.text[b+d]||d++}return a-c+d}})(); +(function(){function e(b,d,e){var f=c.parse(b);f.port||(f.port=0===f.protocol.indexOf("https:")?443:80);b=(0===f.protocol.indexOf("https:")?g:a).request({hostname:f.hostname,port:f.port,path:f.path,method:"GET"},function(a){var b="";d&&a.setEncoding(d);a.on("end",function(){e(b)});a.on("data",function(c){200===a.statusCode&&(b+=c)})});b.on("error",function(a){a.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+f.hostname+":"+f.port):fabric.log(a.message);e(null)});b.end()} +function b(a,b){require("fs").readFile(a,function(a,c){if(a)throw fabric.log(a),a;b(c)})}if("undefined"===typeof document||"undefined"===typeof window){var d=require("xmldom").DOMParser,c=require("url"),a=require("http"),g=require("https"),h=require("canvas"),f=require("canvas").Image;fabric.util.loadImage=function(a,c,d){function g(b){b?(h.src=new Buffer(b,"binary"),h._src=a,c&&c.call(d,h)):(h=null,c&&c.call(d,null,!0))}var h=new f;a&&(a instanceof Buffer||0===a.indexOf("data"))?(h.src=h._src=a, +c&&c.call(d,h)):a&&0!==a.indexOf("http")?b(a,g):a?e(a,"binary",g):c&&c.call(d,a)};fabric.loadSVGFromURL=function(a,c,d){a=a.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim();0!==a.indexOf("http")?b(a,function(a){fabric.loadSVGFromString(a.toString(),c,d)}):e(a,"",function(a){fabric.loadSVGFromString(a,c,d)})};fabric.loadSVGFromString=function(a,b,c){a=(new d).parseFromString(a);fabric.parseSVGDocument(a.documentElement,function(a,c){b&&b(a,c)},c)};fabric.util.getScript=function(a,b){e(a,"",function(a){eval(a); +b&&b()})};fabric.createCanvasForNode=function(a,b,c,d){d=d||c;var e=fabric.document.createElement("canvas"),f=new h(a||600,b||600,d);a=new h(a||600,b||600,d);e.style={};e.width=f.width;e.height=f.height;c=c||{};c.nodeCanvas=f;c.nodeCacheCanvas=a;c=new (fabric.Canvas||fabric.StaticCanvas)(e,c);c.nodeCanvas=f;c.nodeCacheCanvas=a;c.contextContainer=f.getContext("2d");c.contextCache=a.getContext("2d");c.Font=h.Font;return c};var l=fabric.StaticCanvas.prototype._initStatic;fabric.StaticCanvas.prototype._initStatic= +function(a,b){a=a||fabric.document.createElement("canvas");this.nodeCanvas=new h(a.width,a.height);this.nodeCacheCanvas=new h(a.width,a.height);l.call(this,a,b);this.contextContainer=this.nodeCanvas.getContext("2d");this.contextCache=this.nodeCacheCanvas.getContext("2d");this.Font=h.Font};fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()};fabric.StaticCanvas.prototype.createJPEGStream=function(a){return this.nodeCanvas.createJPEGStream(a)};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 k=fabric.StaticCanvas.prototype._setBackstoreDimension;fabric.StaticCanvas.prototype._setBackstoreDimension=function(a,b){k.call(this,a,b);this.nodeCanvas[a]=b;return this};fabric.Canvas&&(fabric.Canvas.prototype._setBackstoreDimension=fabric.StaticCanvas.prototype._setBackstoreDimension)}})(); +/* pako 0.2.3 nodeca/pako */ !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.pako=e()}}(function(){return function e(t,i,n){function a(s,o){if(!i[s]){if(!t[s]){var f="function"==typeof require&&require;if(!o&&f)return f(s,!0);if(r)return r(s,!0);throw new Error("Cannot find module '"+s+"'")}var l=i[s]={exports:{}};t[s][0].call(l.exports,function(e){var i=t[s][1][e];return a(i?i:e)},l,l.exports,e,t,i,n)}return i[s].exports}for(var r="function"==typeof require&&require,s=0;s<n.length;s++)a(n[s]);return a}({1:[function(e,t,i){"use strict";function n(e,t){var i=new h(t);if(i.push(e,!0),i.err)throw i.msg;return i.result}function a(e,t){return t=t||{},t.raw=!0,n(e,t)}var r=e("./zlib/inflate.js"),s=e("./utils/common"),o=e("./utils/strings"),f=e("./zlib/constants"),l=e("./zlib/messages"),d=e("./zlib/zstream"),u=e("./zlib/gzheader"),h=function(e){this.options=s.assign({chunkSize:16384,windowBits:0,to:""},e||{});var t=this.options;t.raw&&t.windowBits>=0&&t.windowBits<16&&(t.windowBits=-t.windowBits,0===t.windowBits&&(t.windowBits=-15)),!(t.windowBits>=0&&t.windowBits<16)||e&&e.windowBits||(t.windowBits+=32),t.windowBits>15&&t.windowBits<48&&0===(15&t.windowBits)&&(t.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new d,this.strm.avail_out=0;var i=r.inflateInit2(this.strm,t.windowBits);if(i!==f.Z_OK)throw new Error(l[i]);this.header=new u,r.inflateGetHeader(this.strm,this.header)};h.prototype.push=function(e,t){var i,n,a,l,d,u=this.strm,h=this.options.chunkSize;if(this.ended)return!1;n=t===~~t?t:t===!0?f.Z_FINISH:f.Z_NO_FLUSH,u.input="string"==typeof e?o.binstring2buf(e):e,u.next_in=0,u.avail_in=u.input.length;do{if(0===u.avail_out&&(u.output=new s.Buf8(h),u.next_out=0,u.avail_out=h),i=r.inflate(u,f.Z_NO_FLUSH),i!==f.Z_STREAM_END&&i!==f.Z_OK)return this.onEnd(i),this.ended=!0,!1;u.next_out&&(0===u.avail_out||i===f.Z_STREAM_END||0===u.avail_in&&n===f.Z_FINISH)&&("string"===this.options.to?(a=o.utf8border(u.output,u.next_out),l=u.next_out-a,d=o.buf2string(u.output,a),u.next_out=l,u.avail_out=h-l,l&&s.arraySet(u.output,u.output,a,l,0),this.onData(d)):this.onData(s.shrinkBuf(u.output,u.next_out)))}while((u.avail_in>0||0===u.avail_out)&&i!==f.Z_STREAM_END);return i===f.Z_STREAM_END&&(n=f.Z_FINISH),n===f.Z_FINISH?(i=r.inflateEnd(this.strm),this.onEnd(i),this.ended=!0,i===f.Z_OK):!0},h.prototype.onData=function(e){this.chunks.push(e)},h.prototype.onEnd=function(e){e===f.Z_OK&&(this.result="string"===this.options.to?this.chunks.join(""):s.flattenChunks(this.chunks)),this.chunks=[],this.err=e,this.msg=this.strm.msg},i.Inflate=h,i.inflate=n,i.inflateRaw=a,i.ungzip=n},{"./utils/common":2,"./utils/strings":3,"./zlib/constants":5,"./zlib/gzheader":7,"./zlib/inflate.js":9,"./zlib/messages":11,"./zlib/zstream":12}],2:[function(e,t,i){"use strict";var n="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;i.assign=function(e){for(var t=Array.prototype.slice.call(arguments,1);t.length;){var i=t.shift();if(i){if("object"!=typeof i)throw new TypeError(i+"must be non-object");for(var n in i)i.hasOwnProperty(n)&&(e[n]=i[n])}}return e},i.shrinkBuf=function(e,t){return e.length===t?e:e.subarray?e.subarray(0,t):(e.length=t,e)};var a={arraySet:function(e,t,i,n,a){if(t.subarray&&e.subarray)return void e.set(t.subarray(i,i+n),a);for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){var t,i,n,a,r,s;for(n=0,t=0,i=e.length;i>t;t++)n+=e[t].length;for(s=new Uint8Array(n),a=0,t=0,i=e.length;i>t;t++)r=e[t],s.set(r,a),a+=r.length;return s}},r={arraySet:function(e,t,i,n,a){for(var r=0;n>r;r++)e[a+r]=t[i+r]},flattenChunks:function(e){return[].concat.apply([],e)}};i.setTyped=function(e){e?(i.Buf8=Uint8Array,i.Buf16=Uint16Array,i.Buf32=Int32Array,i.assign(i,a)):(i.Buf8=Array,i.Buf16=Array,i.Buf32=Array,i.assign(i,r))},i.setTyped(n)},{}],3:[function(e,t,i){"use strict";function n(e,t){if(65537>t&&(e.subarray&&s||!e.subarray&&r))return String.fromCharCode.apply(null,a.shrinkBuf(e,t));for(var i="",n=0;t>n;n++)i+=String.fromCharCode(e[n]);return i}var a=e("./common"),r=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(o){r=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(o){s=!1}for(var f=new a.Buf8(256),l=0;256>l;l++)f[l]=l>=252?6:l>=248?5:l>=240?4:l>=224?3:l>=192?2:1;f[254]=f[254]=1,i.string2buf=function(e){var t,i,n,r,s,o=e.length,f=0;for(r=0;o>r;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),f+=128>i?1:2048>i?2:65536>i?3:4;for(t=new a.Buf8(f),s=0,r=0;f>s;r++)i=e.charCodeAt(r),55296===(64512&i)&&o>r+1&&(n=e.charCodeAt(r+1),56320===(64512&n)&&(i=65536+(i-55296<<10)+(n-56320),r++)),128>i?t[s++]=i:2048>i?(t[s++]=192|i>>>6,t[s++]=128|63&i):65536>i?(t[s++]=224|i>>>12,t[s++]=128|i>>>6&63,t[s++]=128|63&i):(t[s++]=240|i>>>18,t[s++]=128|i>>>12&63,t[s++]=128|i>>>6&63,t[s++]=128|63&i);return t},i.buf2binstring=function(e){return n(e,e.length)},i.binstring2buf=function(e){for(var t=new a.Buf8(e.length),i=0,n=t.length;n>i;i++)t[i]=e.charCodeAt(i);return t},i.buf2string=function(e,t){var i,a,r,s,o=t||e.length,l=new Array(2*o);for(a=0,i=0;o>i;)if(r=e[i++],128>r)l[a++]=r;else if(s=f[r],s>4)l[a++]=65533,i+=s-1;else{for(r&=2===s?31:3===s?15:7;s>1&&o>i;)r=r<<6|63&e[i++],s--;s>1?l[a++]=65533:65536>r?l[a++]=r:(r-=65536,l[a++]=55296|r>>10&1023,l[a++]=56320|1023&r)}return n(l,a)},i.utf8border=function(e,t){var i;for(t=t||e.length,t>e.length&&(t=e.length),i=t-1;i>=0&&128===(192&e[i]);)i--;return 0>i?t:0===i?t:i+f[e[it?i:t}},{"./common":2}],4:[function(e,t){"use strict";function i(e,t,i,n){for(var a=65535&e|0,r=e>>>16&65535|0,s=0;0!==i;){s=i>2e3?2e3:i,i-=s;do a=a+t[n++]|0,r=r+a|0;while(--s);a%=65521,r%=65521}return a|r<<16|0}t.exports=i},{}],5:[function(e,t){t.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],6:[function(e,t){"use strict";function i(){for(var e,t=[],i=0;256>i;i++){e=i;for(var n=0;8>n;n++)e=1&e?3988292384^e>>>1:e>>>1;t[i]=e}return t}function n(e,t,i,n){var r=a,s=n+i;e=-1^e;for(var o=n;s>o;o++)e=e>>>8^r[255&(e^t[o])];return-1^e}var a=i();t.exports=n},{}],7:[function(e,t){"use strict";function i(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}t.exports=i},{}],8:[function(e,t){"use strict";var i=30,n=12;t.exports=function(e,t){var a,r,s,o,f,l,d,u,h,c,b,w,m,k,g,_,v,p,x,y,S,B,E,Z,A;a=e.state,r=e.next_in,Z=e.input,s=r+(e.avail_in-5),o=e.next_out,A=e.output,f=o-(t-e.avail_out),l=o+(e.avail_out-257),d=a.dmax,u=a.wsize,h=a.whave,c=a.wnext,b=a.window,w=a.hold,m=a.bits,k=a.lencode,g=a.distcode,_=(1<m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,0===x)A[o++]=65535&p;else{if(!(16&x)){if(0===(64&x)){p=k[(65535&p)+(w&(1<m&&(w+=Z[r++]<>>=x,m-=x),15>m&&(w+=Z[r++]<>>24,w>>>=x,m-=x,x=p>>>16&255,!(16&x)){if(0===(64&x)){p=g[(65535&p)+(w&(1<m&&(w+=Z[r++]<m&&(w+=Z[r++]<d){e.msg="invalid distance too far back",a.mode=i;break e}if(w>>>=x,m-=x,x=o-f,S>x){if(x=S-x,x>h&&a.sane){e.msg="invalid distance too far back",a.mode=i;break e}if(B=0,E=b,0===c){if(B+=u-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}else if(x>c){if(B+=u+c-x,x-=c,y>x){y-=x;do A[o++]=b[B++];while(--x);if(B=0,y>c){x=c,y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}}}else if(B+=c-x,y>x){y-=x;do A[o++]=b[B++];while(--x);B=o-S,E=A}for(;y>2;)A[o++]=E[B++],A[o++]=E[B++],A[o++]=E[B++],y-=3;y&&(A[o++]=E[B++],y>1&&(A[o++]=E[B++]))}else{B=o-S;do A[o++]=A[B++],A[o++]=A[B++],A[o++]=A[B++],y-=3;while(y>2);y&&(A[o++]=A[B++],y>1&&(A[o++]=A[B++]))}break}}break}}while(s>r&&l>o);y=m>>3,r-=y,m-=y<<3,w&=(1<r?5+(s-r):5-(r-s),e.avail_out=l>o?257+(l-o):257-(o-l),a.hold=w,a.bits=m}},{}],9:[function(e,t,i){"use strict";function n(e){return(e>>>24&255)+(e>>>8&65280)+((65280&e)<<8)+((255&e)<<24)}function a(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new k.Buf16(320),this.work=new k.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function r(e){var t;return e&&e.state?(t=e.state,e.total_in=e.total_out=t.total=0,e.msg="",t.wrap&&(e.adler=1&t.wrap),t.mode=F,t.last=0,t.havedict=0,t.dmax=32768,t.head=null,t.hold=0,t.bits=0,t.lencode=t.lendyn=new k.Buf32(bt),t.distcode=t.distdyn=new k.Buf32(wt),t.sane=1,t.back=-1,A):C}function s(e){var t;return e&&e.state?(t=e.state,t.wsize=0,t.whave=0,t.wnext=0,r(e)):C}function o(e,t){var i,n;return e&&e.state?(n=e.state,0>t?(i=0,t=-t):(i=(t>>4)+1,48>t&&(t&=15)),t&&(8>t||t>15)?C:(null!==n.window&&n.wbits!==t&&(n.window=null),n.wrap=i,n.wbits=t,s(e))):C}function f(e,t){var i,n;return e?(n=new a,e.state=n,n.window=null,i=o(e,t),i!==A&&(e.state=null),i):C}function l(e){return f(e,kt)}function d(e){if(gt){var t;for(w=new k.Buf32(512),m=new k.Buf32(32),t=0;144>t;)e.lens[t++]=8;for(;256>t;)e.lens[t++]=9;for(;280>t;)e.lens[t++]=7;for(;288>t;)e.lens[t++]=8;for(p(y,e.lens,0,288,w,0,e.work,{bits:9}),t=0;32>t;)e.lens[t++]=5;p(S,e.lens,0,32,m,0,e.work,{bits:5}),gt=!1}e.lencode=w,e.lenbits=9,e.distcode=m,e.distbits=5}function u(e,t,i,n){var a,r=e.state;return null===r.window&&(r.wsize=1<=r.wsize?(k.arraySet(r.window,t,i-r.wsize,r.wsize,0),r.wnext=0,r.whave=r.wsize):(a=r.wsize-r.wnext,a>n&&(a=n),k.arraySet(r.window,t,i-n,a,r.wnext),n-=a,n?(k.arraySet(r.window,t,i-n,n,0),r.wnext=n,r.whave=r.wsize):(r.wnext+=a,r.wnext===r.wsize&&(r.wnext=0),r.whavec;){if(0===f)break e;f--,h+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0),h=0,c=0,i.mode=D;break}if(i.flags=0,i.head&&(i.head.done=!1),!(1&i.wrap)||(((255&h)<<8)+(h>>8))%31){e.msg="incorrect header check",i.mode=ut;break}if((15&h)!==T){e.msg="unknown compression method",i.mode=ut;break}if(h>>>=4,c-=4,xt=(15&h)+8,0===i.wbits)i.wbits=xt;else if(xt>i.wbits){e.msg="invalid window size",i.mode=ut;break}i.dmax=1<c;){if(0===f)break e;f--,h+=a[s++]<>8&1),512&i.flags&&(Zt[0]=255&h,Zt[1]=h>>>8&255,i.check=_(i.check,Zt,2,0)),h=0,c=0,i.mode=U;case U:for(;32>c;){if(0===f)break e;f--,h+=a[s++]<>>8&255,Zt[2]=h>>>16&255,Zt[3]=h>>>24&255,i.check=_(i.check,Zt,4,0)),h=0,c=0,i.mode=L;case L:for(;16>c;){if(0===f)break e;f--,h+=a[s++]<>8),512&i.flags&&(Zt[0]=255&h,Zt[1]=h>>>8&255,i.check=_(i.check,Zt,2,0)),h=0,c=0,i.mode=H;case H:if(1024&i.flags){for(;16>c;){if(0===f)break e;f--,h+=a[s++]<>>8&255,i.check=_(i.check,Zt,2,0)),h=0,c=0}else i.head&&(i.head.extra=null);i.mode=M;case M:if(1024&i.flags&&(m=i.length,m>f&&(m=f),m&&(i.head&&(xt=i.head.extra_len-i.length,i.head.extra||(i.head.extra=new Array(i.head.extra_len)),k.arraySet(i.head.extra,a,s,m,xt)),512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,i.length-=m),i.length))break e;i.length=0,i.mode=K;case K:if(2048&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.name+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.name=null);i.length=0,i.mode=j;case j:if(4096&i.flags){if(0===f)break e;m=0;do xt=a[s+m++],i.head&&xt&&i.length<65536&&(i.head.comment+=String.fromCharCode(xt));while(xt&&f>m);if(512&i.flags&&(i.check=_(i.check,a,m,s)),f-=m,s+=m,xt)break e}else i.head&&(i.head.comment=null);i.mode=P;case P:if(512&i.flags){for(;16>c;){if(0===f)break e;f--,h+=a[s++]<>9&1,i.head.done=!0),e.adler=i.check=0,i.mode=G;break;case q:for(;32>c;){if(0===f)break e;f--,h+=a[s++]<>>=7&c,c-=7&c,i.mode=ft;break}for(;3>c;){if(0===f)break e;f--,h+=a[s++]<>>=1,c-=1,3&h){case 0:i.mode=W;break;case 1:if(d(i),i.mode=tt,t===Z){h>>>=2,c-=2;break e}break;case 2:i.mode=V;break;case 3:e.msg="invalid block type",i.mode=ut}h>>>=2,c-=2;break;case W:for(h>>>=7&c,c-=7&c;32>c;){if(0===f)break e;f--,h+=a[s++]<>>16^65535)){e.msg="invalid stored block lengths",i.mode=ut;break}if(i.length=65535&h,h=0,c=0,i.mode=J,t===Z)break e;case J:i.mode=Q;case Q:if(m=i.length){if(m>f&&(m=f),m>l&&(m=l),0===m)break e;k.arraySet(r,a,s,m,o),f-=m,s+=m,l-=m,o+=m,i.length-=m;break}i.mode=G;break;case V:for(;14>c;){if(0===f)break e;f--,h+=a[s++]<>>=5,c-=5,i.ndist=(31&h)+1,h>>>=5,c-=5,i.ncode=(15&h)+4,h>>>=4,c-=4,i.nlen>286||i.ndist>30){e.msg="too many length or distance symbols",i.mode=ut;break}i.have=0,i.mode=$;case $:for(;i.havec;){if(0===f)break e;f--,h+=a[s++]<>>=3,c-=3}for(;i.have<19;)i.lens[At[i.have++]]=0;if(i.lencode=i.lendyn,i.lenbits=7,St={bits:i.lenbits},yt=p(x,i.lens,0,19,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid code lengths set",i.mode=ut;break}i.have=0,i.mode=et;case et:for(;i.have>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,h+=a[s++]<gt)h>>>=mt,c-=mt,i.lens[i.have++]=gt;else{if(16===gt){for(Bt=mt+2;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=mt,c-=mt,0===i.have){e.msg="invalid bit length repeat",i.mode=ut;break}xt=i.lens[i.have-1],m=3+(3&h),h>>>=2,c-=2}else if(17===gt){for(Bt=mt+3;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=mt,c-=mt,xt=0,m=3+(7&h),h>>>=3,c-=3}else{for(Bt=mt+7;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=mt,c-=mt,xt=0,m=11+(127&h),h>>>=7,c-=7}if(i.have+m>i.nlen+i.ndist){e.msg="invalid bit length repeat",i.mode=ut;break}for(;m--;)i.lens[i.have++]=xt}}if(i.mode===ut)break;if(0===i.lens[256]){e.msg="invalid code -- missing end-of-block",i.mode=ut;break}if(i.lenbits=9,St={bits:i.lenbits},yt=p(y,i.lens,0,i.nlen,i.lencode,0,i.work,St),i.lenbits=St.bits,yt){e.msg="invalid literal/lengths set",i.mode=ut;break}if(i.distbits=6,i.distcode=i.distdyn,St={bits:i.distbits},yt=p(S,i.lens,i.nlen,i.ndist,i.distcode,0,i.work,St),i.distbits=St.bits,yt){e.msg="invalid distances set",i.mode=ut;break}if(i.mode=tt,t===Z)break e;case tt:i.mode=it;case it:if(f>=6&&l>=258){e.next_out=o,e.avail_out=l,e.next_in=s,e.avail_in=f,i.hold=h,i.bits=c,v(e,w),o=e.next_out,r=e.output,l=e.avail_out,s=e.next_in,a=e.input,f=e.avail_in,h=i.hold,c=i.bits,i.mode===G&&(i.back=-1);break}for(i.back=0;Et=i.lencode[h&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,h+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,h+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(h>>>=mt,c-=mt,i.back+=mt,i.length=gt,0===kt){i.mode=ot;break}if(32&kt){i.back=-1,i.mode=G;break}if(64&kt){e.msg="invalid literal/length code",i.mode=ut;break}i.extra=15&kt,i.mode=nt;case nt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}i.was=i.length,i.mode=at;case at:for(;Et=i.distcode[h&(1<>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=mt);){if(0===f)break e;f--,h+=a[s++]<>_t)],mt=Et>>>24,kt=Et>>>16&255,gt=65535&Et,!(c>=_t+mt);){if(0===f)break e;f--,h+=a[s++]<>>=_t,c-=_t,i.back+=_t}if(h>>>=mt,c-=mt,i.back+=mt,64&kt){e.msg="invalid distance code",i.mode=ut;break}i.offset=gt,i.extra=15&kt,i.mode=rt;case rt:if(i.extra){for(Bt=i.extra;Bt>c;){if(0===f)break e;f--,h+=a[s++]<>>=i.extra,c-=i.extra,i.back+=i.extra}if(i.offset>i.dmax){e.msg="invalid distance too far back",i.mode=ut;break}i.mode=st;case st:if(0===l)break e;if(m=w-l,i.offset>m){if(m=i.offset-m,m>i.whave&&i.sane){e.msg="invalid distance too far back",i.mode=ut;break}m>i.wnext?(m-=i.wnext,bt=i.wsize-m):bt=i.wnext-m,m>i.length&&(m=i.length),wt=i.window}else wt=r,bt=o-i.offset,m=i.length;m>l&&(m=l),l-=m,i.length-=m;do r[o++]=wt[bt++];while(--m);0===i.length&&(i.mode=it);break;case ot:if(0===l)break e;r[o++]=i.length,l--,i.mode=it;break;case ft:if(i.wrap){for(;32>c;){if(0===f)break e;f--,h|=a[s++]<c;){if(0===f)break e;f--,h+=a[s++]<=z;z++)M[z]=0;for(R=0;b>R;R++)M[t[c+R]]++;for(I=A,N=n;N>=1&&0===M[N];N--);if(I>N&&(I=N),0===N)return w[m++]=20971520,w[m++]=20971520,g.bits=1,0;for(C=1;N>C&&0===M[C];C++);for(C>I&&(I=C),F=1,z=1;n>=z;z++)if(F<<=1,F-=M[z],0>F)return-1;if(F>0&&(e===s||1!==N))return-1;for(K[1]=0,z=1;n>z;z++)K[z+1]=K[z]+M[z];for(R=0;b>R;R++)0!==t[c+R]&&(k[K[t[c+R]]++]=R);switch(e){case s:L=j=k,S=19;break;case o:L=l,H-=257,j=d,P-=257,S=256;break;default:L=u,j=h,S=-1}if(U=0,R=0,z=C,y=m,O=I,T=0,p=-1,D=1<a||e===f&&D>r)return 1;for(var q=0;;){q++,B=z-T,k[R]S?(E=j[P+k[R]],Z=L[H+k[R]]):(E=96,Z=0),_=1<>T)+v]=B<<24|E<<16|Z|0;while(0!==v);for(_=1<>=1;if(0!==_?(U&=_-1,U+=_):U=0,R++,0===--M[z]){if(z===N)break;z=t[c+k[R]]}if(z>I&&(U&x)!==p){for(0===T&&(T=I),y+=C,O=z-T,F=1<O+T&&(F-=M[O+T],!(0>=F));)O++,F<<=1;if(D+=1<a||e===f&&D>r)return 1;p=U&x,w[p]=I<<24|O<<16|y-m|0}}return 0!==U&&(w[y+U]=z-T<<24|64<<16|0),g.bits=I,0}},{"../utils/common":2}],11:[function(e,t){"use strict";t.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],12:[function(e,t){"use strict";function i(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}t.exports=i},{}]},{},[1])(1)});/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */ var saveAs=saveAs||"undefined"!=typeof navigator&&navigator.msSaveOrOpenBlob&&navigator.msSaveOrOpenBlob.bind(navigator)||function(e){"use strict";if("undefined"==typeof navigator||!/MSIE [1-9]\./.test(navigator.userAgent)){var t=e.document,n=function(){return e.URL||e.webkitURL||e},o=t.createElementNS("http://www.w3.org/1999/xhtml","a"),r="download"in o,i=function(n){var o=t.createEvent("MouseEvents");o.initMouseEvent("click",!0,!1,e,0,0,0,0,0,!1,!1,!1,!1,0,null),n.dispatchEvent(o)},a=e.webkitRequestFileSystem,c=e.requestFileSystem||a||e.mozRequestFileSystem,s=function(t){(e.setImmediate||e.setTimeout)(function(){throw t},0)},u="application/octet-stream",f=0,d=500,l=function(t){var o=function(){"string"==typeof t?n().revokeObjectURL(t):t.remove()};e.chrome?o():setTimeout(o,d)},v=function(e,t,n){t=[].concat(t);for(var o=t.length;o--;){var r=e["on"+t[o]];if("function"==typeof r)try{r.call(e,n||e)}catch(i){s(i)}}},p=function(t,s){var d,p,w,y=this,m=t.type,S=!1,h=function(){v(y,"writestart progress write writeend".split(" "))},O=function(){if((S||!d)&&(d=n().createObjectURL(t)),p)p.location.href=d;else{var o=e.open(d,"_blank");void 0==o&&"undefined"!=typeof safari&&(e.location.href=d)}y.readyState=y.DONE,h(),l(d)},b=function(e){return function(){return y.readyState!==y.DONE?e.apply(this,arguments):void 0}},g={create:!0,exclusive:!1};return y.readyState=y.INIT,s||(s="download"),r?(d=n().createObjectURL(t),o.href=d,o.download=s,i(o),y.readyState=y.DONE,h(),void l(d)):(/^\s*(?:text\/(?:plain|xml)|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(t.type)&&(t=new Blob(["",t],{type:t.type})),e.chrome&&m&&m!==u&&(w=t.slice||t.webkitSlice,t=w.call(t,0,t.size,u),S=!0),a&&"download"!==s&&(s+=".download"),(m===u||a)&&(p=e),c?(f+=t.size,void c(e.TEMPORARY,f,b(function(e){e.root.getDirectory("saved",g,b(function(e){var n=function(){e.getFile(s,g,b(function(e){e.createWriter(b(function(n){n.onwriteend=function(t){p.location.href=e.toURL(),y.readyState=y.DONE,v(y,"writeend",t),l(e)},n.onerror=function(){var e=n.error;e.code!==e.ABORT_ERR&&O()},"writestart progress write abort".split(" ").forEach(function(e){n["on"+e]=y["on"+e]}),n.write(t),y.abort=function(){n.abort(),y.readyState=y.DONE},y.readyState=y.WRITING}),O)}),O)};e.getFile(s,{create:!1},b(function(e){e.remove(),n()}),b(function(e){e.code===e.NOT_FOUND_ERR?n():O()}))}),O)}),O)):void O())},w=p.prototype,y=function(e,t){return new p(e,t)};return w.abort=function(){var e=this;e.readyState=e.DONE,v(e,"abort")},w.readyState=w.INIT=0,w.WRITING=1,w.DONE=2,w.error=w.onwritestart=w.onprogress=w.onwrite=w.onabort=w.onerror=w.onwriteend=null,y}}("undefined"!=typeof self&&self||"undefined"!=typeof window&&window||this.content);"undefined"!=typeof module&&module.exports?module.exports.saveAs=saveAs:"undefined"!=typeof define&&null!==define&&null!=define.amd&&define([],function(){return saveAs});/* canvas-toBlob.js * A canvas.toBlob() implementation.