From cbecc7910ce96955b4664d1455fec8c86a3e8c2a Mon Sep 17 00:00:00 2001 From: kangax Date: Sat, 9 Nov 2013 18:09:25 +0100 Subject: [PATCH] Fix vertical cursor movement in center/right -aligned and styled text --- component.json | 2 +- dist/all.js | 182 +++++++++++++++++++++++------ dist/all.min.js | 2 +- dist/all.min.js.gz | Bin 58542 -> 58899 bytes dist/all.require.js | 182 +++++++++++++++++++++++------ src/mixins/collection.mixin.js | 1 + src/mixins/itext_behavior.mixin.js | 181 ++++++++++++++++++++++------ 7 files changed, 443 insertions(+), 107 deletions(-) diff --git a/component.json b/component.json index 4d2c4db1..9586979c 100644 --- a/component.json +++ b/component.json @@ -2,7 +2,7 @@ "name": "fabric.js", "repo": "kangax/fabric.js", "description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.", - "version": "1.3.9", + "version": "1.3.10", "keywords": ["canvas", "graphic", "graphics", "SVG", "node-canvas", "parser", "HTML5", "object model"], "dependencies": {}, "development": {}, diff --git a/dist/all.js b/dist/all.js index ca444d90..03e8ae1a 100644 --- a/dist/all.js +++ b/dist/all.js @@ -1981,6 +1981,7 @@ fabric.Collection = { /** * 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} */ @@ -21162,20 +21163,76 @@ fabric.util.object.extend(fabric.Text.prototype, { * Gets start offset of a selection * @return {Number} */ - getSelectionStartOffset: function() { - var textBeforeCursor = this.text.slice(0, this.selectionStart); - var textAfterCursor = this.text.slice(this.selectionStart); + getDownCursorOffset: function(e) { - var textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1); - var textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\n?/)[1]; - var textOnNextLine = (textAfterCursor.match(/.*\n(.*)\n?/) || { })[1] || ''; + var textLines = this.text.split(this._reNewline), + _char, + lineLeftOffset, + foundMatch, - if (textOnSameLineBeforeCursor.length > textOnNextLine.length) { - return (textOnNextLine + textOnSameLineAfterCursor).length + 1; + textBeforeCursor = this.text.slice(0, this.selectionStart), + textAfterCursor = this.text.slice(this.selectionStart), + + textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1), + textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\n?/)[1], + textOnNextLine = (textAfterCursor.match(/.*\n(.*)\n?/) || { })[1] || '', + + cursorLocation = this.get2DCursorLocation(); + + // if on last line, down cursor goes to end of line + if (cursorLocation.lineIndex === textLines.length - 1 || e.metaKey) { + + // move to the end of a text + return this.text.length - this.selectionStart; } - else { - return (textOnSameLineBeforeCursor + textOnSameLineAfterCursor).length + 1; + + var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); + + var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; + var lineIndex = cursorLocation.lineIndex; + + for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { + _char = textOnSameLineBeforeCursor[i]; + widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); } + + var widthOfNextLine = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex + 1, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfNextLine); + var widthOfCharsOnNextLine = lineLeftOffset; + var indexOnNextLine = 0; + + lineIndex = cursorLocation.lineIndex + 1; + + for (var j = 0, jlen = textOnNextLine.length; j < jlen; j++) { + + _char = textOnNextLine[j]; + var widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); + + widthOfCharsOnNextLine += widthOfChar; + + if (widthOfCharsOnNextLine > widthOfCharsOnSameLineBeforeCursor) { + + foundMatch = true; + + var leftEdge = widthOfCharsOnNextLine - widthOfChar; + var rightEdge = widthOfCharsOnNextLine; + + var offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor); + var offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); + + indexOnNextLine = offsetFromRightEdge < offsetFromLeftEdge ? j + 1 : j; + + break; + } + } + + // reached end + if (!foundMatch) { + indexOnNextLine = textOnNextLine.length; + } + + return textOnSameLineAfterCursor.length + 1 + indexOnNextLine; }, /** @@ -21187,12 +21244,7 @@ fabric.util.object.extend(fabric.Text.prototype, { this.abortCursorAnimation(); this._currentCursorOpacity = 1; - var offset = this.getSelectionStartOffset(); - - if (e.metaKey) { - // move to the end of a text - offset = this.text.length - this.selectionStart; - } + var offset = this.getDownCursorOffset(e); if (e.shiftKey) { this.moveCursorDownWithShift(offset); @@ -21239,33 +21291,82 @@ fabric.util.object.extend(fabric.Text.prototype, { } }, + getUpCursorOffset: function(e) { + + var cursorLocation = this.get2DCursorLocation(); + + // if on first line, up cursor goes to start of line + if (cursorLocation.lineIndex === 0 || e.metaKey) { + return this.selectionStart; + } + + var textBeforeCursor = this.text.slice(0, this.selectionStart), + textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1), + textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || '', + textLines = this.text.split(this._reNewline), + _char, + lineLeftOffset, + foundMatch; + + var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); + + var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; + var lineIndex = cursorLocation.lineIndex; + + for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { + _char = textOnSameLineBeforeCursor[i]; + widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); + } + + var widthOfPreviousLine = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex - 1, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine); + var widthOfCharsOnPreviousLine = lineLeftOffset; + var indexOnPrevLine = 0; + + lineIndex = cursorLocation.lineIndex - 1; + + for (var j = 0, jlen = textOnPreviousLine.length; j < jlen; j++) { + + _char = textOnPreviousLine[j]; + var widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); + + widthOfCharsOnPreviousLine += widthOfChar; + + if (widthOfCharsOnPreviousLine > widthOfCharsOnSameLineBeforeCursor) { + + foundMatch = true; + + var leftEdge = widthOfCharsOnPreviousLine - widthOfChar; + var rightEdge = widthOfCharsOnPreviousLine; + + var offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor); + var offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); + + indexOnPrevLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1); + + break; + } + } + + // reached end + if (!foundMatch) { + indexOnPrevLine = textOnPreviousLine.length - 1; + } + + return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length; + }, + /** * Moves cursor up * @param {Event} e Event object */ moveCursorUp: function(e) { - var textBeforeCursor = this.text.slice(0, this.selectionStart); - this.abortCursorAnimation(); this._currentCursorOpacity = 1; - var textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1); - var textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || ''; - var offset; - - // only change cursor location if there's no selection at the moment - if (textOnSameLineBeforeCursor.length > textOnPreviousLine.length) { - offset = textOnSameLineBeforeCursor.length + 1; - } - else { - offset = textOnPreviousLine.length + 1; - } - - if (e.metaKey) { - // move to start of text - offset = this.selectionStart; - } + var offset = this.getUpCursorOffset(e); if (e.shiftKey) { this.moveCursorUpWithShift(offset); @@ -21635,10 +21736,16 @@ fabric.util.object.extend(fabric.Text.prototype, { width = lineLeftOffset; + if (this.flipX) { + // when oject is horizontally flipped we reverse chars + textLines[i] = textLines[i].split('').reverse().join(''); + } + for (var j = 0, jlen = textLines[i].length; j < jlen; j++) { var _char = textLines[i][j]; prevWidth = width; - width += this._getWidthOfChar(this.ctx, _char, i, j) * this.scaleX; + width += this._getWidthOfChar(this.ctx, _char, i, this.flipX ? jlen - j : j) * + this.scaleX; // debugging // var objectLeftTop = this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top'); @@ -21664,6 +21771,11 @@ fabric.util.object.extend(fabric.Text.prototype, { newSelectionStart = charIndex + i + 1; } + // 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; } diff --git a/dist/all.min.js b/dist/all.min.js index 5295f4cf..93820450 100644 --- a/dist/all.min.js +++ b/dist/all.min.js @@ -4,4 +4,4 @@ ._setActiveObject(e),this.renderAll(),this.fire("object:selected",{target:e,e:t}),e.fire("selected",{e:t}),this},getActiveObject:function(){return this._activeObject},_discardActiveObject:function(){this._activeObject&&this._activeObject.set("active",!1),this._activeObject=null},discardActiveObject:function(e){return this._discardActiveObject(),this.renderAll(),this.fire("selection:cleared",{e:e}),this},_setActiveGroup:function(e){this._activeGroup=e,e&&(e.canvas=this,e.set("active",!0))},setActiveGroup:function(e,t){return this._setActiveGroup(e),e&&(this.fire("object:selected",{target:e,e:t}),e.fire("selected",{e:t})),this},getActiveGroup:function(){return this._activeGroup},_discardActiveGroup:function(){var e=this.getActiveGroup();e&&e.destroy(),this.setActiveGroup(null)},discardActiveGroup:function(e){return this._discardActiveGroup(),this.fire("selection:cleared",{e:e}),this},deactivateAll:function(){var e=this.getObjects(),t=0,n=e.length;for(;t"},get:function(e){return this[e]},set:function(e,t){if(typeof e=="object")for(var n in e)this._set(n,e[n]);else typeof t=="function"&&e!=="clipTo"?this._set(e,t(this.get(e))):this._set(e,t);return this},_set:function(e,n){var i=e==="scaleX"||e==="scaleY";return i&&(n=this._constrainScale(n)),e==="scaleX"&&n<0?(this.flipX=!this.flipX,n*=-1):e==="scaleY"&&n<0?(this.flipY=!this.flipY,n*=-1):e==="width"||e==="height"?this.minScaleLimit=r(Math.min(.1,1/Math.max(this.width,this.height)),2):e==="shadow"&&n&&!(n instanceof t.Shadow)&&(n=new t.Shadow(n)),this[e]=n,this},toggle:function(e){var t=this.get(e);return typeof t=="boolean"&&this.set(e,!t),this},setSourcePath:function(e){return this.sourcePath=e,this},render:function(e,n){if(this.width===0||this.height===0||!this.visible)return;e.save(),this._transform(e,n),this._setStrokeStyles(e),this._setFillStyles(e);var r=this.transformMatrix;r&&this.group&&(e.translate(-this.group.width/2,-this.group.height/2),e.transform(r[0],r[1],r[2],r[3],r[4],r[5])),this._setShadow(e),this.clipTo&&t.util.clipContext(this,e),this._render(e,n),this.clipTo&&e.restore(),this._removeShadow(e),this.active&&!n&&(this.drawBorders(e),this.drawControls(e)),e.restore()},_transform:function(e,t){var n=this.transformMatrix;n&&!this.group&&e.setTransform(n[0],n[1],n[2],n[3],n[4],n[5]),t||this.transform(e)},_setStrokeStyles:function(e){this.stroke&&(e.lineWidth=this.strokeWidth,e.lineCap=this.strokeLineCap,e.lineJoin=this.strokeLineJoin,e.miterLimit=this.strokeMiterLimit,e.strokeStyle=this.stroke.toLive?this.stroke.toLive(e):this.stroke)},_setFillStyles:function(e){this.fill&&(e.fillStyle=this.fill.toLive?this.fill.toLive(e):this.fill)},_setShadow:function(e){if(!this.shadow)return;e.shadowColor=this.shadow.color,e.shadowBlur=this.shadow.blur,e.shadowOffsetX=this.shadow.offsetX,e.shadowOffsetY=this.shadow.offsetY},_removeShadow:function(e){e.shadowColor="",e.shadowBlur=e.shadowOffsetX=e.shadowOffsetY=0},_renderFill:function(e){if(!this.fill)return;this.fill.toLive&&(e.save(),e.translate(-this.width/2+this.fill.offsetX||0,-this.height/2+this.fill.offsetY||0)),e.fill(),this.fill.toLive&&e.restore(),this.shadow&&!this.shadow.affectStroke&&this._removeShadow(e)},_renderStroke:function(e){if(!this.stroke)return;e.save(),this.strokeDashArray?(1&this.strokeDashArray.length&&this.strokeDashArray.push.apply(this.strokeDashArray,this.strokeDashArray),o?(e.setLineDash(this.strokeDashArray),this._stroke&&this._stroke(e)):this._renderDashedStroke&&this._renderDashedStroke(e),e.stroke()):this._stroke?this._stroke(e):e.stroke(),this._removeShadow(e),e.restore()},clone:function(e,n){return this.constructor.fromObject?this.constructor.fromObject(this.toObject(n),e):new t.Object(this.toObject(n))},cloneAsImage:function(e){var n=this.toDataURL();return t.util.loadImage(n,function(n){e&&e(new t.Image(n))}),this},toDataURL:function(e){e||(e={});var n=t.util.createCanvasElement(),r=this.getBoundingRect();n.width=r.width,n.height=r.height,t.util.wrapElement(n,"div");var i=new t.Canvas(n);e.format==="jpg"&&(e.format="jpeg"),e.format==="jpeg"&&(i.backgroundColor="#fff");var s={active:this.get("active"),left:this.getLeft(),top:this.getTop()};this.set("active",!1),this.setPositionByOrigin(new t.Point(n.width/2,n.height/2),"center","center");var o=this.canvas;i.add(this);var u=i.toDataURL(e);return this.set(s).setCoords(),this.canvas=o,i.dispose(),i=null,u},isType:function(e){return this.type===e},complexity:function(){return 0},toJSON:function(e){return this.toObject(e)},setGradient:function(e,n){n||(n={});var r={colorStops:[]};r.type=n.type||(n.r1||n.r2?"radial":"linear"),r.coords={x1:n.x1,y1:n.y1,x2:n.x2,y2:n.y2};if(n.r1||n.r2)r.coords.r1=n.r1,r.coords.r2=n.r2;for(var i in n.colorStops){var s=new t.Color(n.colorStops[i]);r.colorStops.push({offset:i,color:s.toRgb(),opacity:s.getAlpha()})}return this.set(e,t.Gradient.forObject(this,r))},setPatternFill:function(e){return this.set("fill",new t.Pattern(e))},setShadow:function(e){return this.set("shadow",new t.Shadow(e))},setColor:function(e){return this.set("fill",e),this},centerH:function(){return this.canvas.centerObjectH(this),this},centerV:function(){return this.canvas.centerObjectV(this),this},center:function(){return this.centerH().centerV()},remove:function(){return this.canvas.remove(this)},sendToBack:function(){return this.group?t.StaticCanvas.prototype.sendToBack.call(this.group,this):this.canvas.sendToBack(this),this},bringToFront:function(){return this.group?t.StaticCanvas.prototype.bringToFront.call(this.group,this):this.canvas.bringToFront(this),this},sendBackwards:function(e){return this.group?t.StaticCanvas.prototype.sendBackwards.call(this.group,this,e):this.canvas.sendBackwards(this,e),this},bringForward:function(e){return this.group?t.StaticCanvas.prototype.bringForward.call(this.group,this,e):this.canvas.bringForward(this,e),this},moveTo:function(e){return this.group?t.StaticCanvas.prototype.moveTo.call(this.group,this,e):this.canvas.moveTo(this,e),this}}),t.util.createAccessors(t.Object),t.Object.prototype.rotate=t.Object.prototype.setAngle,n(t.Object.prototype,t.Observable),t.Object.NUM_FRACTION_DIGITS=2,t.Object.__uid=0}(typeof exports!="undefined"?exports:this),function(){var e=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{translateToCenterPoint:function(t,n,r){var i=t.x,s=t.y;return n==="left"?i=t.x+(this.getWidth()+this.strokeWidth*this.scaleX)/2:n==="right"&&(i=t.x-(this.getWidth()+this.strokeWidth*this.scaleX)/2),r==="top"?s=t.y+(this.getHeight()+this.strokeWidth*this.scaleY)/2:r==="bottom"&&(s=t.y-(this.getHeight()+this.strokeWidth*this.scaleY)/2),fabric.util.rotatePoint(new fabric.Point(i,s),t,e(this.angle))},translateToOriginPoint:function(t,n,r){var i=t.x,s=t.y;return n==="left"?i=t.x-(this.getWidth()+this.strokeWidth*this.scaleX)/2:n==="right"&&(i=t.x+(this.getWidth()+this.strokeWidth*this.scaleX)/2),r==="top"?s=t.y-(this.getHeight()+this.strokeWidth*this.scaleY)/2:r==="bottom"&&(s=t.y+(this.getHeight()+this.strokeWidth*this.scaleY)/2),fabric.util.rotatePoint(new fabric.Point(i,s),t,e(this.angle))},getCenterPoint:function(){var e=new fabric.Point(this.left,this.top);return this.translateToCenterPoint(e,this.originX,this.originY)},getPointByOrigin:function(e,t){var n=this.getCenterPoint();return this.translateToOriginPoint(n,e,t)},toLocalPoint:function(t,n,r){var i=this.getCenterPoint(),s,o;return n!==undefined&&r!==undefined?(n==="left"?s=i.x-(this.getWidth()+this.strokeWidth*this.scaleX)/2:n==="right"?s=i.x+(this.getWidth()+this.strokeWidth*this.scaleX)/2:s=i.x,r==="top"?o=i.y-(this.getHeight()+this.strokeWidth*this.scaleY)/2:r==="bottom"?o=i.y+(this.getHeight()+this.strokeWidth*this.scaleY)/2:o=i.y):(s=this.left,o=this.top),fabric.util.rotatePoint(new fabric.Point(t.x,t.y),i,-e(this.angle)).subtractEquals(new fabric.Point(s,o))},setPositionByOrigin:function(e,t,n){var r=this.translateToCenterPoint(e,t,n),i=this.translateToOriginPoint(r,this.originX,this.originY);this.set("left",i.x),this.set("top",i.y)},adjustPosition:function(t){var n=e(this.angle),r=this.getWidth()/2,i=Math.cos(n)*r,s=Math.sin(n)*r,o=this.getWidth(),u=Math.cos(n)*o,a=Math.sin(n)*o;this.originX==="center"&&t==="left"||this.originX==="right"&&t==="center"?(this.left-=i,this.top-=s):this.originX==="left"&&t==="center"||this.originX==="center"&&t==="right"?(this.left+=i,this.top+=s):this.originX==="left"&&t==="right"?(this.left+=u,this.top+=a):this.originX==="right"&&t==="left"&&(this.left-=u,this.top-=a),this.setCoords(),this.originX=t},_getLeftTopCoords:function(){return this.translateToOriginPoint(this.getCenterPoint(),"left","center")}})}(),function(){var e=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{oCoords:null,intersectsWithRect:function(e,t){var n=this.oCoords,r=new fabric.Point(n.tl.x,n.tl.y),i=new fabric.Point(n.tr.x,n.tr.y),s=new fabric.Point(n.bl.x,n.bl.y),o=new fabric.Point(n.br.x,n.br.y),u=fabric.Intersection.intersectPolygonRectangle([r,i,o,s],e,t);return u.status==="Intersection"},intersectsWithObject:function(e){function t(e){return{tl:new fabric.Point(e.tl.x,e.tl.y),tr:new fabric.Point(e.tr.x,e.tr.y),bl:new fabric.Point(e.bl.x,e.bl.y),br:new fabric.Point(e.br.x,e.br.y)}}var n=t(this.oCoords),r=t(e.oCoords),i=fabric.Intersection.intersectPolygonPolygon([n.tl,n.tr,n.br,n.bl],[r.tl,r.tr,r.br,r.bl]);return i.status==="Intersection"},isContainedWithinObject:function(e){var t=e.getBoundingRect(),n=new fabric.Point(t.left,t.top),r=new fabric.Point(t.left+t.width,t.top+t.height);return this.isContainedWithinRect(n,r)},isContainedWithinRect:function(e,t){var n=this.getBoundingRect();return n.left>e.x&&n.left+n.widthe.y&&n.top+n.height=e.y&&f.d.y>=e.y)continue;f.o.x===f.d.x&&f.o.x>=e.x?(o=f.o.x,u=e.y):(n=0,r=(f.d.y-f.o.y)/(f.d.x-f.o.x),i=e.y-n*e.x,s=f.o.y-r*f.o.x,o=-(i-s)/(n-r),u=i+n*o),o>=e.x&&(a+=1);if(a===2)break}return a},getBoundingRectWidth:function(){return this.getBoundingRect().width},getBoundingRectHeight:function(){return this.getBoundingRect().height},getBoundingRect:function(){this.oCoords||this.setCoords();var e=[this.oCoords.tl.x,this.oCoords.tr.x,this.oCoords.br.x,this.oCoords.bl.x],t=fabric.util.array.min(e),n=fabric.util.array.max(e),r=Math.abs(t-n),i=[this.oCoords.tl.y,this.oCoords.tr.y,this.oCoords.br.y,this.oCoords.bl.y],s=fabric.util.array.min(i),o=fabric.util.array.max(i),u=Math.abs(s-o);return{left:t,top:s,width:r,height:u}},getWidth:function(){return this.width*this.scaleX},getHeight:function(){return this.height*this.scaleY},_constrainScale:function(e){return Math.abs(e)1?this.strokeWidth:0,n=this.padding,r=e(this.angle);this.currentWidth=(this.width+t)*this.scaleX+n*2,this.currentHeight=(this.height+t)*this.scaleY+n*2,this.currentWidth<0&&(this.currentWidth=Math.abs(this.currentWidth));var i=Math.sqrt(Math.pow(this.currentWidth/2,2)+Math.pow(this.currentHeight/2,2)),s=Math.atan(isFinite(this.currentHeight/this.currentWidth)?this.currentHeight/this.currentWidth:0),o=Math.cos(s+r)*i,u=Math.sin(s+r)*i,a=Math.sin(r),f=Math.cos(r),l=this.getCenterPoint(),c={x:l.x-o,y:l.y-u},h={x:c.x+this.currentWidth*f,y:c.y+this.currentWidth*a},p={x:h.x-this.currentHeight*a,y:h.y+this.currentHeight*f},d={x:c.x-this.currentHeight*a,y:c.y+this.currentHeight*f},v={x:c.x-this.currentHeight/2*a,y:c.y+this.currentHeight/2*f},m={x:c.x+this.currentWidth/2*f,y:c.y+this.currentWidth/2*a},g={x:h.x-this.currentHeight/2*a,y:h.y+this.currentHeight/2*f},y={x:d.x+this.currentWidth/2*f,y:d.y+this.currentWidth/2*a},b={x:m.x,y:m.y};return this.oCoords={tl:c,tr:h,br:p,bl:d,ml:v,mt:m,mr:g,mb:y,mtr:b},this._setCornerCoords&&this._setCornerCoords(),this}})}(),fabric.util.object.extend(fabric.Object.prototype,{hasStateChanged:function(){return this.stateProperties.some(function(e){return this.get(e)!==this.originalState[e]},this)},saveState:function(e){return this.stateProperties.forEach(function(e){this.originalState[e]=this.get(e)},this),e&&e.stateProperties&&e.stateProperties.forEach(function(e){this.originalState[e]=this.get(e)},this),this},setupState:function(){return this.originalState={},this.saveState(),this}}),function(){var e=fabric.util.getPointer,t=fabric.util.degreesToRadians;fabric.util.object.extend(fabric.Object.prototype,{_controlsVisibility:null,_findTargetCorner:function(t,n){if(!this.hasControls||!this.active)return!1;var r=e(t,this.canvas.upperCanvasEl),i=r.x-n.left,s=r.y-n.top,o,u;for(var a in this.oCoords){if(!this.isControlVisible(a))continue;if(a==="mtr"&&!this.hasRotatingPoint)continue;if(!(!this.get("lockUniScaling")||a!=="mt"&&a!=="mr"&&a!=="mb"&&a!=="ml"))continue;u=this._getImageLines(this.oCoords[a].corner),o=this._findCrossPoints({x:i,y:s},u);if(o!==0&&o%2===1)return this.__corner=a,a}return!1},_setCornerCoords:function(){var e=this.oCoords,n=t(this.angle),r=t(45-this.angle),i=Math.sqrt(2*Math.pow(this.cornerSize,2))/2,s=i*Math.cos(r),o=i*Math.sin(r),u=Math.sin(n),a=Math.cos(n);e.tl.corner={tl:{x:e.tl.x-o,y:e.tl.y-s},tr:{x:e.tl.x+s,y:e.tl.y-o},bl:{x:e.tl.x-s,y:e.tl.y+o},br:{x:e.tl.x+o,y:e.tl.y+s}},e.tr.corner={tl:{x:e.tr.x-o,y:e.tr.y-s},tr:{x:e.tr.x+s,y:e.tr.y-o},br:{x:e.tr.x+o,y:e.tr.y+s},bl:{x:e.tr.x-s,y:e.tr.y+o}},e.bl.corner={tl:{x:e.bl.x-o,y:e.bl.y-s},bl:{x:e.bl.x-s,y:e.bl.y+o},br:{x:e.bl.x+o,y:e.bl.y+s},tr:{x:e.bl.x+s,y:e.bl.y-o}},e.br.corner={tr:{x:e.br.x+s,y:e.br.y-o},bl:{x:e.br.x-s,y:e.br.y+o},br:{x:e.br.x+o,y:e.br.y+s},tl:{x:e.br.x- o,y:e.br.y-s}},e.ml.corner={tl:{x:e.ml.x-o,y:e.ml.y-s},tr:{x:e.ml.x+s,y:e.ml.y-o},bl:{x:e.ml.x-s,y:e.ml.y+o},br:{x:e.ml.x+o,y:e.ml.y+s}},e.mt.corner={tl:{x:e.mt.x-o,y:e.mt.y-s},tr:{x:e.mt.x+s,y:e.mt.y-o},bl:{x:e.mt.x-s,y:e.mt.y+o},br:{x:e.mt.x+o,y:e.mt.y+s}},e.mr.corner={tl:{x:e.mr.x-o,y:e.mr.y-s},tr:{x:e.mr.x+s,y:e.mr.y-o},bl:{x:e.mr.x-s,y:e.mr.y+o},br:{x:e.mr.x+o,y:e.mr.y+s}},e.mb.corner={tl:{x:e.mb.x-o,y:e.mb.y-s},tr:{x:e.mb.x+s,y:e.mb.y-o},bl:{x:e.mb.x-s,y:e.mb.y+o},br:{x:e.mb.x+o,y:e.mb.y+s}},e.mtr.corner={tl:{x:e.mtr.x-o+u*this.rotatingPointOffset,y:e.mtr.y-s-a*this.rotatingPointOffset},tr:{x:e.mtr.x+s+u*this.rotatingPointOffset,y:e.mtr.y-o-a*this.rotatingPointOffset},bl:{x:e.mtr.x-s+u*this.rotatingPointOffset,y:e.mtr.y+o-a*this.rotatingPointOffset},br:{x:e.mtr.x+o+u*this.rotatingPointOffset,y:e.mtr.y+s-a*this.rotatingPointOffset}}},drawBorders:function(e){if(!this.hasBorders)return this;var t=this.padding,n=t*2,r=~~(this.strokeWidth/2)*2;e.save(),e.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,e.strokeStyle=this.borderColor;var i=1/this._constrainScale(this.scaleX),s=1/this._constrainScale(this.scaleY);e.lineWidth=1/this.borderScaleFactor,e.scale(i,s);var o=this.getWidth(),u=this.getHeight();e.strokeRect(~~(-(o/2)-t-r/2*this.scaleX)-.5,~~(-(u/2)-t-r/2*this.scaleY)-.5,~~(o+n+r*this.scaleX)+1,~~(u+n+r*this.scaleY)+1);if(this.hasRotatingPoint&&this.isControlVisible("mtr")&&!this.get("lockRotation")&&this.hasControls){var a=(this.flipY?u+r*this.scaleY+t*2:-u-r*this.scaleY-t*2)/2;e.beginPath(),e.moveTo(0,a),e.lineTo(0,a+(this.flipY?this.rotatingPointOffset:-this.rotatingPointOffset)),e.closePath(),e.stroke()}return e.restore(),this},drawControls:function(e){if(!this.hasControls)return this;var t=this.cornerSize,n=t/2,r=~~(this.strokeWidth/2),i=-(this.width/2),s=-(this.height/2),o,u,a=t/this.scaleX,f=t/this.scaleY,l=this.padding/this.scaleX,c=this.padding/this.scaleY,h=n/this.scaleY,p=n/this.scaleX,d=(n-t)/this.scaleX,v=(n-t)/this.scaleY,m=this.height,g=this.width,y=this.transparentCorners?"strokeRect":"fillRect",b=this.transparentCorners,w=typeof G_vmlCanvasManager!="undefined";return e.save(),e.lineWidth=1/Math.max(this.scaleX,this.scaleY),e.globalAlpha=this.isMoving?this.borderOpacityWhenMoving:1,e.strokeStyle=e.fillStyle=this.cornerColor,this.isControlVisible("tl")&&(o=i-p-r-l,u=s-h-r-c,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),this.isControlVisible("tr")&&(o=i+g-p+r+l,u=s-h-r-c,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),this.isControlVisible("bl")&&(o=i-p-r-l,u=s+m+v+r+c,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),this.isControlVisible("br")&&(o=i+g+d+r+l,u=s+m+v+r+c,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),this.get("lockUniScaling")||(this.isControlVisible("mt")&&(o=i+g/2-p,u=s-h-r-c,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),this.isControlVisible("mb")&&(o=i+g/2-p,u=s+m+v+r+c,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),this.isControlVisible("mr")&&(o=i+g+d+r+l,u=s+m/2-h,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),this.isControlVisible("ml")&&(o=i-p-r-l,u=s+m/2-h,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f))),this.hasRotatingPoint&&this.isControlVisible("mtr")&&(o=i+g/2-p,u=this.flipY?s+m+this.rotatingPointOffset/this.scaleY-f/2+r+c:s-this.rotatingPointOffset/this.scaleY-f/2-r-c,w||b||e.clearRect(o,u,a,f),e[y](o,u,a,f)),e.restore(),this},isControlVisible:function(e){return this._getControlsVisibility()[e]},setControlVisible:function(e,t){return this._getControlsVisibility()[e]=t,this},setControlsVisibility:function(e){e||(e={});for(var t in e)this.setControlVisible(t,e[t]);return this},_getControlsVisibility:function(){return this._controlsVisibility||(this._controlsVisibility={tl:!0,tr:!0,br:!0,bl:!0,ml:!0,mt:!0,mr:!0,mb:!0,mtr:!0}),this._controlsVisibility}})}(),fabric.util.object.extend(fabric.StaticCanvas.prototype,{FX_DURATION:500,fxCenterObjectH:function(e,t){t=t||{};var n=function(){},r=t.onComplete||n,i=t.onChange||n,s=this;return fabric.util.animate({startValue:e.get("left"),endValue:this.getCenter().left,duration:this.FX_DURATION,onChange:function(t){e.set("left",t),s.renderAll(),i()},onComplete:function(){e.setCoords(),r()}}),this},fxCenterObjectV:function(e,t){t=t||{};var n=function(){},r=t.onComplete||n,i=t.onChange||n,s=this;return fabric.util.animate({startValue:e.get("top"),endValue:this.getCenter().top,duration:this.FX_DURATION,onChange:function(t){e.set("top",t),s.renderAll(),i()},onComplete:function(){e.setCoords(),r()}}),this},fxRemove:function(e,t){t=t||{};var n=function(){},r=t.onComplete||n,i=t.onChange||n,s=this;return fabric.util.animate({startValue:e.get("opacity"),endValue:0,duration:this.FX_DURATION,onStart:function(){e.set("active",!1)},onChange:function(t){e.set("opacity",t),s.renderAll(),i()},onComplete:function(){s.remove(e),r()}}),this}}),fabric.util.object.extend(fabric.Object.prototype,{animate:function(){if(arguments[0]&&typeof arguments[0]=="object"){var e=[],t,n;for(t in arguments[0])e.push(t);for(var r=0,i=e.length;r'),e?e(t.join("")):t.join("")},complexity:function(){return 1}}),t.Line.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("x1 y1 x2 y2".split(" ")),t.Line.fromElement=function(e,r){var i=t.parseAttributes(e,t.Line.ATTRIBUTE_NAMES),s=[i.x1||0,i.y1||0,i.x2||0,i.y2||0];return new t.Line(s,n(i,r))},t.Line.fromObject=function(e){var n=[e.x1,e.y1,e.x2,e.y2];return new t.Line(n,e)}}(typeof exports!="undefined"?exports:this),function(e){"use strict";function i(e){return"radius"in e&&e.radius>0}var t=e.fabric||(e.fabric={}),n=Math.PI*2,r=t.util.object.extend;if(t.Circle){t.warn("fabric.Circle is already defined.");return}t.Circle=t.util.createClass(t.Object,{type:"circle",initialize:function(e){e=e||{},this.set("radius",e.radius||0),this.callSuper("initialize",e)},_set:function(e,t){return this.callSuper("_set",e,t),e==="radius"&&this.setRadius(t),this},toObject:function(e){return r(this.callSuper("toObject",e),{radius:this.get("radius")})},toSVG:function(e){var t=this._createBaseSVGMarkup();return t.push("'),e?e(t.join("")):t.join("")},_render:function(e,t){e.beginPath(),e.globalAlpha=this.group?e.globalAlpha*this.opacity:this.opacity,e.arc(t?this.left:0,t?this.top:0,this.radius,0,n,!1),e.closePath(),this._renderFill(e),this._renderStroke(e)},getRadiusX:function(){return this.get("radius")*this.get("scaleX")},getRadiusY:function(){return this.get("radius")*this.get("scaleY")},setRadius:function(e){this.radius=e,this.set("width",e*2).set("height",e*2)},complexity:function(){return 1}}),t.Circle.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("cx cy r".split(" ")),t.Circle.fromElement=function(e,n){n||(n={});var s=t.parseAttributes(e,t.Circle.ATTRIBUTE_NAMES);if(!i(s))throw new Error("value of `r` attribute is required and can not be negative");"left"in s&&(s.left-=n.width/2||0),"top"in s&&(s.top-=n.height/2||0);var o=new t.Circle(r(s,n));return o.cx=parseFloat(e.getAttribute("cx"))||0,o.cy=parseFloat(e.getAttribute("cy"))||0,o},t.Circle.fromObject=function(e){return new t.Circle(e)}}(typeof exports!="undefined"?exports:this),function(e){"use strict";var t=e.fabric||(e.fabric={});if(t.Triangle){t.warn("fabric.Triangle is already defined");return}t.Triangle=t.util.createClass(t.Object,{type:"triangle",initialize:function(e){e=e||{},this.callSuper("initialize",e),this.set("width",e.width||100).set("height",e.height||100)},_render:function(e){var t=this.width/2,n=this.height/2;e.beginPath(),e.moveTo(-t,n),e.lineTo(0,-n),e.lineTo(t,n),e.closePath(),this._renderFill(e),this._renderStroke(e)},_renderDashedStroke:function(e){var n=this.width/2,r=this.height/2;e.beginPath(),t.util.drawDashedLine(e,-n,r,0,-r,this.strokeDashArray),t.util.drawDashedLine(e,0,-r,n,r,this.strokeDashArray),t.util.drawDashedLine(e,n,r,-n,r,this.strokeDashArray),e.closePath()},toSVG:function(e){var t=this._createBaseSVGMarkup(),n=this.width/2,r=this.height/2,i=[-n+" "+r,"0 "+ -r,n+" "+r].join(",");return t.push("'),e?e(t.join("")):t.join("")},complexity:function(){return 1}}),t.Triangle.fromObject=function(e){return new t.Triangle(e)}}(typeof exports!="undefined"?exports:this),function(e){"use strict";var t=e.fabric||(e.fabric={}),n=Math.PI*2,r=t.util.object.extend;if(t.Ellipse){t.warn("fabric.Ellipse is already defined.");return}t.Ellipse=t.util.createClass(t.Object,{type:"ellipse",rx:0,ry:0,initialize:function(e){e=e||{},this.callSuper("initialize",e),this.set("rx",e.rx||0),this.set("ry",e.ry||0),this.set("width",this.get("rx")*2),this.set("height",this.get("ry")*2)},toObject:function(e){return r(this.callSuper("toObject",e),{rx:this.get("rx"),ry:this.get("ry")})},toSVG:function(e){var t=this._createBaseSVGMarkup();return t.push("'),e?e(t.join("")):t.join("")},render:function(e,t){if(this.rx===0||this.ry===0)return;return this.callSuper("render",e,t)},_render:function(e,t){e.beginPath(),e.save(),e.globalAlpha=this.group?e.globalAlpha*this.opacity:this.opacity,this.transformMatrix&&this.group&&e.translate(this.cx,this.cy),e.transform(1,0,0,this.ry/this.rx,0,0),e.arc(t?this.left:0,t?this.top:0,this.rx,0,n,!1),this._renderFill(e),this._renderStroke(e),e.restore()},complexity:function(){return 1}}),t.Ellipse.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("cx cy rx ry".split(" ")),t.Ellipse.fromElement=function(e,n){n||(n={});var i=t.parseAttributes(e,t.Ellipse.ATTRIBUTE_NAMES),s=i.left,o=i.top;"left"in i&&(i.left-=n.width/2||0),"top"in i&&(i.top-=n.height/2||0);var u=new t.Ellipse(r(i,n));return u.cx=s||0,u.cy=o||0,u},t.Ellipse.fromObject=function(e){return new t.Ellipse(e)}}(typeof exports!="undefined"?exports:this),function(e){"use strict";function i(e){return e.left=e.left||0,e.top=e.top||0,e}var t=e.fabric||(e.fabric={}),n=t.util.object.extend;if(t.Rect){console.warn("fabric.Rect is already defined");return}var r=t.Object.prototype.stateProperties.concat();r.push("rx","ry","x","y"),t.Rect=t.util.createClass(t.Object,{stateProperties:r,type:"rect",rx:0,ry:0,x:0,y:0,strokeDashArray:null,initialize:function(e){e=e||{},this.callSuper("initialize",e),this._initRxRy(),this.x=e.x||0,this.y=e.y||0},_initRxRy:function(){this.rx&&!this.ry?this.ry=this.rx:this.ry&&!this.rx&&(this.rx=this.ry)},_render:function(e){var t=this.rx||0,n=this.ry||0,r=-this.width/2,i=-this.height/2,s=this.width,o=this.height,u=this.group&&this.group.type!=="group";e.beginPath(),e.globalAlpha=u?e.globalAlpha*this.opacity:this.opacity,this.transformMatrix&&u&&e.translate(this.width/2+this.x,this.height/2+this.y),!this.transformMatrix&&u&&e.translate(-this.group.width/2+this.width/2+this.x,-this.group.height/2+this.height/2+this.y);var a=t!==0||n!==0;e.moveTo(r+t,i),e.lineTo(r+s-t,i),a&&e.quadraticCurveTo(r+s,i,r+s,i+n,r+s,i+n),e.lineTo(r+s,i+o-n),a&&e.quadraticCurveTo(r+s,i+o,r+s-t,i+o,r+s-t,i+o),e.lineTo(r+t,i+o),a&&e.quadraticCurveTo(r,i+o,r,i+o-n,r,i+o-n),e.lineTo(r,i+n),a&&e.quadraticCurveTo(r,i,r+t,i,r+t,i),e.closePath(),this._renderFill(e),this._renderStroke(e)},_renderDashedStroke:function(e){var n=-this.width/2,r=-this.height/2,i=this.width,s=this.height;e.beginPath(),t.util.drawDashedLine(e,n,r,n+i,r,this.strokeDashArray),t.util.drawDashedLine(e,n+i,r,n+i,r+s,this.strokeDashArray),t.util.drawDashedLine(e,n+i,r+s,n,r+s,this.strokeDashArray),t.util.drawDashedLine(e,n,r+s,n,r,this.strokeDashArray),e.closePath()},_normalizeLeftTopProperties:function(e){return"left"in e&&this.set("left",e.left+this.getWidth()/2),this.set("x",e.left||0),"top"in e&&this.set("top",e.top+this.getHeight()/2),this.set("y",e.top||0),this},toObject:function(e){var t=n(this.callSuper("toObject",e),{rx:this.get("rx")||0,ry:this.get("ry")||0,x:this.get("x"),y:this.get("y")});return this.includeDefaultValues||this._removeDefaultValues(t),t},toSVG:function(e){var t=this._createBaseSVGMarkup();return t.push("'),e?e(t.join("")):t.join("")},complexity:function(){return 1}}),t.Rect.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("x y rx ry width height".split(" ")),t.Rect.fromElement=function(e,r){if(!e)return null;var s=t.parseAttributes(e,t.Rect.ATTRIBUTE_NAMES);s=i(s);var o=new t.Rect(n(r?t.util.object.clone(r):{},s));return o._normalizeLeftTopProperties(s),o},t.Rect.fromObject=function(e){return new t.Rect(e)}}(typeof exports!="undefined"?exports:this),function(e){"use strict";var t=e.fabric||(e.fabric={}),n=t.util.toFixed;if(t.Polyline){t.warn("fabric.Polyline is already defined");return}t.Polyline=t.util.createClass(t.Object,{type:"polyline",initialize:function(e,t,n){t=t||{},this.set("points",e),this.callSuper("initialize",t),this._calcDimensions(n)},_calcDimensions:function(e){return t.Polygon.prototype._calcDimensions.call(this,e)},toObject:function(e){return t.Polygon.prototype.toObject.call(this,e)},toSVG:function(e){var t=[],r=this._createBaseSVGMarkup();for(var i=0,s=this.points.length;i'),e?e(r.join("")):r.join("")},_render:function(e){var t;e.beginPath(),e.moveTo(this.points[0].x,this.points[0].y);for(var n=0,r=this.points.length;n'),e?e(n.join("")):n.join("")},_render:function(e){var t;e.beginPath(),e.moveTo(this.points[0].x,this.points[0].y);for(var n=0,r=this.points.length;n"},toObject:function(e){var t=s(this.callSuper("toObject",e),{path:this.path,pathOffset:this.pathOffset});return this.sourcePath&&(t.sourcePath=this.sourcePath),this.transformMatrix&&(t.transformMatrix=this.transformMatrix),t},toDatalessObject:function(e){var t=this.toObject(e);return this.sourcePath&&(t.path=this.sourcePath),delete t.sourcePath,t},toSVG:function(e){var t=[],n=this._createBaseSVGMarkup();for(var r=0,i=this.path.length;r',"",""),e?e(n.join("")):n.join("")},complexity:function(){return this.path.length},_parsePath:function(){var e=[],n=[],r,i,s=/(-?\.\d+)|(-?\d+(\.\d+)?)/g,o,u;for(var a=0,f,l=this.path.length;ad)for(var v=1,m=f.length;v"];for(var r=0,i=t.length;r"),e?e(n.join("")):n.join("")},toString:function(){return"#"},isSameColor:function(){var e=this.getObjects()[0].get("fill");return this.getObjects().every(function(t){return t.get("fill")===e})},complexity:function(){return this.paths.reduce(function(e,t){return e+(t&&t.complexity?t.complexity():0)},0)},getObjects:function(){return this.paths}}),t.PathGroup.fromObject=function(e,n){typeof e.paths=="string"?t.loadSVGFromURL(e.paths,function(r){var i=e.paths;delete e.paths;var s=t.util.groupSVGElements(r,e,i);n(s)}):t.util.enlivenObjects(e.paths,function(r){delete e.paths,n(new t.PathGroup(r,e))})},t.PathGroup.async=!0}(typeof exports!="undefined"?exports:this),function(e){"use strict";var t=e.fabric||(e.fabric={}),n=t.util.object.extend,r=t.util.array.min,i=t.util.array.max,s=t.util.array.invoke;if(t.Group)return;var o={lockMovementX:!0,lockMovementY:!0,lockRotation:!0,lockScalingX:!0,lockScalingY:!0,lockUniScaling:!0};t.Group=t.util.createClass(t.Object,t.Collection,{type:"group",initialize:function(e,t){t=t||{},this._objects=e||[];for(var r=this._objects.length;r--;)this._objects[r].group=this;this.originalState={},this.callSuper("initialize"),this._calcBounds(),this._updateObjectsCoords(),t&&n(this,t),this._setOpacityIfSame(),this.setCoords(!0),this.saveCoords()},_updateObjectsCoords:function(){var e=this.left,t=this.top;this.forEachObject(function(n){var r=n.get("left"),i=n.get("top");n.set("originalLeft",r),n.set("originalTop",i),n.set("left",r-e),n.set("top",i-t),n.setCoords(),n.__origHasControls=n.hasControls,n.hasControls=!1},this)},toString:function(){return"#"},addWithUpdate:function(e){return this._restoreObjectsState(),this._objects.push(e),e.group=this,this.forEachObject(function(e){e.set("active",!0),e.group=this},this),this._calcBounds(),this._updateObjectsCoords(),this},removeWithUpdate:function(e){return this._moveFlippedObject(e),this._restoreObjectsState(),this.forEachObject(function(e){e.set("active",!0),e.group=this},this),this.remove(e),this._calcBounds(),this._updateObjectsCoords(),this},_onObjectAdded:function(e){e.group=this},_onObjectRemoved:function(e){delete e.group,e.set("active",!1)},delegatedProperties:{fill:!0,opacity:!0,fontFamily:!0,fontWeight:!0,fontSize:!0,fontStyle:!0,lineHeight:!0,textDecoration:!0,textAlign:!0,backgroundColor:!0},_set:function(e,t){if(e in this.delegatedProperties){var n=this._objects.length;this[e]=t;while(n--)this._objects[n].set(e,t)}else this[e]=t},toObject:function(e){return n(this.callSuper("toObject",e),{objects:s(this._objects,"toObject",e)})},render:function(e,n){if(!this.visible)return;e.save(),this.transform(e);var r=Math.max(this.scaleX,this.scaleY);this.clipTo&&t.util.clipContext(this,e);for(var i=0,s=this._objects.length;i'];for(var n=0,r=this._objects.length;n"),e?e(t.join("")):t.join("")},get:function(e){if(e in o){if(this[e])return this[e];for(var t=0,n=this._objects.length;t','');if(this.stroke||this.strokeDashArray){var n=this.fill;this.fill=null,t.push("'),this.fill=n}return t.push(""),e?e(t.join("")):t.join("")},getSrc:function(){return this.getElement().src||this.getElement()._src},toString:function(){return'#'},clone:function(e,t){this.constructor.fromObject(this.toObject(t),e)},applyFilters:function(e){if(this.filters.length===0){this._element=this._originalElement,e&&e();return}var t=this._originalElement,n=fabric.util.createCanvasElement(),r=fabric.util.createImage(),i=this;return n.width=t.width,n.height=t.height,n.getContext("2d").drawImage(t,0,0,t.width,t.height),this.filters.forEach(function(e){e&&e.applyTo(n)}),r.width=t.width,r.height=t.height,fabric.isLikelyNode?(r.src=n.toBuffer(undefined,fabric.Image.pngCompression),i._element=r,e&&e()):(r.onload=function(){i._element=r,e&&e(),r.onload=n=t=null},r.src=n.toDataURL("image/png")),this},_render:function(e){e.drawImage(this._element,-this.width/2,-this.height/2,this.width,this.height)},_resetWidthHeight:function(){var e=this.getElement();this.set("width",e.width),this.set("height",e.height)},_initElement:function(e){this.setElement(fabric.util.getById(e)),fabric.util.addClass(this.getElement(),fabric.Image.CSS_CANVAS)},_initConfig:function(e){e||(e={}),this.setOptions(e),this._setWidthHeight(e),this._element.crossOrigin=this.crossOrigin},_initFilters:function(e,t){e.filters&&e.filters.length?fabric.util.enlivenObjects(e.filters,function(e){t&&t(e)},"fabric.Image.filters"):t&&t()},_setWidthHeight:function(e){this.width="width"in e?e.width:this.getElement().width||0,this.height="height"in e?e.height:this.getElement().height||0},complexity:function(){return 1}}),fabric.Image.CSS_CANVAS="canvas-img",fabric.Image.prototype.getSvgSrc=fabric.Image.prototype.getSrc,fabric.Image.fromObject=function(e,t){fabric.util.loadImage(e.src,function(n){fabric.Image.prototype._initFilters.call(e,e,function(r){e.filters=r||[];var i=new fabric.Image(n,e);t&&t(i)})},null,e.crossOrigin)},fabric.Image.fromURL=function(e,t,n){fabric.util.loadImage(e,function(e){t(new fabric.Image(e,n))},null,n&&n.crossOrigin)},fabric.Image.ATTRIBUTE_NAMES=fabric.SHARED_ATTRIBUTES.concat("x y width height xlink:href".split(" ")),fabric.Image.fromElement=function(e,n,r){var i=fabric.parseAttributes(e,fabric.Image.ATTRIBUTE_NAMES);fabric.Image.fromURL(i["xlink:href"],n,t(r?fabric.util.object.clone(r):{},i))},fabric.Image.async=!0,fabric.Image.pngCompression=1}(typeof exports!="undefined"?exports:this),fabric.util.object.extend(fabric.Object.prototype,{_getAngleValueForStraighten:function(){var e=this.getAngle()%360;return e>0?Math.round((e-1)/90)*90:Math.round(e/90)*90},straighten:function(){return this.setAngle(this._getAngleValueForStraighten()),this},fxStraighten:function(e){e=e||{};var t=function(){},n=e.onComplete||t,r=e.onChange||t,i=this;return fabric.util.animate({startValue:this.get("angle"),endValue:this._getAngleValueForStraighten(),duration:this.FX_DURATION,onChange:function(e){i.setAngle(e),r()},onComplete:function(){i.setCoords(),n()},onStart:function(){i.set("active",!1)}}),this}}),fabric.util.object.extend(fabric.StaticCanvas.prototype,{straightenObject:function(e){return e.straighten(),this.renderAll(),this},fxStraightenObject:function(e){return e.fxStraighten({onChange:this.renderAll.bind(this)}),this}}),fabric.Image.filters=fabric.Image.filters||{},fabric.Image.filters.BaseFilter=fabric.util.createClass({type:"BaseFilter",toObject:function(){return{type:this.type}},toJSON:function(){return this.toObject()}}),function(e){"use strict";var t=e.fabric||(e.fabric={}),n=t.util.object.extend;t.Image.filters.Brightness=t.util.createClass(t.Image.filters.BaseFilter,{type:"Brightness",initialize:function(e){e=e||{},this.brightness=e.brightness||100},applyTo:function(e){var t=e.getContext("2d"),n=t.getImageData(0,0,e.width,e.height),r=n.data,i=this.brightness;for(var s=0,o=r.length;s=0&&N=0&&C-1?e.channel:0},applyTo:function(e){if(!this.mask)return;var n=e.getContext("2d"),r=n.getImageData(0,0,e.width,e.height),i=r.data,s=this.mask.getElement(),o=t.util.createCanvasElement(),u=this.channel,a,f=r.width*r.height*4;o.width=s.width,o.height=s.height,o.getContext("2d").drawImage(s,0,0,s.width,s.height);var l=o.getContext("2d").getImageData(0,0,s.width,s.height),c=l.data;for(a=0;ao&&f>o&&l>o&&u(a-f)'},_render:function(e){var t=this.group&&this.group.type!=="group";t&&!this.transformMatrix?e.translate(-this.group.width/2+this.left,-this.group.height/2+this.top):t&&this.transformMatrix&&e.translate(-this.group.width/2,-this.group.height/2),typeof Cufon=="undefined"||this.useNative===!0?this._renderViaNative(e):this._renderViaCufon(e)},_renderViaNative:function(e){var n=this.text.split(this._reNewline);this.transform(e,t.isLikelyNode),this._setTextStyles(e),this.width=this._getTextWidth(e,n),this.height=this._getTextHeight(e,n),this.clipTo&&t.util.clipContext(this,e),this._renderTextBackground(e,n),this._translateForTextAlign(e),this._renderText(e,n),this.textAlign!=="left"&&this.textAlign!=="justify"&&e.restore(),this._renderTextDecoration(e,n),this.clipTo&&e.restore(),this._setBoundaries(e,n),this._totalLineHeight=0},_renderText:function(e,t){e.save(),this._setShadow(e),this._renderTextFill(e,t),this._renderTextStroke(e,t),this._removeShadow(e),e.restore()},_translateForTextAlign:function(e){this.textAlign!=="left"&&this.textAlign!=="justify"&&(e.save(),e.translate(this.textAlign==="center"?this.width/2:this.width,0))},_setBoundaries:function(e,t){this._boundaries=[];for(var n=0,r=t.length;nn&&(n=s)}return n},_renderChars:function(e,t,n,r,i){t[e](n,r,i)},_renderTextLine:function(e,t,n,r,i,s){i-=this.fontSize/4;if(this.textAlign!=="justify"){this._renderChars(e,t,n,r,i,s);return}var o=t.measureText(n).width,u=this.width;if(u>o){var a=n.split(/\s+/),f=t.measureText(n.replace(/\s+/g,"")).width,l=u-f,c=a.length-1,h=l/c,p=0;for(var d=0,v=a.length;d-1&&i(this.fontSize*this.lineHeight),this.textDecoration.indexOf("line-through")>-1&&i(this.fontSize*this.lineHeight-this.fontSize/2),this.textDecoration.indexOf("overline")>-1&&i(this.fontSize*this.lineHeight-this.fontSize)},_getFontDeclaration:function(){return[t.isLikelyNode?this.fontWeight:this.fontStyle,t.isLikelyNode?this.fontStyle:this.fontWeight,this.fontSize+"px",t.isLikelyNode?'"'+this.fontFamily+'"':this.fontFamily].join(" ")},render:function(e,t){if(!this.visible)return;e.save(),this._render(e),!t&&this.active&&(this.drawBorders(e),this.drawControls(e)),e.restore()},toObject:function(e){var t=n(this.callSuper("toObject",e),{text:this.text,fontSize:this.fontSize,fontWeight:this.fontWeight,fontFamily:this.fontFamily,fontStyle:this.fontStyle,lineHeight:this.lineHeight,textDecoration:this.textDecoration,textAlign:this.textAlign,path:this.path,textBackgroundColor:this.textBackgroundColor,useNative:this.useNative});return this.includeDefaultValues||this._removeDefaultValues(t),t},toSVG:function(e){var t=[],n=this.text.split(this._reNewline),r=this._getSVGLeftTopOffsets(n),i=this._getSVGTextAndBg(r.lineTop,r.textLeft,n),s=this._getSVGShadows(r.lineTop,n);return r.textTop+=this._fontAscent?this._fontAscent/5*this.lineHeight:0,this._wrapSVGTextAndBg(t,i,s,r),e?e(t.join("")):t.join("")},_getSVGLeftTopOffsets:function(e){var t=this.useNative?this.fontSize*this.lineHeight:-this._fontAscent-this._fontAscent/5*this.lineHeight,n=-(this.width/2),r=this.useNative?this.fontSize-1:this.height/2-e.length*this.fontSize-this._totalLineHeight;return{textLeft:n,textTop:r,lineTop:t}},_wrapSVGTextAndBg:function(e,t,n,r){e.push('',t.textBgRects.join(""),"',n.join(""),t.textSpans.join(""),"","")},_getSVGShadows:function(e,n){var r=[],s,o,u=1;if(!this.shadow||!this._boundaries)return r;for(s=0,o=n.length;s",t.util.string.escapeXml(n[s]),""),u=1}else u++;return r},_getSVGTextAndBg:function(e,t,n){var r=[],i=[],s=1;this._setSVGBg(i);for(var o=0,u=n.length;o",t.util.string.escapeXml(e),"")},_setSVGTextLineBg:function(e,t,n,r){e.push("')},_setSVGBg:function(e){this.backgroundColor&&this._boundaries&&e.push("')},_getFillAttributes:function(e){var n=e&&typeof e=="string"?new t.Color(e):"";return!n||!n.getSource()||n.getAlpha()===1?'fill="'+e+'"':'opacity="'+n.getAlpha()+'" fill="'+n.setAlpha(1).toRgb()+'"'},_set:function(e,t){e==="fontFamily"&&this.path&&(this.path=this.path.replace(/(.*?)([^\/]*)(\.font\.js)/,"$1"+t+"$3")),this.callSuper("_set",e,t),e in this._dimensionAffectingProps&&(this._initDimensions(),this.setCoords())},complexity:function(){return 1}}),t.Text.ATTRIBUTE_NAMES=t.SHARED_ATTRIBUTES.concat("x y font-family font-style font-weight font-size text-decoration".split(" ")),t.Text.fromElement=function(e,n){if(!e)return null;var r=t.parseAttributes(e,t.Text.ATTRIBUTE_NAMES);n=t.util.object.extend(n?t.util.object.clone(n):{},r);var i=new t.Text(e.textContent,n);return i.set({left:i.getLeft()+i.getWidth()/2,top:i.getTop()-i.getHeight()/2}),i},t.Text.fromObject=function(e){return new t.Text(e.text,r(e))},t.util.createAccessors(t.Text)}(typeof exports!="undefined"?exports:this),fabric.util.object.extend(fabric.Text.prototype,{_renderViaCufon:function(e){var t=Cufon.textOptions||(Cufon.textOptions={});t.left=this.left,t.top=this.top,t.context=e,t.color=this.fill;var n=this._initDummyElementForCufon();this.transform(e),Cufon.replaceElement(n,{engine:"canvas",separate:"none",fontFamily:this.fontFamily,fontWeight:this.fontWeight,textDecoration:this.textDecoration,textShadow:this.shadow&&this.shadow.toString(),textAlign:this.textAlign,fontStyle:this.fontStyle,lineHeight:this.lineHeight,stroke:this.stroke,strokeWidth:this.strokeWidth,backgroundColor:this.backgroundColor,textBackgroundColor:this.textBackgroundColor}),this.width=t.width,this.height=t.height,this._totalLineHeight=t.totalLineHeight,this._fontAscent=t.fontAscent,this._boundaries=t.boundaries,n=null,this.setCoords()},_initDummyElementForCufon:function(){var e=fabric.document.createElement("pre"),t=fabric.document.createElement("div");return t.appendChild(e),typeof G_vmlCanvasManager=="undefined"?e.innerHTML=this.text:e.innerText=this.text.replace(/\r?\n/gi,"\r"),e.style.fontSize=this.fontSize+"px",e.style.letterSpacing="normal",e}}),function(){var e=fabric.util.object.clone,t=fabric.util.toFixed;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,skipFillStrokeCheck:!0,_reSpace:/\s|\n/,_fontSizeFraction:4,_currentCursorOpacity:0,_selectionDirection:null,_abortCursorAnimation:!1,_charWidthsCache:{},initialize:function(e,t){this.styles=t.styles||{},this.callSuper("initialize",e,t),this.initBehavior(),fabric.IText.instances.push(this)},isEmptyStyles:function(){if(!this.styles)return!0;var e=this.styles;for(var t in e)for(var n in e[t])for(var r in e[t][n])return!1;return!0},setSelectionStart:function(e){this.selectionStart=e,this.hiddenTextarea&&(this.hiddenTextarea.selectionStart=e)},setSelectionEnd:function(e){this.selectionEnd=e,this.hiddenTextarea&&(this.hiddenTextarea.selectionEnd=e)},getSelectionStyles:function(){var e=this.get2DCursorLocation();return this.styles[e.lineIndex]?this.styles[e.lineIndex][e.charIndex]||{}:{}},setSelectionStyles:function(e){if(this.selectionStart===this.selectionEnd)this._extendStyles(this.selectionStart,e);else for(var t=this.selectionStart;t-1&&this._renderCharDecorationAtOffset(e,n,r+this.fontSize/this._fontSizeFraction,i,0),o.indexOf("line-through")>-1&&this._renderCharDecorationAtOffset(e,n,r+this.fontSize/this._fontSizeFraction,i,s/this._fontSizeFraction),o.indexOf("overline")>-1&&this._renderCharDecorationAtOffset(e,n,r,i,s-this.fontSize/this._fontSizeFraction)},_renderCharDecorationAtOffset:function(e,t,n,r,i){e.fillRect(t,n-i,r,1)},_renderTextLine:function(e,t,n,r,i,s){i+=this.fontSize/4,this.callSuper("_renderTextLine",e,t,n,r,i,s)},_renderTextDecoration:function(e,t){if(this.isEmptyStyles())return this.callSuper("_renderTextDecoration",e,t)},_renderTextLinesBackground:function(e,t){if(!this.textBackgroundColor&&!this.styles)return;e.save(),this.textBackgroundColor&&(e.fillStyle=this.textBackgroundColor);var n=0,r=this.fontSize/this._fontSizeFraction;for(var i=0,s=t.length;in&&(n=s)}return n},_getHeightOfLine:function(e,t,n){n=n||this.text.split(this._reNewline);var r=this._getHeightOfChar(e,n[t][0],t,0),i=n[t],s=i.split("");for(var o=1,u=s.length;or&&(r=a)}return r*this.lineHeight},_getTextHeight:function(e,t){var n=0;for(var r=0,i=t.length;r',fabric.util.string.escapeXml(a[d]),"");var y=this._getWidthOfChar(this.ctx,a[d],n,d);m.textBackgroundColor&&o.push(''),f+=y}}}),fabric.IText.fromObject=function(t){return new fabric.IText(t.text,e(t))},fabric.IText.instances=[]}(),function(){var e=fabric.util.object.clone;fabric.util.object.extend(fabric.IText.prototype,{initBehavior:function(){this.initKeyHandlers(),this.initCursorSelectionHandlers(),this.initDblClickSimulation(),this.initHiddenTextarea()},initKeyHandlers:function(){fabric.util.addListener(document,"keydown",this.onKeyDown.bind(this)),fabric.util.addListener(document,"keypress",this.onKeyPress.bind(this))},initHiddenTextarea:function(){if(!/(iPad|iPhone|iPod)/g.test(navigator.userAgent))return;this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.style.cssText="position: absolute; top: 0; left: -9999px",fabric.document.body.appendChild(this.hiddenTextarea)},initDblClickSimulation:function(){var e=+(new Date),t,n={},r;this.on("mousedown",function(i){var s=i.e;t=+(new Date),r=this.canvas.getPointer(s);var o=t-e<500&&n.x===r.x&&n.y===r.y;o&&(this.fire("dblclick",i),s.preventDefault&&s.preventDefault(),s.stopPropagation&&s.stopPropagation()),e=t,n=r})},initCursorSelectionHandlers:function(){this.initSelectedHandler(),this.initMousedownHandler(),this.initMousemoveHandler(),this.initMouseupHandler(),this.on("dblclick",function(e){this.selectWord(this.getSelectionStartFromPointer(e.e))})},initMousedownHandler:function(){this.on("mousedown",function(e){var t=this.canvas.getPointer(e.e);this.__mousedownX=t.x,this.__mousedownY=t.y,this.__isMousedown=!0,this.hiddenTextarea&&this.canvas&&this.canvas.wrapperEl.appendChild(this.hiddenTextarea),this.isEditing&&this.setCursorByClick(e.e)})},initMousemoveHandler:function(){this.on("mousemove",function(){this.__isMousedown&&this.isEditing&&console.log("mousemove: need to select text")})},initMouseupHandler:function(){this.on("mouseup",function(e){this.__isMousedown=!1;var t=this.canvas.getPointer(e.e),n=this.__mousedownX!==t.x||this.__mousedownY!==t.y;if(n)return;this.selected&&this.enterEditing()})},initSelectedHandler:function(){this.on("selected",function(){var e=this;setTimeout(function(){e.selected=!0},100),this._hasClearSelectionListener||(this.canvas.on("selection:cleared",function(t){if(t.e&&e.canvas.containsPoint(t.e,e))return;e.exitEditing()}),this._hasClearSelectionListener=!0)})},_tick:function(){var e=this;if(this._abortCursorAnimation)return;this.animate("_currentCursorOpacity",1,{duration:this.cursorDuration,onComplete:function(){e._onTickComplete()},onChange:function(){e.canvas&&e.canvas.renderAll()},abort:function(){return e._abortCursorAnimation}})},_onTickComplete:function(){if(this._abortCursorAnimation)return;var e=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1),this._cursorTimeout1=setTimeout(function(){e.animate("_currentCursorOpacity",0,{duration:this.cursorDuration/2,onComplete:function(){e._tick()},onChange:function(){e.canvas&&e.canvas.renderAll()},abort:function(){return e._abortCursorAnimation}})},100)},initDelayedCursor:function(){var e=this;this._cursorTimeout2&&clearTimeout(this._cursorTimeout2),this._cursorTimeout2=setTimeout(function(){e._abortCursorAnimation=!1,e._tick()},this.cursorDelay)},abortCursorAnimation:function(){this._abortCursorAnimation=!0,clearTimeout(this._cursorTimeout1),clearTimeout(this._cursorTimeout2),this._currentCursorOpacity=0,this.canvas&&this.canvas.renderAll();var e=this;setTimeout(function(){e._abortCursorAnimation=!1},10)},_keysMap:{8:"removeChars",13:"insertNewline",37:"moveCursorLeft",38:"moveCursorUp",39:"moveCursorRight",40:"moveCursorDown"},_ctrlKeysMap:{65:"selectAll",67:"copy",86:"paste",88:"cut"},onKeyDown:function(e){if(!this.isEditing||e.ctrlKey)return;if(e.keyCode in this._keysMap)this[this._keysMap[e.keyCode]](e);else{if(!(e.keyCode in this._ctrlKeysMap&&(e.ctrlKey||e.metaKey)))return;this[this._ctrlKeysMap[e.keyCode]](e)}e.preventDefault(),e.stopPropagation(),this.canvas&&this.canvas.renderAll()},forwardDelete:function(e){this.moveCursorRight(e),this.removeChars(e)},copy:function(){var e=this.getSelectedText();this.copiedText=e},paste:function(){this.copiedText&&this.insertChars(this.copiedText)},cut:function(e){this.copy(),this.removeChars(e)},selectAll:function(){this.selectionStart=0,this.selectionEnd=this.text.length},getSelectedText:function(){return this.text.slice(this.selectionStart,this.selectionEnd)},onKeyPress:function(e){if(!this.isEditing||e.metaKey||e.ctrlKey||e.keyCode===8||e.keyCode===13)return;this.insertChars(String.fromCharCode(e.which)),e.preventDefault(),e.stopPropagation()},getSelectionStartOffset:function(){var e=this.text.slice(0,this.selectionStart),t=this.text.slice(this.selectionStart),n=e.slice(e.lastIndexOf("\n")+1),r=t.match(/(.*)\n?/)[1],i=(t.match(/.*\n(.*)\n?/)||{})[1]||"";return n.length>i.length?(i+r).length+1:(n+r).length+1},moveCursorDown:function(e){this.abortCursorAnimation(),this._currentCursorOpacity=1;var t=this.getSelectionStartOffset();e.metaKey&&(t=this.text.length-this.selectionStart),e.shiftKey?this.moveCursorDownWithShift(t):this.moveCursorDownWithoutShift(t),this.initDelayedCursor()},moveCursorDownWithoutShift:function(e){this._selectionDirection="right",this.selectionStart+=e,this.selectionStart>this.text.length&&(this.selectionStart=this.text.length),this.selectionEnd=this.selectionStart},moveCursorDownWithShift:function(e){this._selectionDirection==="left"&&this.selectionStart!==this.selectionEnd?(this.selectionStart=this.selectionEnd,this._selectionDirection="right"):(this._selectionDirection="right",this.selectionEnd+=e,this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length))},moveCursorUp:function(e){var t=this.text.slice(0,this.selectionStart);this.abortCursorAnimation(),this._currentCursorOpacity=1;var n=t.slice(t.lastIndexOf("\n")+1),r=(t.match(/\n?(.*)\n.*$/)||{})[1]||"",i;n.length>r.length?i=n.length+1:i=r.length+1,e.metaKey&&(i=this.selectionStart),e.shiftKey?this.moveCursorUpWithShift(i):this.moveCursorUpWithoutShift(i),this.initDelayedCursor()},moveCursorUpWithShift:function(e){this.selectionStart===this.selectionEnd?this.selectionStart-=e:this._selectionDirection==="right"?this.selectionEnd=this.selectionStart:this.selectionStart-=e,this.selectionStart<0&&(this.selectionStart=0),this._selectionDirection="left"},moveCursorUpWithoutShift:function(e){this.selectionStart===this.selectionEnd&&(this.selectionStart-=e),this.selectionStart<0&&(this.selectionStart=0),this.selectionEnd=this.selectionStart,this._selectionDirection="left"},moveCursorLeft:function(e){if(this.selectionStart===0&&this.selectionEnd===0)return;this.abortCursorAnimation(),this._currentCursorOpacity=1,e.shiftKey?this.moveCursorLeftWithShift(e):this.moveCursorLeftWithoutShift(e),this.initDelayedCursor()},findWordBoundaryLeft:function(e){var t=0,n=e-1;if(this._reSpace.test(this.text.charAt(n)))while(this._reSpace.test(this.text.charAt(n)))t++,n--;while(/\S/.test(this.text.charAt(n))&&n>-1)t++,n--;return e-t},findWordBoundaryRight:function(e){var t=0,n=e;if(this._reSpace.test(this.text.charAt(n)))while(this._reSpace.test(this.text.charAt(n)))t++,n++;while(/\S/.test(this.text.charAt(n))&&n-1)t++,n--;return e-t},findLineBoundaryRight:function(e){var t=0,n=e;while(!/\n/.test(this.text.charAt(n))&&n=this.text.length&&this.selectionEnd>=this.text.length)return;this.abortCursorAnimation(),this._currentCursorOpacity=1,e.shiftKey?this.moveCursorRightWithShift(e):this.moveCursorRightWithoutShift(e),this.initDelayedCursor()},moveCursorRightWithShift:function(e){this._selectionDirection==="left"&&this.selectionStart!==this.selectionEnd?this._moveRight(e,"selectionStart"):(this._selectionDirection="right",this._moveRight(e,"selectionEnd"),this.text.charAt(this.selectionEnd-1)==="\n"&&this.selectionEnd++,this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length))},moveCursorRightWithoutShift:function(e){this._selectionDirection="right",this.selectionStart===this.selectionEnd?(this._moveRight(e,"selectionStart"),this.selectionEnd=this.selectionStart):(this.selectionEnd+=this.getNumNewLinesInSelectedText(),this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length),this.selectionStart=this.selectionEnd)},getNumNewLinesInSelectedText:function(){var e=this.getSelectedText(),t=0;for(var n=0,r=e.split(""),i=r.length;n0&&nr&&o>n){var g=n-s,y=o-n;return y>g?f=a+l:f=a+l+1,f>this.text.length&&(f=this.text.length),f}a++}}if(typeof f=="undefined")return this.text.length},enterEditing:function(){if(this.isEditing||!this.editable)return;return fabric.IText.instances.forEach(function(e){if(e===this)return;e.exitEditing()},this),this.isEditing=!0,this._updateTextarea(),this._saveProps(),this.hoverCursor="text",this.canvas.defaultCursor="text",this.canvas.moveCursor="text",this.hasControls=!1,this.borderColor=this.editingBorderColor,this.selectable=!1,this.lockMovementX=!0,this.lockMovementY=!0,this._tick(),this.canvas.renderAll(),this},_updateTextarea:function(){if(!this.hiddenTextarea)return;this.hiddenTextarea.value=this.text,this.hiddenTextarea.selectionStart=this.selectionStart,this.hiddenTextarea.focus()},_saveProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,defaultCursor:this.canvas.defaultCursor,moveCursor:this.canvas.moveCursor}},_restoreProps:function(){if(!this._savedProps)return;this.hoverCursor=this._savedProps.overCursor,this.canvas.defaultCursor=this._savedProps.defaultCursor,this.canvas.moveCursor=this._savedProps.moveCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,this.lockMovementX=this._savedProps.lockMovementX,this.lockMovementY=this._savedProps.lockMovementY},exitEditing:function(){return this.selected=!1,this.isEditing=!1,this.selectable=!0,this.hiddenTextarea&&this.hiddenTextarea.blur(),this.abortCursorAnimation(),this._restoreProps(),this._currentCursorOpacity=0,this},removeChars:function(e){if(this.selectionStart===this.selectionEnd){if(this.selectionStart!==0)if(e.metaKey){var t=this.findLineBoundaryLeft(this.selectionStart);this._removeCharsFromTo(t,this.selectionStart),this.selectionStart=t}else if(e.altKey){var n=this.findWordBoundaryLeft(this.selectionStart);this._removeCharsFromTo(n,this.selectionStart),this.selectionStart=n}else{var r=this.text.slice(this.selectionStart-1,this.selectionStart)==="\n";this.removeStyleObject(r),this.selectionStart--,this.text=this.text.slice(0,this.selectionStart)+this.text.slice(this.selectionStart+1)}}else this._removeCharsFromTo(this.selectionStart,this.selectionEnd);this.selectionEnd=this.selectionStart;var i=this.text.split(this._reNewline);for(var s in this.styles)i[s]||delete this.styles[s];this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire("text:changed")},_removeCharsFromTo:function(e,t){var n=t;while(n!==e)n--,this.removeStyleObject(!1,n);this.text=this.text.slice(0,e)+this.text.slice(t)},insertChars:function(e){var t=this.text.slice(this.selectionStart,this.selectionStart+1)==="\n";this.text=this.text.slice(0,this.selectionStart)+e+this.text.slice(this.selectionEnd),this.selectionStart===this.selectionEnd?this.insertStyleObject(e,t):this.selectionEnd-this.selectionStart>1,this.selectionStart+=e.length,this.selectionEnd=this.selectionStart,this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire("text:changed")},insertNewlineStyleObject:function(t,n,r){this.shiftLineStyles(t,1),this.styles[t+1]||(this.styles[t+1]={});var i=this.styles[t][n-1],s={};if(r)s[0]=e(i),this.styles[t+1]=s;else{for(var o in this.styles[t])parseInt(o,10)>=n&&(s[parseInt(o,10)-n]=this.styles[t][o],delete this.styles[t][o]);this.styles[t+1]=s}},insertCharStyleObject:function(t,n){var r=this.styles[t],i=e(r);n===0&&(n=1);for(var s in i){var o=parseInt(s,10);o>=n&&(r[o+1]=i[o])}this.styles[t][n]=e(r[n-1])},insertStyleObject:function(e,t){if(this.isEmptyStyles())return;var n=this.get2DCursorLocation(),r=n.lineIndex,i=n.charIndex;this.styles[r]||(this.styles[r]={}),e==="\n"?this.insertNewlineStyleObject(r,i,t):this.insertCharStyleObject(r,i)},shiftLineStyles:function(t,n){var r=e(this.styles);for(var i in this.styles){var s=parseInt(i,10);s>t&&(this.styles[s+n]=r[s])}},removeStyleObject:function(t,n){var r=this.get2DCursorLocation(n),i=r.lineIndex,s=r.charIndex;if(t){var o=this.text.split(this._reNewline),u=o[i-1],a=u.length;this.styles[i-1]||(this.styles[i-1]={});for(s in this.styles[i])this.styles[i-1][parseInt(s,10)+a]=this.styles[i][s];this.shiftLineStyles(i,-1)}else{var f=this.styles[i];if(f){var l=this.selectionStart===this.selectionEnd?-1:0;delete f[s+l]}var c=e(f);for(var h in c){var p=parseInt(h,10);p>=s&&p!==0&&(f[p-1]=c[p],delete f[p])}}},insertNewline:function(){this.insertChars("\n")}})}(),function(){function request(e,t,n){var r=URL.parse(e);r.port||(r.port=r.protocol.indexOf("https:")===0?443:80);var i=r.port===443?HTTPS:HTTP,s=i.request({hostname:r.hostname,port:r.port,path:r.path,method:"GET"},function(e){var r="";t&&e.setEncoding(t),e.on("end",function(){n(r)}),e.on("data",function(t){e.statusCode===200&&(r+=t)})});s.on("error",function(e){e.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+r.hostname+":"+r.port):fabric.log(e.message)}),s.end()}function request_fs(e,t){var n=require("fs");n.readFile(e,function(e,n){if(e)throw fabric.log(e),e;t(n)})}if(typeof document!="undefined"&&typeof window!="undefined")return;var DOMParser=(new require("xmldom")).DOMParser,URL=require("url"),HTTP=require("http"),HTTPS=require("https"),Canvas=require("canvas"),Image=require("canvas").Image;fabric.util.loadImage=function(e,t,n){var r=function(r){i.src=new Buffer(r,"binary"),i._src=e,t&&t.call(n,i)},i=new Image;e&&(e instanceof Buffer||e.indexOf("data")===0)?(i.src=i._src=e,t&&t.call(n,i)):e&&e.indexOf("http")!==0?request_fs(e,r):e&&request(e,"binary",r)},fabric.loadSVGFromURL=function(e,t,n){e=e.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim(),e.indexOf("http")!==0?request_fs(e,function(e){fabric.loadSVGFromString(e,t,n)}):request(e,"",function(e){fabric.loadSVGFromString(e,t,n)})},fabric.loadSVGFromString=function(e,t,n){var r=(new DOMParser).parseFromString(e);fabric.parseSVGDocument(r.documentElement,function(e,n){t&&t(e,n)},n)},fabric.util.getScript=function(url,callback){request(url,"",function(body){eval(body),callback&&callback()})},fabric.Image.fromObject=function(e,t){fabric.util.loadImage(e.src,function(n){var r=new fabric.Image(n);r._initConfig(e),r._initFilters(e,function(e){r.filters=e||[],t&&t(r)})})},fabric.createCanvasForNode=function(e,t){var n=fabric.document.createElement("canvas"),r=new Canvas(e||600,t||600);n.style={},n.width=r.width,n.height=r.height;var i=fabric.Canvas||fabric.StaticCanvas,s=new i(n);return s.contextContainer=r.getContext("2d"),s.nodeCanvas=r,s.Font=Canvas.Font,s},fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(e){return this.nodeCanvas.createJPEGStream(e)};var origSetWidth=fabric.StaticCanvas.prototype.setWidth;fabric.StaticCanvas.prototype.setWidth=function(e){return origSetWidth.call(this,e),this.nodeCanvas.width=e,this},fabric.Canvas&&(fabric.Canvas.prototype.setWidth=fabric.StaticCanvas.prototype.setWidth);var origSetHeight=fabric.StaticCanvas.prototype.setHeight;fabric.StaticCanvas.prototype.setHeight=function(e){return origSetHeight.call(this,e),this.nodeCanvas.height=e,this},fabric.Canvas&&(fabric.Canvas.prototype.setHeight=fabric.StaticCanvas.prototype.setHeight)}(); \ No newline at end of file +(o.shadow));var a=o.fill||this.fill;return t.fillStyle=a.toLive?a.toLive(t):a,o.stroke&&(t.strokeStyle=o.stroke&&o.stroke.toLive?o.stroke.toLive(t):o.stroke),t.lineWidth=o.strokeWidth||this.strokeWidth,t.font=this._getFontDeclaration.call(o),this._setShadow.call(o,t),this._charWidthsCache[u]||(this._charWidthsCache[u]=t.measureText(n).width),this._charWidthsCache[u]},_applyFontStyles:function(e){e.fontFamily||(e.fontFamily=this.fontFamily),e.fontSize||(e.fontSize=this.fontSize),e.fontWeight||(e.fontWeight=this.fontWeight),e.fontStyle||(e.fontStyle=this.fontStyle)},_getWidthOfChar:function(e,t,n,r){e.save();var i=this._applyCharStylesGetWidth(e,t,n,r);return e.restore(),i},_getHeightOfChar:function(e,t,n,r){return this.styles[n]&&this.styles[n][r]?this.styles[n][r].fontSize||this.fontSize:this.fontSize},_getWidthOfCharAt:function(e,t,n,r){r=r||this.text.split(this._reNewline);var i=r[t].split("")[n];return this._getWidthOfChar(e,i,t,n)},_getHeightOfCharAt:function(e,t,n,r){r=r||this.text.split(this._reNewline);var i=r[t].split("")[n];return this._getHeightOfChar(e,i,t,n)},_getWidthOfCharsAt:function(e,t,n,r){var i=0;for(var s=0;sn&&(n=s)}return n},_getHeightOfLine:function(e,t,n){n=n||this.text.split(this._reNewline);var r=this._getHeightOfChar(e,n[t][0],t,0),i=n[t],s=i.split("");for(var o=1,u=s.length;or&&(r=a)}return r*this.lineHeight},_getTextHeight:function(e,t){var n=0;for(var r=0,i=t.length;r',fabric.util.string.escapeXml(a[d]),"");var y=this._getWidthOfChar(this.ctx,a[d],n,d);m.textBackgroundColor&&o.push(''),f+=y}}}),fabric.IText.fromObject=function(t){return new fabric.IText(t.text,e(t))},fabric.IText.instances=[]}(),function(){var e=fabric.util.object.clone;fabric.util.object.extend(fabric.IText.prototype,{initBehavior:function(){this.initKeyHandlers(),this.initCursorSelectionHandlers(),this.initDblClickSimulation(),this.initHiddenTextarea()},initKeyHandlers:function(){fabric.util.addListener(document,"keydown",this.onKeyDown.bind(this)),fabric.util.addListener(document,"keypress",this.onKeyPress.bind(this))},initHiddenTextarea:function(){if(!/(iPad|iPhone|iPod)/g.test(navigator.userAgent))return;this.hiddenTextarea=fabric.document.createElement("textarea"),this.hiddenTextarea.setAttribute("autocapitalize","off"),this.hiddenTextarea.style.cssText="position: absolute; top: 0; left: -9999px",fabric.document.body.appendChild(this.hiddenTextarea)},initDblClickSimulation:function(){var e=+(new Date),t,n={},r;this.on("mousedown",function(i){var s=i.e;t=+(new Date),r=this.canvas.getPointer(s);var o=t-e<500&&n.x===r.x&&n.y===r.y;o&&(this.fire("dblclick",i),s.preventDefault&&s.preventDefault(),s.stopPropagation&&s.stopPropagation()),e=t,n=r})},initCursorSelectionHandlers:function(){this.initSelectedHandler(),this.initMousedownHandler(),this.initMousemoveHandler(),this.initMouseupHandler(),this.on("dblclick",function(e){this.selectWord(this.getSelectionStartFromPointer(e.e))})},initMousedownHandler:function(){this.on("mousedown",function(e){var t=this.canvas.getPointer(e.e);this.__mousedownX=t.x,this.__mousedownY=t.y,this.__isMousedown=!0,this.hiddenTextarea&&this.canvas&&this.canvas.wrapperEl.appendChild(this.hiddenTextarea),this.isEditing&&this.setCursorByClick(e.e)})},initMousemoveHandler:function(){this.on("mousemove",function(){this.__isMousedown&&this.isEditing&&console.log("mousemove: need to select text")})},initMouseupHandler:function(){this.on("mouseup",function(e){this.__isMousedown=!1;var t=this.canvas.getPointer(e.e),n=this.__mousedownX!==t.x||this.__mousedownY!==t.y;if(n)return;this.selected&&this.enterEditing()})},initSelectedHandler:function(){this.on("selected",function(){var e=this;setTimeout(function(){e.selected=!0},100),this._hasClearSelectionListener||(this.canvas.on("selection:cleared",function(t){if(t.e&&e.canvas.containsPoint(t.e,e))return;e.exitEditing()}),this._hasClearSelectionListener=!0)})},_tick:function(){var e=this;if(this._abortCursorAnimation)return;this.animate("_currentCursorOpacity",1,{duration:this.cursorDuration,onComplete:function(){e._onTickComplete()},onChange:function(){e.canvas&&e.canvas.renderAll()},abort:function(){return e._abortCursorAnimation}})},_onTickComplete:function(){if(this._abortCursorAnimation)return;var e=this;this._cursorTimeout1&&clearTimeout(this._cursorTimeout1),this._cursorTimeout1=setTimeout(function(){e.animate("_currentCursorOpacity",0,{duration:this.cursorDuration/2,onComplete:function(){e._tick()},onChange:function(){e.canvas&&e.canvas.renderAll()},abort:function(){return e._abortCursorAnimation}})},100)},initDelayedCursor:function(){var e=this;this._cursorTimeout2&&clearTimeout(this._cursorTimeout2),this._cursorTimeout2=setTimeout(function(){e._abortCursorAnimation=!1,e._tick()},this.cursorDelay)},abortCursorAnimation:function(){this._abortCursorAnimation=!0,clearTimeout(this._cursorTimeout1),clearTimeout(this._cursorTimeout2),this._currentCursorOpacity=0,this.canvas&&this.canvas.renderAll();var e=this;setTimeout(function(){e._abortCursorAnimation=!1},10)},_keysMap:{8:"removeChars",13:"insertNewline",37:"moveCursorLeft",38:"moveCursorUp",39:"moveCursorRight",40:"moveCursorDown"},_ctrlKeysMap:{65:"selectAll",67:"copy",86:"paste",88:"cut"},onKeyDown:function(e){if(!this.isEditing||e.ctrlKey)return;if(e.keyCode in this._keysMap)this[this._keysMap[e.keyCode]](e);else{if(!(e.keyCode in this._ctrlKeysMap&&(e.ctrlKey||e.metaKey)))return;this[this._ctrlKeysMap[e.keyCode]](e)}e.preventDefault(),e.stopPropagation(),this.canvas&&this.canvas.renderAll()},forwardDelete:function(e){this.moveCursorRight(e),this.removeChars(e)},copy:function(){var e=this.getSelectedText();this.copiedText=e},paste:function(){this.copiedText&&this.insertChars(this.copiedText)},cut:function(e){this.copy(),this.removeChars(e)},selectAll:function(){this.selectionStart=0,this.selectionEnd=this.text.length},getSelectedText:function(){return this.text.slice(this.selectionStart,this.selectionEnd)},onKeyPress:function(e){if(!this.isEditing||e.metaKey||e.ctrlKey||e.keyCode===8||e.keyCode===13)return;this.insertChars(String.fromCharCode(e.which)),e.preventDefault(),e.stopPropagation()},getDownCursorOffset:function(e){var t=this.text.split(this._reNewline),n,r,i,s=this.text.slice(0,this.selectionStart),o=this.text.slice(this.selectionStart),u=s.slice(s.lastIndexOf("\n")+1),a=o.match(/(.*)\n?/)[1],f=(o.match(/.*\n(.*)\n?/)||{})[1]||"",l=this.get2DCursorLocation();if(l.lineIndex===t.length-1||e.metaKey)return this.text.length-this.selectionStart;var c=this._getWidthOfLine(this.ctx,l.lineIndex,t);r=this._getLineLeftOffset(c);var h=r,p=l.lineIndex;for(var d=0,v=u.length;dh){i=!0;var S=g-E,x=g,T=Math.abs(S-h),N=Math.abs(x-h);y=Nthis.text.length&&(this.selectionStart=this.text.length),this.selectionEnd=this.selectionStart},moveCursorDownWithShift:function(e){this._selectionDirection==="left"&&this.selectionStart!==this.selectionEnd?(this.selectionStart=this.selectionEnd,this._selectionDirection="right"):(this._selectionDirection="right",this.selectionEnd+=e,this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length))},getUpCursorOffset:function(e){var t=this.get2DCursorLocation();if(t.lineIndex===0||e.metaKey)return this.selectionStart;var n=this.text.slice(0,this.selectionStart),r=n.slice(n.lastIndexOf("\n")+1),i=(n.match(/\n?(.*)\n.*$/)||{})[1]||"",s=this.text.split(this._reNewline),o,u,a,f=this._getWidthOfLine(this.ctx,t.lineIndex,s);u=this._getLineLeftOffset(f);var l=u,c=t.lineIndex;for(var h=0,p=r.length;hl){a=!0;var w=v-b,E=v,S=Math.abs(w-l),x=Math.abs(E-l);m=x-1)t++,n--;return e-t},findWordBoundaryRight:function(e){var t=0,n=e;if(this._reSpace.test(this.text.charAt(n)))while(this._reSpace.test(this.text.charAt(n)))t++,n++;while(/\S/.test(this.text.charAt(n))&&n-1)t++,n--;return e-t},findLineBoundaryRight:function(e){var t=0,n=e;while(!/\n/.test(this.text.charAt(n))&&n=this.text.length&&this.selectionEnd>=this.text.length)return;this.abortCursorAnimation(),this._currentCursorOpacity=1,e.shiftKey?this.moveCursorRightWithShift(e):this.moveCursorRightWithoutShift(e),this.initDelayedCursor()},moveCursorRightWithShift:function(e){this._selectionDirection==="left"&&this.selectionStart!==this.selectionEnd?this._moveRight(e,"selectionStart"):(this._selectionDirection="right",this._moveRight(e,"selectionEnd"),this.text.charAt(this.selectionEnd-1)==="\n"&&this.selectionEnd++,this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length))},moveCursorRightWithoutShift:function(e){this._selectionDirection="right",this.selectionStart===this.selectionEnd?(this._moveRight(e,"selectionStart"),this.selectionEnd=this.selectionStart):(this.selectionEnd+=this.getNumNewLinesInSelectedText(),this.selectionEnd>this.text.length&&(this.selectionEnd=this.text.length),this.selectionStart=this.selectionEnd)},getNumNewLinesInSelectedText:function(){var e=this.getSelectedText(),t=0;for(var n=0,r=e.split(""),i=r.length;n0&&nr&&o>n){var g=n-s,y=o-n;return y>g?f=a+l:f=a+l+1,this.flipX&&(f=v-f),f>this.text.length&&(f=this.text.length),f}a++}}if(typeof f=="undefined")return this.text.length},enterEditing:function(){if(this.isEditing||!this.editable)return;return fabric.IText.instances.forEach(function(e){if(e===this)return;e.exitEditing()},this),this.isEditing=!0,this._updateTextarea(),this._saveProps(),this.hoverCursor="text",this.canvas.defaultCursor="text",this.canvas.moveCursor="text",this.hasControls=!1,this.borderColor=this.editingBorderColor,this.selectable=!1,this.lockMovementX=!0,this.lockMovementY=!0,this._tick(),this.canvas.renderAll(),this},_updateTextarea:function(){if(!this.hiddenTextarea)return;this.hiddenTextarea.value=this.text,this.hiddenTextarea.selectionStart=this.selectionStart,this.hiddenTextarea.focus()},_saveProps:function(){this._savedProps={hasControls:this.hasControls,borderColor:this.borderColor,lockMovementX:this.lockMovementX,lockMovementY:this.lockMovementY,hoverCursor:this.hoverCursor,defaultCursor:this.canvas.defaultCursor,moveCursor:this.canvas.moveCursor}},_restoreProps:function(){if(!this._savedProps)return;this.hoverCursor=this._savedProps.overCursor,this.canvas.defaultCursor=this._savedProps.defaultCursor,this.canvas.moveCursor=this._savedProps.moveCursor,this.hasControls=this._savedProps.hasControls,this.borderColor=this._savedProps.borderColor,this.lockMovementX=this._savedProps.lockMovementX,this.lockMovementY=this._savedProps.lockMovementY},exitEditing:function(){return this.selected=!1,this.isEditing=!1,this.selectable=!0,this.hiddenTextarea&&this.hiddenTextarea.blur(),this.abortCursorAnimation(),this._restoreProps(),this._currentCursorOpacity=0,this},removeChars:function(e){if(this.selectionStart===this.selectionEnd){if(this.selectionStart!==0)if(e.metaKey){var t=this.findLineBoundaryLeft(this.selectionStart);this._removeCharsFromTo(t,this.selectionStart),this.selectionStart=t}else if(e.altKey){var n=this.findWordBoundaryLeft(this.selectionStart);this._removeCharsFromTo(n,this.selectionStart),this.selectionStart=n}else{var r=this.text.slice(this.selectionStart-1,this.selectionStart)==="\n";this.removeStyleObject(r),this.selectionStart--,this.text=this.text.slice(0,this.selectionStart)+this.text.slice(this.selectionStart+1)}}else this._removeCharsFromTo(this.selectionStart,this.selectionEnd);this.selectionEnd=this.selectionStart;var i=this.text.split(this._reNewline);for(var s in this.styles)i[s]||delete this.styles[s];this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire("text:changed")},_removeCharsFromTo:function(e,t){var n=t;while(n!==e)n--,this.removeStyleObject(!1,n);this.text=this.text.slice(0,e)+this.text.slice(t)},insertChars:function(e){var t=this.text.slice(this.selectionStart,this.selectionStart+1)==="\n";this.text=this.text.slice(0,this.selectionStart)+e+this.text.slice(this.selectionEnd),this.selectionStart===this.selectionEnd?this.insertStyleObject(e,t):this.selectionEnd-this.selectionStart>1,this.selectionStart+=e.length,this.selectionEnd=this.selectionStart,this.canvas&&this.canvas.renderAll().renderAll(),this.setCoords(),this.fire("text:changed")},insertNewlineStyleObject:function(t,n,r){this.shiftLineStyles(t,1),this.styles[t+1]||(this.styles[t+1]={});var i=this.styles[t][n-1],s={};if(r)s[0]=e(i),this.styles[t+1]=s;else{for(var o in this.styles[t])parseInt(o,10)>=n&&(s[parseInt(o,10)-n]=this.styles[t][o],delete this.styles[t][o]);this.styles[t+1]=s}},insertCharStyleObject:function(t,n){var r=this.styles[t],i=e(r);n===0&&(n=1);for(var s in i){var o=parseInt(s,10);o>=n&&(r[o+1]=i[o])}this.styles[t][n]=e(r[n-1])},insertStyleObject:function(e,t){if(this.isEmptyStyles())return;var n=this.get2DCursorLocation(),r=n.lineIndex,i=n.charIndex;this.styles[r]||(this.styles[r]={}),e==="\n"?this.insertNewlineStyleObject(r,i,t):this.insertCharStyleObject(r,i)},shiftLineStyles:function(t,n){var r=e(this.styles);for(var i in this.styles){var s=parseInt(i,10);s>t&&(this.styles[s+n]=r[s])}},removeStyleObject:function(t,n){var r=this.get2DCursorLocation(n),i=r.lineIndex,s=r.charIndex;if(t){var o=this.text.split(this._reNewline),u=o[i-1],a=u.length;this.styles[i-1]||(this.styles[i-1]={});for(s in this.styles[i])this.styles[i-1][parseInt(s,10)+a]=this.styles[i][s];this.shiftLineStyles(i,-1)}else{var f=this.styles[i];if(f){var l=this.selectionStart===this.selectionEnd?-1:0;delete f[s+l]}var c=e(f);for(var h in c){var p=parseInt(h,10);p>=s&&p!==0&&(f[p-1]=c[p],delete f[p])}}},insertNewline:function(){this.insertChars("\n")}})}(),function(){function request(e,t,n){var r=URL.parse(e);r.port||(r.port=r.protocol.indexOf("https:")===0?443:80);var i=r.port===443?HTTPS:HTTP,s=i.request({hostname:r.hostname,port:r.port,path:r.path,method:"GET"},function(e){var r="";t&&e.setEncoding(t),e.on("end",function(){n(r)}),e.on("data",function(t){e.statusCode===200&&(r+=t)})});s.on("error",function(e){e.errno===process.ECONNREFUSED?fabric.log("ECONNREFUSED: connection refused to "+r.hostname+":"+r.port):fabric.log(e.message)}),s.end()}function request_fs(e,t){var n=require("fs");n.readFile(e,function(e,n){if(e)throw fabric.log(e),e;t(n)})}if(typeof document!="undefined"&&typeof window!="undefined")return;var DOMParser=(new require("xmldom")).DOMParser,URL=require("url"),HTTP=require("http"),HTTPS=require("https"),Canvas=require("canvas"),Image=require("canvas").Image;fabric.util.loadImage=function(e,t,n){var r=function(r){i.src=new Buffer(r,"binary"),i._src=e,t&&t.call(n,i)},i=new Image;e&&(e instanceof Buffer||e.indexOf("data")===0)?(i.src=i._src=e,t&&t.call(n,i)):e&&e.indexOf("http")!==0?request_fs(e,r):e&&request(e,"binary",r)},fabric.loadSVGFromURL=function(e,t,n){e=e.replace(/^\n\s*/,"").replace(/\?.*$/,"").trim(),e.indexOf("http")!==0?request_fs(e,function(e){fabric.loadSVGFromString(e,t,n)}):request(e,"",function(e){fabric.loadSVGFromString(e,t,n)})},fabric.loadSVGFromString=function(e,t,n){var r=(new DOMParser).parseFromString(e);fabric.parseSVGDocument(r.documentElement,function(e,n){t&&t(e,n)},n)},fabric.util.getScript=function(url,callback){request(url,"",function(body){eval(body),callback&&callback()})},fabric.Image.fromObject=function(e,t){fabric.util.loadImage(e.src,function(n){var r=new fabric.Image(n);r._initConfig(e),r._initFilters(e,function(e){r.filters=e||[],t&&t(r)})})},fabric.createCanvasForNode=function(e,t){var n=fabric.document.createElement("canvas"),r=new Canvas(e||600,t||600);n.style={},n.width=r.width,n.height=r.height;var i=fabric.Canvas||fabric.StaticCanvas,s=new i(n);return s.contextContainer=r.getContext("2d"),s.nodeCanvas=r,s.Font=Canvas.Font,s},fabric.StaticCanvas.prototype.createPNGStream=function(){return this.nodeCanvas.createPNGStream()},fabric.StaticCanvas.prototype.createJPEGStream=function(e){return this.nodeCanvas.createJPEGStream(e)};var origSetWidth=fabric.StaticCanvas.prototype.setWidth;fabric.StaticCanvas.prototype.setWidth=function(e){return origSetWidth.call(this,e),this.nodeCanvas.width=e,this},fabric.Canvas&&(fabric.Canvas.prototype.setWidth=fabric.StaticCanvas.prototype.setWidth);var origSetHeight=fabric.StaticCanvas.prototype.setHeight;fabric.StaticCanvas.prototype.setHeight=function(e){return origSetHeight.call(this,e),this.nodeCanvas.height=e,this},fabric.Canvas&&(fabric.Canvas.prototype.setHeight=fabric.StaticCanvas.prototype.setHeight)}(); \ No newline at end of file diff --git a/dist/all.min.js.gz b/dist/all.min.js.gz index 749a6948a31af7394eb17d23a43c8cb313d12bf8..2e730ce476768fe88622db03fe3192ac5aa35bcc 100644 GIT binary patch delta 5557 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 HGg1QpTKh>z diff --git a/dist/all.require.js b/dist/all.require.js index 2437a69c..814a4554 100644 --- a/dist/all.require.js +++ b/dist/all.require.js @@ -1981,6 +1981,7 @@ fabric.Collection = { /** * 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} */ @@ -21162,20 +21163,76 @@ fabric.util.object.extend(fabric.Text.prototype, { * Gets start offset of a selection * @return {Number} */ - getSelectionStartOffset: function() { - var textBeforeCursor = this.text.slice(0, this.selectionStart); - var textAfterCursor = this.text.slice(this.selectionStart); + getDownCursorOffset: function(e) { - var textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1); - var textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\n?/)[1]; - var textOnNextLine = (textAfterCursor.match(/.*\n(.*)\n?/) || { })[1] || ''; + var textLines = this.text.split(this._reNewline), + _char, + lineLeftOffset, + foundMatch, - if (textOnSameLineBeforeCursor.length > textOnNextLine.length) { - return (textOnNextLine + textOnSameLineAfterCursor).length + 1; + textBeforeCursor = this.text.slice(0, this.selectionStart), + textAfterCursor = this.text.slice(this.selectionStart), + + textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1), + textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\n?/)[1], + textOnNextLine = (textAfterCursor.match(/.*\n(.*)\n?/) || { })[1] || '', + + cursorLocation = this.get2DCursorLocation(); + + // if on last line, down cursor goes to end of line + if (cursorLocation.lineIndex === textLines.length - 1 || e.metaKey) { + + // move to the end of a text + return this.text.length - this.selectionStart; } - else { - return (textOnSameLineBeforeCursor + textOnSameLineAfterCursor).length + 1; + + var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); + + var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; + var lineIndex = cursorLocation.lineIndex; + + for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { + _char = textOnSameLineBeforeCursor[i]; + widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); } + + var widthOfNextLine = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex + 1, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfNextLine); + var widthOfCharsOnNextLine = lineLeftOffset; + var indexOnNextLine = 0; + + lineIndex = cursorLocation.lineIndex + 1; + + for (var j = 0, jlen = textOnNextLine.length; j < jlen; j++) { + + _char = textOnNextLine[j]; + var widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); + + widthOfCharsOnNextLine += widthOfChar; + + if (widthOfCharsOnNextLine > widthOfCharsOnSameLineBeforeCursor) { + + foundMatch = true; + + var leftEdge = widthOfCharsOnNextLine - widthOfChar; + var rightEdge = widthOfCharsOnNextLine; + + var offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor); + var offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); + + indexOnNextLine = offsetFromRightEdge < offsetFromLeftEdge ? j + 1 : j; + + break; + } + } + + // reached end + if (!foundMatch) { + indexOnNextLine = textOnNextLine.length; + } + + return textOnSameLineAfterCursor.length + 1 + indexOnNextLine; }, /** @@ -21187,12 +21244,7 @@ fabric.util.object.extend(fabric.Text.prototype, { this.abortCursorAnimation(); this._currentCursorOpacity = 1; - var offset = this.getSelectionStartOffset(); - - if (e.metaKey) { - // move to the end of a text - offset = this.text.length - this.selectionStart; - } + var offset = this.getDownCursorOffset(e); if (e.shiftKey) { this.moveCursorDownWithShift(offset); @@ -21239,33 +21291,82 @@ fabric.util.object.extend(fabric.Text.prototype, { } }, + getUpCursorOffset: function(e) { + + var cursorLocation = this.get2DCursorLocation(); + + // if on first line, up cursor goes to start of line + if (cursorLocation.lineIndex === 0 || e.metaKey) { + return this.selectionStart; + } + + var textBeforeCursor = this.text.slice(0, this.selectionStart), + textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1), + textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || '', + textLines = this.text.split(this._reNewline), + _char, + lineLeftOffset, + foundMatch; + + var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); + + var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; + var lineIndex = cursorLocation.lineIndex; + + for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { + _char = textOnSameLineBeforeCursor[i]; + widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); + } + + var widthOfPreviousLine = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex - 1, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine); + var widthOfCharsOnPreviousLine = lineLeftOffset; + var indexOnPrevLine = 0; + + lineIndex = cursorLocation.lineIndex - 1; + + for (var j = 0, jlen = textOnPreviousLine.length; j < jlen; j++) { + + _char = textOnPreviousLine[j]; + var widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); + + widthOfCharsOnPreviousLine += widthOfChar; + + if (widthOfCharsOnPreviousLine > widthOfCharsOnSameLineBeforeCursor) { + + foundMatch = true; + + var leftEdge = widthOfCharsOnPreviousLine - widthOfChar; + var rightEdge = widthOfCharsOnPreviousLine; + + var offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor); + var offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); + + indexOnPrevLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1); + + break; + } + } + + // reached end + if (!foundMatch) { + indexOnPrevLine = textOnPreviousLine.length - 1; + } + + return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length; + }, + /** * Moves cursor up * @param {Event} e Event object */ moveCursorUp: function(e) { - var textBeforeCursor = this.text.slice(0, this.selectionStart); - this.abortCursorAnimation(); this._currentCursorOpacity = 1; - var textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1); - var textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || ''; - var offset; - - // only change cursor location if there's no selection at the moment - if (textOnSameLineBeforeCursor.length > textOnPreviousLine.length) { - offset = textOnSameLineBeforeCursor.length + 1; - } - else { - offset = textOnPreviousLine.length + 1; - } - - if (e.metaKey) { - // move to start of text - offset = this.selectionStart; - } + var offset = this.getUpCursorOffset(e); if (e.shiftKey) { this.moveCursorUpWithShift(offset); @@ -21635,10 +21736,16 @@ fabric.util.object.extend(fabric.Text.prototype, { width = lineLeftOffset; + if (this.flipX) { + // when oject is horizontally flipped we reverse chars + textLines[i] = textLines[i].split('').reverse().join(''); + } + for (var j = 0, jlen = textLines[i].length; j < jlen; j++) { var _char = textLines[i][j]; prevWidth = width; - width += this._getWidthOfChar(this.ctx, _char, i, j) * this.scaleX; + width += this._getWidthOfChar(this.ctx, _char, i, this.flipX ? jlen - j : j) * + this.scaleX; // debugging // var objectLeftTop = this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top'); @@ -21664,6 +21771,11 @@ fabric.util.object.extend(fabric.Text.prototype, { newSelectionStart = charIndex + i + 1; } + // 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; } diff --git a/src/mixins/collection.mixin.js b/src/mixins/collection.mixin.js index f5c1cc2d..b387e7f9 100644 --- a/src/mixins/collection.mixin.js +++ b/src/mixins/collection.mixin.js @@ -81,6 +81,7 @@ fabric.Collection = { /** * 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} */ diff --git a/src/mixins/itext_behavior.mixin.js b/src/mixins/itext_behavior.mixin.js index 8859dbcf..86b4e07b 100644 --- a/src/mixins/itext_behavior.mixin.js +++ b/src/mixins/itext_behavior.mixin.js @@ -360,20 +360,76 @@ * Gets start offset of a selection * @return {Number} */ - getSelectionStartOffset: function() { - var textBeforeCursor = this.text.slice(0, this.selectionStart); - var textAfterCursor = this.text.slice(this.selectionStart); + getDownCursorOffset: function(e) { - var textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1); - var textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\n?/)[1]; - var textOnNextLine = (textAfterCursor.match(/.*\n(.*)\n?/) || { })[1] || ''; + var textLines = this.text.split(this._reNewline), + _char, + lineLeftOffset, + foundMatch, - if (textOnSameLineBeforeCursor.length > textOnNextLine.length) { - return (textOnNextLine + textOnSameLineAfterCursor).length + 1; + textBeforeCursor = this.text.slice(0, this.selectionStart), + textAfterCursor = this.text.slice(this.selectionStart), + + textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1), + textOnSameLineAfterCursor = textAfterCursor.match(/(.*)\n?/)[1], + textOnNextLine = (textAfterCursor.match(/.*\n(.*)\n?/) || { })[1] || '', + + cursorLocation = this.get2DCursorLocation(); + + // if on last line, down cursor goes to end of line + if (cursorLocation.lineIndex === textLines.length - 1 || e.metaKey) { + + // move to the end of a text + return this.text.length - this.selectionStart; } - else { - return (textOnSameLineBeforeCursor + textOnSameLineAfterCursor).length + 1; + + var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); + + var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; + var lineIndex = cursorLocation.lineIndex; + + for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { + _char = textOnSameLineBeforeCursor[i]; + widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); } + + var widthOfNextLine = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex + 1, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfNextLine); + var widthOfCharsOnNextLine = lineLeftOffset; + var indexOnNextLine = 0; + + lineIndex = cursorLocation.lineIndex + 1; + + for (var j = 0, jlen = textOnNextLine.length; j < jlen; j++) { + + _char = textOnNextLine[j]; + var widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); + + widthOfCharsOnNextLine += widthOfChar; + + if (widthOfCharsOnNextLine > widthOfCharsOnSameLineBeforeCursor) { + + foundMatch = true; + + var leftEdge = widthOfCharsOnNextLine - widthOfChar; + var rightEdge = widthOfCharsOnNextLine; + + var offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor); + var offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); + + indexOnNextLine = offsetFromRightEdge < offsetFromLeftEdge ? j + 1 : j; + + break; + } + } + + // reached end + if (!foundMatch) { + indexOnNextLine = textOnNextLine.length; + } + + return textOnSameLineAfterCursor.length + 1 + indexOnNextLine; }, /** @@ -385,12 +441,7 @@ this.abortCursorAnimation(); this._currentCursorOpacity = 1; - var offset = this.getSelectionStartOffset(); - - if (e.metaKey) { - // move to the end of a text - offset = this.text.length - this.selectionStart; - } + var offset = this.getDownCursorOffset(e); if (e.shiftKey) { this.moveCursorDownWithShift(offset); @@ -437,33 +488,82 @@ } }, + getUpCursorOffset: function(e) { + + var cursorLocation = this.get2DCursorLocation(); + + // if on first line, up cursor goes to start of line + if (cursorLocation.lineIndex === 0 || e.metaKey) { + return this.selectionStart; + } + + var textBeforeCursor = this.text.slice(0, this.selectionStart), + textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1), + textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || '', + textLines = this.text.split(this._reNewline), + _char, + lineLeftOffset, + foundMatch; + + var widthOfSameLineBeforeCursor = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfSameLineBeforeCursor); + + var widthOfCharsOnSameLineBeforeCursor = lineLeftOffset; + var lineIndex = cursorLocation.lineIndex; + + for (var i = 0, len = textOnSameLineBeforeCursor.length; i < len; i++) { + _char = textOnSameLineBeforeCursor[i]; + widthOfCharsOnSameLineBeforeCursor += this._getWidthOfChar(this.ctx, _char, lineIndex, i); + } + + var widthOfPreviousLine = this._getWidthOfLine(this.ctx, cursorLocation.lineIndex - 1, textLines); + lineLeftOffset = this._getLineLeftOffset(widthOfPreviousLine); + var widthOfCharsOnPreviousLine = lineLeftOffset; + var indexOnPrevLine = 0; + + lineIndex = cursorLocation.lineIndex - 1; + + for (var j = 0, jlen = textOnPreviousLine.length; j < jlen; j++) { + + _char = textOnPreviousLine[j]; + var widthOfChar = this._getWidthOfChar(this.ctx, _char, lineIndex, j); + + widthOfCharsOnPreviousLine += widthOfChar; + + if (widthOfCharsOnPreviousLine > widthOfCharsOnSameLineBeforeCursor) { + + foundMatch = true; + + var leftEdge = widthOfCharsOnPreviousLine - widthOfChar; + var rightEdge = widthOfCharsOnPreviousLine; + + var offsetFromLeftEdge = Math.abs(leftEdge - widthOfCharsOnSameLineBeforeCursor); + var offsetFromRightEdge = Math.abs(rightEdge - widthOfCharsOnSameLineBeforeCursor); + + indexOnPrevLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1); + + break; + } + } + + // reached end + if (!foundMatch) { + indexOnPrevLine = textOnPreviousLine.length - 1; + } + + return textOnPreviousLine.length - indexOnPrevLine + textOnSameLineBeforeCursor.length; + }, + /** * Moves cursor up * @param {Event} e Event object */ moveCursorUp: function(e) { - var textBeforeCursor = this.text.slice(0, this.selectionStart); - this.abortCursorAnimation(); this._currentCursorOpacity = 1; - var textOnSameLineBeforeCursor = textBeforeCursor.slice(textBeforeCursor.lastIndexOf('\n') + 1); - var textOnPreviousLine = (textBeforeCursor.match(/\n?(.*)\n.*$/) || {})[1] || ''; - var offset; - - // only change cursor location if there's no selection at the moment - if (textOnSameLineBeforeCursor.length > textOnPreviousLine.length) { - offset = textOnSameLineBeforeCursor.length + 1; - } - else { - offset = textOnPreviousLine.length + 1; - } - - if (e.metaKey) { - // move to start of text - offset = this.selectionStart; - } + var offset = this.getUpCursorOffset(e); if (e.shiftKey) { this.moveCursorUpWithShift(offset); @@ -833,10 +933,16 @@ width = lineLeftOffset; + if (this.flipX) { + // when oject is horizontally flipped we reverse chars + textLines[i] = textLines[i].split('').reverse().join(''); + } + for (var j = 0, jlen = textLines[i].length; j < jlen; j++) { var _char = textLines[i][j]; prevWidth = width; - width += this._getWidthOfChar(this.ctx, _char, i, j) * this.scaleX; + width += this._getWidthOfChar(this.ctx, _char, i, this.flipX ? jlen - j : j) * + this.scaleX; // debugging // var objectLeftTop = this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top'); @@ -862,6 +968,11 @@ newSelectionStart = charIndex + i + 1; } + // 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; }