{"version":3,"sources":["webpack:///./node_modules/fabric/dist/fabric.js"],"names":["fabric","version","exports","document","window","HTMLDocument","Document","implementation","createHTMLDocument","jsdom","virtualWindow","JSDOM","decodeURIComponent","features","FetchExternalResources","resources","jsdomImplForWrapper","implForWrapper","nodeCanvas","Canvas","DOMParser","isTouchSupported","navigator","maxTouchPoints","isLikelyNode","Buffer","SHARED_ATTRIBUTES","DPI","reNum","commaWsp","rePathCommand","reNonWord","fontPaths","iMatrix","svgNS","perfLimitSizeTotal","maxCacheSideLimit","minCacheSideLimit","charWidthsCache","textureSize","disableStyleCopyPaste","enableGLFiltering","devicePixelRatio","webkitDevicePixelRatio","mozDevicePixelRatio","browserShadowBlurConstant","arcToSegmentsCache","boundsOfCurveCache","cachesBoundsOfCurve","forceGLPutImageData","initFilterBackend","isWebglSupported","console","log","maxTextureSize","WebglFilterBackend","tileSize","Canvas2dFilterBackend","eventjs","root","modifyEventListener","modifySelectors","configure","conf","isFinite","eventListenersAgumented","augmentEventListeners","selectorsAugmented","augmentSelectors","add","target","type","listener","eventManager","remove","returnFalse","event","stop","stopPropagation","cancelBubble","cancelBubbleCount","prevent","preventDefault","preventManipulation","returnValue","cancel","blur","node","activeElement","nodeName","contentEditable","getEventSupport","setAttribute","createElement","removeAttribute","isSupported","clone","obj","temp","constructor","key","trigger","fromOverwrite","String","data","param","value","ret","split","o","k","n","length","eventjs_stallOnReady","time","Date","getTime","timeout","ms","interval","setInterval","clearInterval","querySelector","setTimeout","querySelectorAll","createError","arguments","events","n0","length0","createBatchCommands","toLowerCase","indexOf","n1","length1","slice","useCapture","id","getID","Gesture","_gestureHandlers","wrappers","useCall","tmp","self","call","gesture","proxy","eventId","eventList","getEventList","message","error","pointerDefs","pointerDetect","supports","msPointerEnabled","msPointer","touch","mouse","prefix","addEventListener","idx","types","push","counter","object","uniqueID","removeEventListener","createPointerEvent","preventRecord","eventName","pts","changedTouches","getCoords","pt","pointers","pageX","pageY","x","y","newEvent","createEvent","initEvent","originalEvent","oldListener","HTMLElement","augmentEventListener","proto","recall","handle","handler","this","userAgent","match","HTMLDivElement","prototype","HTMLCanvasElement","NodeList","pointerSetup","doc","ownerDocument","minFingers","fingers","maxFingers","Infinity","position","enabled","env","defaultListener","onPointerDown","onPointerMove","onPointerUp","reset","pause","opt","move","up","resume","tracker","sp","isMouse","isMSPointer","isTouch","pointerStart","toUpperCase","addTouchStart","sid","bbox","track","offsetX","offsetY","x1","y1","scrollLeft","scrollTop","rotation","scale","startTime","moveTime","start","isTouchStart","touches","i","identifier","ids","join","rid","getBoundingBox","pointerEnd","exists","gestureFingers","Array","pointerId","documentElement","clientX","clientY","getCoord","pX","pY","getPropertyAsFloat","parseFloat","getPropertyValue","body","bcr","getBoundingClientRect","width","height","left","top","scaleX","offsetWidth","scaleY","offsetHeight","style","getComputedStyle","borderBox","right","bottom","border","x2","y2","parentNode","undefined","scrollBodyLeft","pageXOffset","scrollBodyTop","pageYOffset","metaKeys","agent","mac","91","93","224","17","metaTrackerReset","fnKey","metaKey","escKey","ctrlKey","shiftKey","altKey","metaTracker","isKeyDown","keyCode","MutationObserver","WebKitMutationObserver","MozMutationObserver","DOMAttrModifiedSupported","p","flag","fn","attachEvent","container","callback","options","subtree","attributes","observer","mutations","forEach","e","attributeName","observe","attrName","propertyName","click","pointer","newbbox","point","state","dbltap","dblclick","time0","time1","pointer0","pointer1","delay","clearTimeout","ax","ay","Math","abs","dragElement","that","drag","monitor","RAD_DEG","PI","getCentroid","points","centroidx","centroidy","sids","parseInt","distance","dx","dy","sqrt","angle","atan2","rotate","DEG2","DEG1","pointerdown","pointermove","pointerup","isPointerEmitter","isDown","shake","acceleration","accelerationIncludingGravity","onDeviceMotion","threshold","timeframe","shakes","lastShake","gravity","z","delta","count","alpha","now","letter","ACCELERATION","DELTA","span","swipe","snap","velocity1","degree1","endx","endy","xdist","ydist","degree2","velocity2","velocity","longpress","tap","timestamp","driftDeviance","end","scrollX","scrollY","wheelPreventElasticBounce","el","preventElasticBounce","wheel","wheelDelta","scrollHeight","onMouseWheel","detail","Event","resizeCanvasIfNeeded","pipelineState","targetCanvas","dWidth","destinationWidth","dHeight","destinationHeight","copyGLTo2DDrawImage","gl","glCanvas","canvas","ctx","getContext","translate","sourceY","drawImage","copyGLTo2DPutImageData","numBytes","u8","Uint8Array","imageBuffer","u8Clamped","Uint8ClampedArray","readPixels","RGBA","UNSIGNED_BYTE","imgData","ImageData","putImageData","orientation","previous","current","onOrientationChange","DeviceOrientationEvent","_removeEventListener","__eventListeners","eventListener","util","array","fill","on","prop","_once","_handler","apply","off","bind","once","fire","listenersForEvent","len","filter","Observable","Collection","_objects","_onObjectAdded","renderOnAddRemove","requestRenderAll","insertAt","index","nonSplicing","objects","splice","somethingRemoved","_onObjectRemoved","forEachObject","context","getObjects","concat","item","isEmpty","size","contains","deep","some","complexity","reduce","memo","CommonMethods","_setOptions","set","_initGradient","filler","property","colorStops","Gradient","_initPattern","source","Pattern","_setObject","_set","toggle","get","global","pow","PiBy180","PiBy2","cos","angleSlice","sin","sign","removeFromArray","getRandomInt","min","max","floor","random","degreesToRadians","degrees","radiansToDegrees","radians","rotatePoint","origin","newPoint","Point","v","rotateVector","addEquals","vector","rx","ry","createVector","from","to","calcAngleBetweenVectors","a","b","acos","hypot","getHatVector","multiply","getBisector","A","B","C","AB","AC","ro","phi","projectStrokeOnPoints","openPath","coords","s","strokeWidth","strokeUniformScalar","strokeUniform","getStrokeHatVector","scalar","miterVector","bisector","bisectorVector","strokeLineJoin","strokeMiterLimit","subtract","SQRT2","transformPoint","t","ignoreOffset","makeBoundingBoxFromPoints","transform","xPoints","minX","maxX","yPoints","minY","maxY","invertTransform","r","toFixed","number","fractionDigits","Number","parseUnit","fontSize","unit","exec","Text","DEFAULT_SVG_FONT_SIZE","falseFunction","getKlass","namespace","string","camelize","charAt","resolveNamespace","getSvgAttributes","parts","loadImage","url","crossOrigin","img","createImage","onLoadCallback","onload","onerror","src","substring","loadImageInDom","div","appendChild","removeChild","enlivenObjects","reviver","enlivenedObjects","numLoadedObjects","numTotalObjects","onLoaded","klass","fromObject","enlivenObjectEnlivables","enlivenProps","Object","ENLIVEN_PROPS","map","enlivedProps","enlivenPatterns","patterns","numLoadedPatterns","numPatterns","enlivenedPatterns","pattern","groupSVGElements","elements","path","centerPoint","Group","sourcePath","populateWithProperties","destination","properties","isArray","createCanvasElement","copyCanvasElement","newCanvas","toDataURL","canvasEl","format","quality","multiplyTransformMatrices","is2x2","qrDecompose","denom","skewX","skewY","translateX","translateY","calcRotateMatrix","theta","calcDimensionsMatrix","scaleMatrix","flipX","flipY","tan","composeMatrix","matrix","resetObjectTransform","saveObjectTransform","isTransparent","tolerance","_isTransparent","imageData","getImageData","l","parsePreserveAspectRatioAttribute","attribute","align","meetOrSlice","alignX","alignY","aspectRatioAttrs","pop","clearFabricFontCache","fontFamily","limitDimsByArea","ar","maximumArea","roughWidth","perfLimitSizeY","capValue","findScaleToFit","findScaleToCover","matrixToSVG","NUM_FRACTION_DIGITS","removeTransformFromObject","inverted","finalTransform","calcOwnMatrix","applyTransformToObject","addTransformToObject","center","setPositionByOrigin","sizeAfterTransform","dimX","dimY","transformMatrix","mergeClipPaths","c1","c2","calcTransformMatrix","clipPath","_join","commandLengths","m","h","c","q","repeatedCommands","M","segmentToBezier","th2","th3","cosTh","sinTh","cx1","cy1","mT","fromX","fromY","costh2","sinth2","costh3","sinth3","toX","toY","cp1X","cp1Y","cp2X","cp2Y","arcToSegments","large","sweep","rotateX","th","px","py","rx2","ry2","py2","px2","pl","cx","cy","mTheta","calcVectorAngle","dtheta","segments","ceil","result","mDelta","ux","uy","vx","vy","ta","tb","getBoundsOfCurve","x0","y0","x3","y3","argsString","t1","t2","b2ac","sqrtb2ac","tvalues","bounds","mt","j","jlen","fromArcToBeziers","fx","fy","rot","tx","ty","segsNorm","makePathSimpler","converted","controlX","controlY","destinationPath","calcLineLength","CB1","CB2","CB3","CB4","getPointOnCubicBezierIterator","p1x","p1y","p2x","p2y","p3x","p3y","p4x","p4y","pct","c3","c4","getTangentCubicIterator","invT","tangentX","tangentY","QB1","QB2","QB3","getPointOnQuadraticBezierIterator","getTangentQuadraticIterator","pathIterator","iterator","perc","tempP","tmpLen","findPercentageForDistance","segInfo","nextLen","lastPerc","nextStep","angleFinder","getPathSegmentsInfo","tempInfo","totalLength","info","command","destX","destY","getPointOnPath","infos","segPercent","segment","lerp","parsePath","pathString","currentPath","parsed","coordsStr","re","rNumber","rNumberCommaWsp","rFlagCommaWsp","rArcSeq","regArcArgumentSequence","RegExp","coordsParsed","trim","args","isNaN","commandLength","repeatedCommand","klen","getSmoothPathFromPoints","correction","p1","p2","multSignX","multSignY","manyPoints","eq","midPoint","midPointFrom","transformPath","pathOffset","pathSegment","newSegment","joinPath","pathData","invoke","method","byProperty","find","value1","value2","condition","extend","Element","hasOwnProperty","replace","character","capitalize","firstLetterOnly","escapeXml","graphemeSplit","textstring","chr","graphemes","getWholeChar","str","code","charCodeAt","next","prev","emptyFunction","IS_DONTENUM_BUGGY","toString","addMethods","parent","superclass","valueOf","Subclass","callSuper","methodName","parentMethod","_this","superClassMethod","createClass","initialize","shift","subclasses","couldUseAttachEvent","touchEvents","getTouchInfo","touchProp","addListener","element","removeListener","getPointer","scroll","getScrollLeftTop","_evt","isTouchEvent","pointerType","setStyle","styles","elementStyle","cssText","setOpacity","normalizedProperty","styleFloat","parseEl","supportsOpacity","opacity","supportsFilters","reOpacity","es","currentStyle","hasLayout","zoom","test","_slice","getById","getElementById","sliceCanConvertNodelists","getElementStyle","toArray","arrayLike","childNodes","err","makeElement","tagName","className","htmlFor","addClass","wrapElement","wrapper","replaceChild","docElement","host","nodeType","getElementOffset","docElem","scrollLeftTop","box","offset","offsetAttributes","borderLeftWidth","borderTopWidth","paddingLeft","paddingTop","attr","clientLeft","clientTop","getNodeCanvas","impl","_canvas","_image","cleanUpJsdomNode","_currentSrc","_attributes","_classList","setImageSmoothing","imageSmoothingEnabled","webkitImageSmoothingEnabled","mozImageSmoothingEnabled","msImageSmoothingEnabled","oImageSmoothingEnabled","arr","defaultView","selectProp","makeElementUnselectable","onselectstart","unselectable","makeElementSelectable","addParamToUrl","emptyFn","request","onComplete","xhr","XMLHttpRequest","parameters","onreadystatechange","readyState","open","setRequestHeader","send","warn","RUNNING_ANIMATIONS","noop","defaultEasing","d","animate","removeFromRegistry","runningAnimations","currentValue","startValue","completionRate","durationRate","requestAnimFrame","duration","finish","onChange","abort","easing","isMany","endValue","byValue","onStart","tick","ticktime","currentTime","timePerc","_value","valuePerc","cancelAll","animations","animation","cancelByCanvas","cancelled","cancelByTarget","findAnimationsByTarget","findAnimationIndex","cancelFunc","findAnimation","_requestAnimFrame","requestAnimationFrame","webkitRequestAnimationFrame","mozRequestAnimationFrame","oRequestAnimationFrame","msRequestAnimationFrame","_cancelAnimFrame","cancelAnimationFrame","cancelAnimFrame","calculateColor","begin","pos","color","animateColor","fromColor","toColor","startColor","Color","getSource","endColor","originalOnComplete","originalOnChange","posValue","colorEasing","normalize","asin","elastic","opts","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","easeInSine","easeOutSine","easeInOutSine","easeInExpo","easeOutExpo","easeInOutExpo","easeInCirc","easeOutCirc","easeInOutCirc","easeInElastic","easeOutElastic","easeInOutElastic","easeInBack","easeOutBack","easeInOutBack","easeInBounce","easeOutBounce","easeInOutBounce","ease","easeInQuad","easeOutQuad","easeInOutQuad","easeInCubic","svgValidTagNames","svgViewBoxElements","svgInvalidAncestors","svgValidParents","attributesMap","display","visibility","colorAttributes","stroke","fSize","cPath","normalizeAttr","normalizeValue","parentAttributes","parseTransformAttribute","visible","fillIndex","strokeIndex","getSvgRegex","_setStrokeFillOpacity","setAlpha","getAlpha","toRgba","_getMultipleNodes","nodeNames","nodeList","nodeArray","getElementsByTagName","parseStyleString","oStyle","chunk","pair","parseStyleObject","getGlobalStylesForElement","svgUid","rule","cssRules","elementMatchesRule","selectors","firstMatching","parentMatching","selectorMatches","doesSomeParentMatch","selector","matcher","classNames","getAttribute","elementById","nodelist","parseUseDirectives","xlinkAttribute","attrs","xlink","el2","cloneNode","currentTrans","oldLength","applyViewboxTransform","el3","createElementNS","setAttributeNS","nodeValue","firstChild","svgValidTagNamesRegEx","svgViewBoxElementsRegEx","svgInvalidAncestorsRegEx","svgValidParentsRegEx","gradientDefs","clipPaths","rotateMatrix","multiplierX","multiplierY","skewMatrix","translateMatrix","transforms","transformList","reTransformList","reTransform","attributeValue","matrices","operation","combinedMatrix","reViewBoxAttrValue","viewBoxWidth","viewBoxHeight","viewBoxAttr","widthAttr","heightAttr","preserveAspectRatio","missingViewBox","missingDimAttr","toBeParsed","parsedDim","widthDiff","heightDiff","hasAncestorWithNodeName","recursivelyParseGradientsXlink","gradient","gradientsAttrs","xlinkAttr","xLink","referencedGradient","hasAttribute","children","referenceClone","parseSVGDocument","parsingOptions","__uid","descendants","selectNodes","getGradientDefs","getCSSRules","parseElements","instances","reFontDeclaration","parseFontDeclaration","fontStyle","fontWeight","lineHeight","tagArray","elList","parseAttributes","parentFontSize","ownAttributes","cssAttrs","parseStyleAttribute","normalizedAttr","normalizedValue","normalizedStyle","font","mergedAttrs","ElementsParser","parse","parsePointsAttribute","parsedPoints","rules","allRules","styleContents","textContent","ruleObj","declaration","propertyValuePairs","_rule","loadSVGFromURL","xml","responseXML","results","_options","allElements","loadSVGFromString","parser","parseFromString","regexUrl","numElements","createObjects","createObject","findTag","fromElement","createCallback","checkIfDone","resolveGradient","Image","_originalElement","_removeTransformMatrix","resolveClipPath","extractPropertyDefinition","storage","regex","lastIndex","gradientDef","opacityAttr","createClipPathCallback","_newObj","fillRule","clipRule","usingElement","objTransformInv","gTransform","clipPathTag","clipPathOwner","scalarAdd","scalarAddEquals","subtractEquals","scalarSubtract","scalarSubtractEquals","multiplyEquals","divide","divideEquals","lt","lte","gt","gte","distanceFrom","setXY","setX","setY","setFromPoint","swap","Intersection","status","appendPoint","appendPoints","intersectLineLine","a1","a2","b1","b2","uaT","ubT","uB","ua","ub","intersectLinePolygon","inter","intersectPolygonPolygon","points1","points2","intersectPolygonRectangle","r1","r2","topRight","bottomLeft","inter1","inter2","inter3","inter4","_tryParsingColor","setSource","hue2rgb","colorNameMap","sourceFromHex","sourceFromRgb","sourceFromHsl","_rgbToHsl","g","round","_source","toRgb","toHsl","hsl","toHsla","toHex","toHexa","toGrayscale","average","currentAlpha","toBlackWhite","overlayWith","otherColor","otherAlpha","otherSource","reRGBa","reHSLa","reHex","aliceblue","antiquewhite","aqua","aquamarine","azure","beige","bisque","black","blanchedalmond","blue","blueviolet","brown","burlywood","cadetblue","chartreuse","chocolate","coral","cornflowerblue","cornsilk","crimson","cyan","darkblue","darkcyan","darkgoldenrod","darkgray","darkgrey","darkgreen","darkkhaki","darkmagenta","darkolivegreen","darkorange","darkorchid","darkred","darksalmon","darkseagreen","darkslateblue","darkslategray","darkslategrey","darkturquoise","darkviolet","deeppink","deepskyblue","dimgray","dimgrey","dodgerblue","firebrick","floralwhite","forestgreen","fuchsia","gainsboro","ghostwhite","gold","goldenrod","gray","grey","green","greenyellow","honeydew","hotpink","indianred","indigo","ivory","khaki","lavender","lavenderblush","lawngreen","lemonchiffon","lightblue","lightcoral","lightcyan","lightgoldenrodyellow","lightgray","lightgrey","lightgreen","lightpink","lightsalmon","lightseagreen","lightskyblue","lightslategray","lightslategrey","lightsteelblue","lightyellow","lime","limegreen","linen","magenta","maroon","mediumaquamarine","mediumblue","mediumorchid","mediumpurple","mediumseagreen","mediumslateblue","mediumspringgreen","mediumturquoise","mediumvioletred","midnightblue","mintcream","mistyrose","moccasin","navajowhite","navy","oldlace","olive","olivedrab","orange","orangered","orchid","palegoldenrod","palegreen","paleturquoise","palevioletred","papayawhip","peachpuff","peru","pink","plum","powderblue","purple","rebeccapurple","red","rosybrown","royalblue","saddlebrown","salmon","sandybrown","seagreen","seashell","sienna","silver","skyblue","slateblue","slategray","slategrey","snow","springgreen","steelblue","teal","thistle","tomato","turquoise","violet","wheat","white","whitesmoke","yellow","yellowgreen","fromRgb","fromSource","fromRgba","fromHsl","fromHsla","fromHex","isShortNotation","isRGBa","oColor","scaleMap","skewMap","controls","LEFT","TOP","RIGHT","BOTTOM","CENTER","opposite","findCornerQuadrant","fabricObject","control","cornerAngle","fireEvent","canvasOptions","scaleIsProportional","eventData","uniScaleKey","uniformIsToggled","uniformScaling","isTransformCentered","originX","originY","scalingIsForbidden","by","scaleProportionally","lockX","lockScalingX","lockY","lockScalingY","scaleCursorStyleHandler","notAllowed","skewCursorStyleHandler","lockSkewingY","lockSkewingX","scaleSkewCursorStyleHandler","altActionKey","scaleOrSkewActionName","isAlternative","rotationStyleHandler","lockRotation","cursorStyle","commonEventInfo","wrapWithFixedAnchor","actionHandler","getCenterPoint","constraint","translateToOriginPoint","actionPerformed","wrapWithFireEvent","getLocalPoint","corner","getZoom","padding","localPoint","toLocalPoint","targetHasOneFlip","compensateScaleForSkew","oppositeSkew","scaleToCompensate","axis","reference","newDim","_getTransformedDimensions","newValue","skewObjectX","newSkew","dimNoSkew","totalSkewSize","currentSkew","hasSkewed","dimBeforeSkewing","skewObjectY","skewHandlerX","localPointFromCenter","finalHandler","skewHandlerY","rotationWithSnapping","pivotPoint","lastAngle","ey","ex","curAngle","hasRotated","snapAngle","snapThreshold","rightAngleLocked","leftAngleLocked","scaleObject","dim","signX","signY","forbidScaling","gestureScale","lockScalingFlip","original","originalDistance","oldScaleX","oldScaleY","scaleObjectFromCorner","scaleObjectX","scaleObjectY","scalingYOrSkewingX","scalingY","scalingXOrSkewingY","scalingX","changeWidth","strokePadding","multiplier","oldWidth","newWidth","dragHandler","newLeft","newTop","moveX","moveY","scalingEqually","controlsUtils","renderCircleControl","styleOverride","xSize","sizeX","cornerSize","ySize","sizeY","transparentCorners","cornerStrokeColor","myLeft","myTop","save","fillStyle","cornerColor","strokeStyle","lineWidth","beginPath","arc","restore","renderSquareControl","xSizeBy2","ySizeBy2","strokeRect","Control","actionName","touchSizeX","touchSizeY","withConnection","mouseDownHandler","mouseUpHandler","getActionHandler","getMouseDownHandler","getMouseUpHandler","cursorStyleHandler","getActionName","getVisibility","controlKey","objectVisibility","_controlsVisibility","setVisibility","positionHandler","finalMatrix","calcCornerCoords","objectAngle","objectCornerSize","centerX","centerY","cosHalfOffset","sinHalfOffset","cosHalfOffsetComp","sinHalfOffsetComp","controlTriangleAngle","cornerHypotenuse","newTheta","newThetaComp","tl","tr","bl","br","render","cornerStyle","getColorStop","colorAlpha","keyValuePairs","getLinearCoords","getRadialCoords","__convertPercentUnitsToValues","instance","svgOptions","gradientUnits","propValue","finalValue","keys","gradientTransform","option","addColorStop","toObject","propertiesToInclude","toSVG","markup","commonAttributes","needsSwap","withViewport","additionalTransform","sort","reverse","minRadius","maxRadius","percentageShift","colorStop","toLive","createLinearGradient","createRadialGradient","colorStopEls","repeat","patternTransform","setOptions","isError","patternSource","patternWidth","patternHeight","patternOffsetX","patternOffsetY","patternImgSrc","complete","naturalWidth","naturalHeight","createPattern","Shadow","affectStroke","includeDefaultValues","nonScaling","_parseShadow","shadow","shadowStr","offsetsAndBlur","reOffsetsAndBlur","fBoxX","fBoxY","BLUR_BOX","StaticCanvas","CANVAS_INIT_ERROR","Error","renderAndResetBound","renderAndReset","requestRenderAllBound","_initStatic","backgroundColor","backgroundImage","overlayColor","overlayImage","stateful","controlsAboveOverlay","allowTouchScrolling","viewportTransform","backgroundVpt","overlayVpt","enableRetinaScaling","vptCoords","skipOffscreen","cb","_createLowerCanvas","_initOptions","interactive","_initRetinaScaling","setOverlayImage","setBackgroundImage","setBackgroundColor","setOverlayColor","calcOffset","_isRetinaScaling","getRetinaScaling","scaleRatio","__initRetinaScaling","lowerCanvasEl","contextContainer","upperCanvasEl","contextTop","_offset","image","__setBgOverlayImage","__setBgOverlayColor","_createCanvasElement","_originalCanvasStyle","_applyCanvasStyle","getWidth","getHeight","setWidth","setDimensions","setHeight","dimensions","cssValue","cssOnly","_setBackstoreDimension","hasLostContext","backstoreOnly","_setCssDimension","_isCurrentlyDrawing","freeDrawingBrush","_setBrushStyles","cacheCanvasEl","wrapperEl","setViewportTransform","vpt","activeObject","_activeObject","backgroundObject","overlayObject","group","setCoords","calcViewportBoundaries","zoomToPoint","before","after","setZoom","absolutePan","relativePan","getElement","setupState","clearContext","clearRect","clear","_hasITextHandlers","_mouseUpITextHandler","_iTextInstances","renderAll","canvasToDrawOn","renderCanvas","isRendering","iVpt","cancelRequestedRender","_renderBackground","_renderObjects","drawControls","shouldCache","_transformDone","renderCache","forClipping","drawClipPathOnCanvas","_renderOverlay","globalCompositeOperation","zoomX","zoomY","_cacheCanvas","cacheTranslationX","cacheTranslationY","_renderBackgroundOrOverlay","needsVpt","moveTo","lineTo","closePath","getCenter","centerObjectH","_centerObject","centerObjectV","centerObject","viewportCenterObject","vpCenter","getVpCenter","viewportCenterObjectH","viewportCenterObjectV","toDatalessJSON","toDatalessObject","_toObjectMethod","_toObjects","excludeFromExport","_toObject","__serializeBgOverlay","originalValue","bgImage","bgColor","background","overlay","svgViewportTransformation","_setSVGPreamble","_setSVGHeader","clipPathId","_setSVGBgOverlayColor","_setSVGBgOverlayImage","_setSVGObjects","suppressPreamble","encoding","viewBox","createSVGFontFacesMarkup","createSVGRefElementsMarkup","createSVGClipPathMarkup","toClipPathSVG","shouldTransform","row","rowIndex","_char","charIndex","fontList","_setSVGObject","finalWidth","finalHeight","shouldInvert","sendToBack","objs","activeSelection","unshift","bringToFront","sendBackwards","intersecting","newIdx","objsMoved","_findNewLowerIndex","isIntersecting","intersectsWithObject","isContainedWithinObject","bringForward","_findNewUpperIndex","dispose","classList","DataURLExporter","EMPTY_JSON","setLineDash","toJSON","createPNGStream","createJPEGStream","BaseBrush","strokeLineCap","strokeDashArray","limitedToCanvasSize","lineCap","miterLimit","lineJoin","_saveAndTransform","_setShadow","shadowColor","shadowBlur","shadowOffsetX","shadowOffsetY","needsFullRender","_resetShadow","_isOutSideCanvas","PencilBrush","decimate","drawStraightLine","straightLineKey","_points","_hasStraightLine","_drawSegment","quadraticCurveTo","onMouseDown","_isMainEvent","_prepareForDrawing","_captureDrawingPath","_render","onMouseMove","oldEnd","onMouseUp","_finalizeAndAddPath","_reset","_addPoint","pointerPoint","convertPointsToSVGPath","_isEmptySVGPath","createPath","Path","decimatePoints","cDistance","adjustedDistance","lastPoint","newPoints","CircleBrush","drawDot","addPoint","dot","radius","originalRenderOnAddRemove","circles","circle","Circle","circleRadius","circleColor","SprayBrush","density","dotWidth","dotWidthVariance","randomOpacity","optimizeOverlapping","sprayChunks","addSprayChunk","sprayChunkPoints","rects","ilen","sprayChunk","rect","Rect","_getOptimizedRects","uniqueRects","uniqueRectsArray","globalAlpha","fillRect","PatternBrush","getPatternSrc","dotDistance","patternCanvas","patternCtx","getPatternSrcFunction","getPattern","topLeft","_getLeftTopCoords","_initInteractive","_createCacheCanvas","centeredScaling","centeredRotation","centeredKey","selection","selectionKey","altSelectionKey","selectionColor","selectionDashArray","selectionBorderColor","selectionLineWidth","selectionFullyContained","hoverCursor","moveCursor","defaultCursor","freeDrawingCursor","notAllowedCursor","containerClass","perPixelTargetFind","targetFindTolerance","skipTargetFind","isDrawingMode","preserveObjectStacking","stopContextMenu","fireRightClick","fireMiddleClick","targets","enablePointerEvents","_hoveredTarget","_hoveredTargets","_currentTransform","_groupSelector","_initWrapperElement","_createUpperCanvas","_initEventListeners","_chooseObjectsToRender","objsToRender","activeGroupObjects","activeObjects","getActiveObjects","contextTopDirty","renderTopLayer","_drawSelection","renderTop","_normalizePointer","invertedM","vptPointer","restorePointerVpt","isTargetTransparent","normalizedPointer","targetRelativeX","targetRelativeY","_cacheContext","contextCache","originalColor","selectionBackgroundColor","_isSelectionKeyPressed","selectionKeyPressed","_shouldClearSelection","evented","selectable","_shouldCenterTransform","action","centerTransform","_getOriginFromCorner","_getActionFromCorner","alreadySelected","_setupCurrentTransform","__corner","lastX","lastY","_beforeTransform","setCursor","cursor","viewportStart","viewportExtent","extent","strokeOffset","_setLineDash","findTarget","skipGroup","activeTarget","activeTargetSubs","ignoreZoom","aObjects","shouldLookForActive","_findTargetCorner","_searchPossibleTargets","_checkTarget","globalPointer","containsPoint","isEditing","subTarget","objToCheck","pointerToUse","subTargetCheck","_absolutePointer","_pointer","cssScale","boundsWidth","boundsHeight","retinaScaling","lowerCanvasClass","_copyCanvasStyle","getTopContext","fromEl","toEl","getSelectionContext","getSelectionElement","getActiveObject","active","_discardActiveObject","_fireSelectionEvents","oldObjects","somethingChanged","added","removed","oldObject","selected","deselected","setActiveObject","currentActives","_setActiveObject","onSelect","onDeselect","discardActiveObject","removeListeners","_renderControls","originalProperties","_realizeGroupTransformOnObject","_unwindGroupTransformOnObject","layoutProps","originalValues","clearContextTop","RIGHT_CLICK","MIDDLE_CLICK","LEFT_CLICK","addEventOptions","passive","checkClick","button","mainTouchId","_bindEvents","addOrRemove","_getEventPrefix","functor","eventjsFunctor","canvasElement","eventTypePrefix","_onResize","_onMouseDown","_onMouseMove","_onMouseOut","_onMouseEnter","_onMouseWheel","_onContextMenu","_onDoubleClick","_onDragOver","_onDragEnter","_onDragLeave","_onDrop","_onTouchStart","_onGesture","_onDrag","_onOrientationChange","_onShake","_onLongPress","_onMouseUp","_onTouchEnd","eventsBound","_simpleEventHandler","__onTransformGesture","__onDrag","__onMouseWheel","_target","hiddenTextarea","focus","__onOrientationChange","__onShake","__onLongPress","_fireEnterLeaveEvents","_cacheTransformEventData","_handleEvent","_resetTransformEventData","getPointerId","evt","isPrimary","__onMouseDown","__onMouseUp","_willAddMouseDown","__onMouseMove","_shouldRender","groupSelector","shouldRender","isClick","_onMouseUpInDrawingMode","_finalizeCurrentTransform","targetWasActive","_maybeGroupObjects","activeOn","isMoving","originalControl","originalMouseUpHandler","_setCursorFromEvent","eventType","subTargets","absolutePointer","currentTarget","currentSubTargets","_scaling","hasStateChanged","_fire","_onMouseDownInDrawingMode","_onMouseMoveInDrawingMode","_previousPointer","shouldGroup","_shouldGroup","_handleGrouping","saveState","_transformObject","_fireOverOutEvents","fireSyntheticInOutEvents","oldTarget","evtOut","canvasEvtOut","evtIn","canvasEvtIn","_draggedoverTarget","config","inOpt","outOpt","outFires","inFires","targetChanged","previousTarget","nextTarget","_performTransformAction","getCornerCursor","_updateActiveSelection","_createActiveSelection","currentActiveObjects","removeWithUpdate","addWithUpdate","_createGroup","isActiveLower","groupObjects","exitEditing","ActiveSelection","_groupSelectedObjects","aGroup","_collectObjects","currentObject","selectionX1Y1","selectionX2Y2","allowIntersect","intersectsWithRect","isContainedWithinRect","toCanvasElement","cropping","scaledWidth","scaledHeight","originalWidth","originalHeight","newZoom","vp","originalInteractive","newVp","originalRetina","originalContextTop","loadFromJSON","json","serialized","JSON","_enlivenObjects","_setBgOverlay","enlivenedCanvasClip","__setupCanvas","loaded","cbIfLoaded","__setBgOverlay","enlivedObject","_toDataURL","_toDataURLWithMultiplier","toDataURLWithMultiplier","stringify","cloneWithoutData","backgroundImageOpacity","backgroundImageStretch","__gesturesParams","__gesturesRenderer","_scaleObjectBy","_rotateObjectByAngle","objectCaching","ALIASING_LIMIT","touchCornerSize","borderColor","borderDashArray","cornerDashArray","strokeDashOffset","borderOpacityWhenMoving","borderScaleFactor","minScaleLimit","hasControls","hasBorders","lockMovementX","lockMovementY","statefullCache","noScaleCache","dirty","paintFirst","stateProperties","cacheProperties","colorProperties","absolutePositioned","_cacheProperties","_updateCacheCanvas","_limitCacheSize","dims","limitedDims","capped","_getCacheCanvasDimensions","objectScale","getTotalObjectScaling","neededX","neededY","drawingWidth","drawingHeight","minCacheSize","dimensionsChanged","cacheWidth","cacheHeight","zoomChanged","shouldRedraw","additionalWidth","additionalHeight","shouldResizeCanvas","canvasWidth","canvasHeight","sizeGrowing","sizeShrinking","getHeightOfLine","setTransform","needFullTransform","_removeDefaultValues","getObjectScaling","retina","getObjectOpacity","shouldConstrainValue","isChanged","groupNeedsUpdate","_constrainScale","isOnACache","setOnGroup","getViewportTransform","isNotVisible","isOnScreen","_setupCompositeOperation","drawSelectionBackground","_setOpacity","drawCacheOnCanvas","_removeCacheCanvas","drawObject","propertySet","isCacheDirty","hasStroke","hasFill","needsItsOwnCache","ownCaching","willDrawShadow","drawClipPathOnCache","originalFill","originalStroke","_setClippingProperties","_drawClipPath","skipCanvas","_getNonTransformedDimensions","_removeShadow","_setStrokeStyles","decl","lineDashOffset","_applyPatternForTransformedGradient","_applyPatternGradientTransform","_setFillStyles","dashArray","drawBorders","forActiveSelection","drawBordersInGroup","scaling","multX","multY","_renderPaintInOrder","_renderStroke","_renderFill","pCtx","pCanvas","_findCenterFromElement","_assignTransformMatrixProps","preserveAspectRatioOptions","cropX","cropY","offsetLeft","offsetTop","objectForm","_fromObject","cloneAsImage","utils","origParams","originalGroup","originalShadow","withoutTransform","withoutShadow","boundingRect","getBoundingRect","shadowOffset","originalCanvas","isType","includes","shouldCenterOrigin","_setOriginToCenter","_resetOrigin","centerH","viewportCenterH","centerV","viewportCenterV","viewportCenter","getLocalPointer","pClicked","objectLeftTop","createAccessors","extraParam","originXOffset","originYOffset","translateToGivenOrigin","fromOriginX","fromOriginY","toOriginX","toOriginY","translateToCenterPoint","leftTop","getPointByOrigin","adjustPosition","offsetFrom","offsetTo","hypotFull","getScaledWidth","xFull","yFull","_originalOriginX","_originalOriginY","originPoint","arrayFromCoords","multiplyMatrices","oCoords","aCoords","lineCoords","ownMatrixCache","matrixCache","_getCoords","absolute","calculate","calcACoords","calcLineCoords","pointTL","pointBR","intersection","other","otherCoords","lines","_getImageLines","_findCrossPoints","_containsCenterOfCanvas","isPartiallyOnScreen","allPointsAreOutside","every","topline","rightline","bottomline","leftline","xi","iLine","xcount","lineKey","getScaledHeight","scaleToWidth","boundingRectFactor","scaleToHeight","cosP","sinP","cosPSinP","cosPMinusSinP","calcOCoords","_calcRotateMatrix","_calcTranslateMatrix","startMatrix","_calculateCurrentDimensions","forEachControl","w","skipCorners","_setCornerCoords","transformMatrixKey","sep","cache","tMatrix","noSkew","_finalizeDimensions","getSvgColorString","getSvgStyles","skipShadow","getSvgFilter","getSvgSpanStyles","useWhiteSpace","term","textDecoration","getSvgTextDecoration","deltaY","decoration","getSvgCommons","getSvgTransform","full","svgTransform","_setSVGBg","textBgRects","_getFillAttributes","_createBaseSVGMarkup","_toSVG","_createBaseClipPathSVGMarkup","objectMarkup","commonPieces","clipPathMarkup","noStyle","styleInfo","shadowInfo","withShadow","vectorEffect","absoluteClipPath","addPaintOrder","originalSet","saveProps","props","tmpObj","_isEqual","origValue","firstPass","dashedPropertySet","forTouch","isControlVisible","touchCorner","controlObject","wh","shouldStroke","setControlVisible","setControlsVisibility","FX_DURATION","fxCenterObjectH","callbacks","empty","fxCenterObjectV","fxRemove","skipCallbacks","propsToAnimate","out","_animate","propPair","propIsColor","valueProgress","timeProgress","coordProps","makeEdgeToOriginGetter","propertyNames","originValues","axis1","axis2","dimension","nearest","farthest","Line","_setWidthHeight","_getLeftToOriginX","_getTopToOriginY","calcLinePoints","origStrokeStyle","xMult","yMult","ATTRIBUTE_NAMES","parsedAttributes","_callback","isValidRadius","startAngle","endAngle","setRadius","svgString","startX","startY","endX","endY","largeFlag","getRadiusX","getRadiusY","Triangle","widthBy2","heightBy2","piBy2","Ellipse","getRx","getRy","_initRxRy","isRounded","bezierCurveTo","Polyline","exactBoundingBox","_setPositionDimensions","_projectStrokeOnPoints","correctLeftTop","calcDim","_calcDimensions","correctSize","fromSVG","diffX","diffY","commonRender","fromElementGenerator","_class","Polygon","_setPath","_renderPathCommands","subpathStartX","subpathStartY","_getOffsetTransform","digits","aX","aY","deltaX","pathUrl","useSetOnGroup","isAlreadyGrouped","_updateObjectsACoords","_calcBounds","_updateObjectsCoords","skipControls","_updateObjectCoords","objectLeft","objectTop","nested","_restoreObjectsState","_includeDefaultValues","objsToObject","originalDefaults","_obj","ownCache","groupMatrix","destroy","toActiveSelection","ungroupOnCanvas","setObjectsCoords","onlyWidthHeight","iLen","jLen","_getBounds","minXY","maxXY","toGroup","newGroup","childrenOverride","srcFromAttribute","_lastScaleX","_lastScaleY","_filterScalingX","_filterScalingY","minimumScaleTrigger","cacheKey","imageSmoothing","filters","_initElement","_element","setElement","removeTexture","_initConfig","applyFilters","resizeFilter","applyResizeFilters","backend","filterBackend","evictCachesForKey","getCrossOrigin","getOriginalSize","_stroke","filterObj","getSrc","hasCrop","strokeSvg","imageMarkup","imageRendering","getSvgSrc","origFill","filtered","setSrc","minimumScale","elementToFilter","_filteredEl","sourceWidth","sourceHeight","isNeutralState","imgElement","_needsResize","elementToDraw","elWidth","elHeight","sX","sY","sW","sH","maxDestW","maxDestH","_resetWidthHeight","CSS_CANVAS","_initFilters","pAR","rWidth","rHeight","pWidth","pHeight","_object","resizeFilters","fromURL","imgOptions","_getAngleValueForStraighten","straighten","fxStraighten","straightenObject","fxStraightenObject","testPrecision","precision","fragmentSource","fragmentShader","createShader","FRAGMENT_SHADER","shaderSource","compileShader","getShaderParameter","COMPILE_STATUS","setupGLContext","captureGPUInfo","getParameter","MAX_TEXTURE_SIZE","precisions","webGlPrecision","createWebGLCanvas","aPosition","Float32Array","chooseFastestCopyGLTo2DMethod","canUseImageData","canMeasurePerf","performance","canUseArrayBuffer","ArrayBuffer","canUseUint8Clamped","copyGLTo2D","drawImageTime","putImageDataTime","testContext","glOptions","premultipliedAlpha","depth","stencil","antialias","clearColor","cachedTexture","getCachedTexture","sourceTexture","createTexture","targetTexture","originalTexture","passes","webgl","programCache","pass","tempFbo","createFramebuffer","bindFramebuffer","FRAMEBUFFER","applyTo","bindTexture","TEXTURE_2D","deleteTexture","deleteFramebuffer","clearWebGLCaches","textureCache","textureImageSource","texture","texParameteri","TEXTURE_MAG_FILTER","NEAREST","TEXTURE_MIN_FILTER","TEXTURE_WRAP_S","CLAMP_TO_EDGE","TEXTURE_WRAP_T","texImage2D","uniqueId","gpuInfo","renderer","vendor","ext","getExtension","UNMASKED_RENDERER_WEBGL","UNMASKED_VENDOR_WEBGL","sourceElement","originalImageData","originalEl","BaseFilter","vertexSource","createProgram","vertexShader","VERTEX_SHADER","getShaderInfoLog","program","attachShader","linkProgram","getProgramParameter","LINK_STATUS","getProgramInfoLog","attributeLocations","getAttributeLocations","uniformLocations","getUniformLocations","uStepW","getUniformLocation","uStepH","getAttribLocation","sendAttributeData","aPositionData","attributeLocation","buffer","createBuffer","bindBuffer","ARRAY_BUFFER","enableVertexAttribArray","vertexAttribPointer","FLOAT","bufferData","STATIC_DRAW","_setupFrameBuffer","framebufferTexture2D","COLOR_ATTACHMENT0","_swapTextures","main","mainParameter","applyToWebGL","applyTo2d","retrieveShader","shader","useProgram","uniform1f","sendUniformData","viewport","drawArrays","TRIANGLE_STRIP","bindAdditionalTexture","textureUnit","activeTexture","TEXTURE0","unbindAdditionalTexture","getMainParameter","setMainParameter","createHelpLayer","helpLayer","mainP","ColorMatrix","colorsOnly","uColorMatrix","uConstants","constants","uniformMatrix4fv","uniform4fv","Brightness","brightness","uBrightness","Convolute","opaque","Convolute_3_1","Convolute_3_0","Convolute_5_1","Convolute_5_0","Convolute_7_1","Convolute_7_0","Convolute_9_1","Convolute_9_0","dstOff","scx","scy","srcOff","wt","weights","side","halfSide","sw","sh","output","createImageData","dst","alphaFac","uMatrix","uOpaque","uHalfSize","uSize","uniform1fv","Grayscale","lightness","luminosity","mode","uMode","uniform1i","Invert","invert","uInvert","Noise","noise","rand","uNoise","uSeed","Pixelate","blocksize","_i","_j","_iLen","_jLen","uBlocksize","RemoveColor","useAlpha","lowC","highC","uLow","uHigh","Brownie","Vintage","Kodachrome","Technicolor","Polaroid","Sepia","BlackWhite","BlendColor","screen","diff","lighten","darken","exclusion","tint","buildSource","tg","alpha1","uColor","BlendImage","mask","TEXTURE1","calculateMatrix","canvas1","blendData","blendImage","uTransformMatrix","uImage","uniformMatrix3fv","Resize","resizeType","lanczosLobes","uDelta","uTaps","uniform2fv","horizontal","taps","filterWindow","getFilterWindow","generateShader","tempScale","getTaps","lobeFunction","lanczosCreate","offsets","fragmentSourceTOP","dW","dH","lobes","xx","rcpScaleX","rcpScaleY","newData","oW","oH","sliceByTwo","hermiteFastResize","bilinearFiltering","lanczosResize","tmpCanvas","mult","doneW","doneH","stepW","stepH","dX","dY","process","u","weight","fX","fY","ratioX","icenter","ratioY","range2X","cacheLanc","range2Y","lanczos","rcpRatioX","rcpRatioY","srcData","destData","destImg","xDiff","yDiff","chnl","origPix","w4","pixels","destImage","destPixels","ratioW","ratioH","ratioWHalf","ratioHHalf","img2","data2","weightsAlpha","gxR","gxG","gxB","gxA","yy","w0","Contrast","contrast","contrastF","uContrast","Saturation","saturation","adjust","uSaturation","Vibrance","vibrance","avg","amt","uVibrance","Blur","aspectRatio","simpleBlur","canvas2","blurLayer1","blurLayer2","percent","ctx1","ctx2","nSamples","newImageData","chooseRightDelta","blurScale","Gamma","gamma","rInv","gInv","bInv","rVals","gVals","bVals","uGamma","uniform3fv","Composed","subFilters","HueRotation","rad","aThird","aThirdSqtSin","OneMinusCos","additionalProps","_dimensionAffectingProps","_reNewline","_reSpacesAndTabs","_reSpaceAndTab","_reWords","underline","overline","linethrough","textAlign","superscript","baseline","subscript","textBackgroundColor","pathStartOffset","pathSide","pathAlign","_fontSizeFraction","_fontSizeMult","charSpacing","_measuringContext","direction","_styleProperties","__charBounds","CACHE_FONT_SIZE","MIN_TEXT_WIDTH","text","__skipDimension","setPathInfo","initDimensions","segmentsInfo","getMeasuringContext","_splitText","newLines","_splitTextIntoLines","textLines","_textLines","graphemeLines","_unwrappedTextLines","_unwrappedLines","_text","graphemeText","_clearCache","calcTextWidth","cursorWidth","calcTextHeight","enlargeSpaces","diffSpace","currentLineWidth","numberOfSpaces","accumulatedSpace","line","charBound","spaces","isEndOfWrapping","getLineWidth","kernedWidth","lineIndex","missingNewlineOffset","_setTextStyles","_renderTextLinesBackground","_renderTextDecoration","_renderText","_renderTextStroke","_renderTextFill","charStyle","forMeasuring","textBaseline","_getFontDeclaration","maxWidth","_renderTextLine","_renderChars","styleHas","heightOfLine","lineLeftOffset","lastColor","charBox","currentColor","drawStart","leftOffset","_getLeftOffset","lineTopOffset","_getTopOffset","boxStart","boxWidth","_getLineLeftOffset","getValueOfPropertyAt","renderLeft","getFontCache","cacheProp","_measureChar","previousChar","prevCharStyle","coupleWidth","previousWidth","fontCache","fontDeclaration","previousFontDeclaration","couple","stylesAreEqual","fontMultiplier","measureText","getHeightOfChar","measureLine","lineInfo","_measureLine","_getWidthOfCharSpacing","grapheme","prevGrapheme","graphemeInfo","startingPoint","totalPathLength","numOfSpaces","lineBounds","positionInPath","_getGraphemeBox","_setGraphemeOnPath","centerPosition","skipLeft","getCompleteStyleDeclaration","prevStyle","previousBox","__lineHeights","maxHeight","_renderTextCommon","lineHeights","isEmptyStyles","actualStyle","nextStyle","timeToRender","drawingLeft","isJustify","charsToRender","shortCut","isLtr","currentDirection","_renderChar","_hasStyleChanged","_applyPatternGradientTransformText","handleFiller","fillOffsets","strokeOffsets","_getStyleDeclaration","fullDecl","shouldFill","fillText","strokeText","setSuperscript","_setScript","setSubscript","schema","loc","get2DCursorLocation","setSelectionStyles","thisStyle","_hasStyleChangedForSvg","lineDiff","__lineWidths","_shouldClearDimensionCache","shouldClear","_forceClearCache","_size","_dy","lastDecoration","currentDecoration","currentFill","lastFill","topOffset","styleObject","family","fontIsGeneric","genericFonts","newLine","newText","allProperties","needsDims","isAddingPath","_key","parsedAnchor","textAnchor","originalStrokeWidth","textHeightScaleFactor","lineHeightDiff","scaledDiff","textHeight","offX","objectCopy","textInstance","pathInstance","p3","0","cleanStyle","letterCount","stylePropertyValue","stylesCount","allStyleObjectPropertiesMatch","graphemeCount","stylePropertyHasBeenSet","removeStyle","lineNum","charNum","_extendStyles","_getLineStyle","_setLineStyle","_setStyleDeclaration","selectionStart","skipWrapping","getSelectionStyles","startIndex","endIndex","selectionEnd","getStyleAtPosition","lineStyle","_deleteStyleDeclaration","_deleteLineStyle","parseDecoration","IText","editable","editingBorderColor","cursorColor","cursorDelay","cursorDuration","caching","hiddenTextareaContainer","_reSpace","_currentCursorOpacity","_selectionDirection","_abortCursorAnimation","__widthOfSpace","inCompositionMode","initBehavior","setSelectionStart","_updateAndFire","setSelectionEnd","_fireSelectionChanged","_updateTextarea","initDelayedCursor","cursorOffsetCache","renderCursorOrSelection","skipRestore","_clearTextArea","boundaries","_getCursorBoundaries","renderCursor","renderSelection","_getCursorBoundariesOffsets","cursorPosition","bound","cursorLocation","charHeight","__isMousedown","startLine","endLine","startChar","endChar","lineOffset","realLineHeight","boxEnd","drawWidth","drawHeight","extraTop","compositionColor","getCurrentCharFontSize","cp","_getCurrentCharIndex","getCurrentCharColor","initAddedHandler","initRemovedHandler","initCursorSelectionHandlers","initDoubleClickSimulation","mouseMoveHandler","_initCanvasHandlers","_removeCanvasHandlers","_tick","_currentTickState","_animateCursor","targetOpacity","completeMethod","tickState","isAborted","_onTickComplete","_cursorTimeout1","_currentTickCompleteState","restart","abortCursorAnimation","_cursorTimeout2","selectAll","getSelectedText","findWordBoundaryLeft","startFrom","findWordBoundaryRight","findLineBoundaryLeft","findLineBoundaryRight","searchWordBoundary","selectWord","newSelectionStart","newSelectionEnd","selectLine","enterEditing","exitEditingOnOthers","initHiddenTextarea","_saveEditingProps","_setEditingProps","_textBeforeEdit","initMouseMoveHandler","getSelectionStartFromPointer","currentStart","currentEnd","__selectionStartOnMouseDown","restartCursorIfNeeded","fromStringToGraphemeSelection","smallerTextStart","graphemeStart","smallerTextEnd","graphemeEnd","fromGraphemeToStringSelection","newSelection","updateTextareaPosition","updateFromTextArea","_calcTextareaPosition","desiredPosition","compositionStart","upperCanvas","upperCanvasWidth","upperCanvasHeight","clientWidth","clientHeight","_savedProps","_restoreEditingProps","isTextChanged","_removeExtraneousStyles","removeStyleFromTo","styleObj","cursorStart","cursorEnd","lineStart","charStart","lineEnd","charEnd","shiftLineStyles","numericChar","clonedStyles","numericLine","insertNewlineStyleObject","qty","copiedStyle","currentCharStyle","newLineStyles","somethingAdded","isEndOfLine","numIndex","styleCarriedOver","insertCharStyleObject","quantity","currentLineStyles","currentLineStylesCloned","numericIndex","newStyle","insertNewStyleBlock","insertedText","cursorLoc","addedLines","linesLength","setSelectionStartEndWithShift","setSelectionInBoundaries","__lastClickTime","__lastLastClickTime","__lastPointer","__newClickTime","newPointer","isTripleClick","_stopEvent","__lastIsEditing","__lastSelected","initMousedownHandler","initMouseupHandler","initClicks","doubleClickHandler","tripleClickHandler","_mouseDownHandler","setCursorByClick","_mouseDownHandlerBefore","currentActive","mouseOffset","prevWidth","_getNewSelectionStartFromOffset","distanceBtwLastCharAndCursor","distanceBtwNextCharAndCursor","onKeyDown","onKeyUp","onInput","copy","paste","onCompositionStart","onCompositionUpdate","onCompositionEnd","_clickHandlerInitialized","onClick","keysMap","9","27","33","34","35","36","37","38","39","40","keysMapRtl","ctrlKeysMapUp","67","88","ctrlKeysMapDown","65","keyMap","stopImmediatePropagation","_copyDone","fromPaste","removedText","removeFrom","removeTo","nextText","charCount","nextCharCount","charDiff","textareaSelection","backDelete","copiedText","copiedTextStyle","compositionEnd","_getClipboardData","clipboardData","_getWidthBeforeCursor","widthBeforeCursor","getDownCursorOffset","isRight","selectionProp","_getSelectionForOffset","indexOnOtherLine","_getIndexOnLine","textAfterCursor","getUpCursorOffset","textBeforeCursor","charWidth","foundMatch","widthOfCharsOnLine","indexOnLine","leftEdge","rightEdge","offsetFromLeftEdge","offsetFromRightEdge","moveCursorDown","_moveCursorUpOrDown","moveCursorUp","moveCursorWithShift","moveCursorWithoutShift","moveCursorLeft","_moveCursorLeftOrRight","_move","_moveLeft","_moveRight","moveCursorLeftWithoutShift","change","moveCursorLeftWithShift","moveCursorRight","moveCursorRightWithShift","moveCursorRightWithoutShift","changed","removeChars","insertChars","multipleSpacesRegex","_getSVGLeftTopOffsets","textAndBg","_getSVGTextAndBg","textTop","textLeft","_wrapSVGTextAndBg","lineTop","noShadow","textSpans","textTopOffset","textLeftOffset","_setSVGTextLineBg","_setSVGTextLineText","_createTextCharSpan","styleDecl","shouldUseWhitespace","styleProps","fillStyles","dySpan","_pushTextBgRect","fillColor","_getSVGLineTopOffset","lastHeight","svgStyle","Textbox","minWidth","dynamicMinWidth","__cachedLines","_wordJoiners","splitByGrapheme","_styleMap","_generateStyleMap","textInfo","realLineCount","realLineCharCount","isWrapping","nextOffset","nextLineIndex","shouldLimit","mapNextLine","_wrapText","desiredWidth","wrapped","_wrapLine","_measureWord","word","charOffset","_line","reservedSpace","words","infix","wordWidth","infixWidth","largestWordWidth","lineJustStarted","additionalSpace","getMinWidth","linesToKeep","scaleSkewStyleHandler","scaleStyleHandler","objectControls","ml","mr","mb","mtr","textBoxControls","__drawClipPath","_needsItsOwnCache","_getSvgCommons","__createBaseClipPathSVGMarkup","__createBaseSVGMarkup","erasable","eraser","_createEraserSVGMarkup","__restoreObjectsState","_addEraserPathToObjects","EraserBrush","_addPathToObjectEraser","applyEraserToObjects","originalTransform","_clipPath","eraserPath","applyClipPathToPath","Eraser","rectSvg","__renderOverlay","isErasing","_isErasing","_isErasable","_prepareCollectionTraversal","collection","restorationContext","preparePattern","_patternCanvas","bgErasable","overlayErasable","clipPathContainerTransformMatrix","pathInvTransform","clipPathTransform","clonePathWithClipPath","objTransform","_path","desiredTransform","__subTargets","applyEraserToCanvas","drawables","drawable"],"mappings":"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","file":"js/group-lesson~f1f6ed5e.0da84c74.js","sourcesContent":["/* build: `node build.js modules=ALL exclude=accessors minifier=uglifyjs` */\n/*! Fabric.js Copyright 2008-2015, Printio (Juriy Zaytsev, Maxim Chernyak) */\n\nvar fabric = fabric || { version: '5.2.1' };\nif (typeof exports !== 'undefined') {\n exports.fabric = fabric;\n}\n/* _AMD_START_ */\nelse if (typeof define === 'function' && define.amd) {\n define([], function() { return fabric; });\n}\n/* _AMD_END_ */\nif (typeof document !== 'undefined' && typeof window !== 'undefined') {\n if (document instanceof (typeof HTMLDocument !== 'undefined' ? HTMLDocument : Document)) {\n fabric.document = document;\n }\n else {\n fabric.document = document.implementation.createHTMLDocument('');\n }\n fabric.window = window;\n}\nelse {\n // assume we're running under node.js when document/window are not present\n var jsdom = require('jsdom');\n var virtualWindow = new jsdom.JSDOM(\n decodeURIComponent('%3C!DOCTYPE%20html%3E%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3C%2Fbody%3E%3C%2Fhtml%3E'),\n {\n features: {\n FetchExternalResources: ['img']\n },\n resources: 'usable'\n }).window;\n fabric.document = virtualWindow.document;\n fabric.jsdomImplForWrapper = require('jsdom/lib/jsdom/living/generated/utils').implForWrapper;\n fabric.nodeCanvas = require('jsdom/lib/jsdom/utils').Canvas;\n fabric.window = virtualWindow;\n DOMParser = fabric.window.DOMParser;\n}\n\n/**\n * True when in environment that supports touch events\n * @type boolean\n */\nfabric.isTouchSupported = 'ontouchstart' in fabric.window || 'ontouchstart' in fabric.document ||\n (fabric.window && fabric.window.navigator && fabric.window.navigator.maxTouchPoints > 0);\n\n/**\n * True when in environment that's probably Node.js\n * @type boolean\n */\nfabric.isLikelyNode = typeof Buffer !== 'undefined' &&\n typeof window === 'undefined';\n\n/* _FROM_SVG_START_ */\n/**\n * Attributes parsed from all SVG elements\n * @type array\n */\nfabric.SHARED_ATTRIBUTES = [\n 'display',\n 'transform',\n 'fill', 'fill-opacity', 'fill-rule',\n 'opacity',\n 'stroke', 'stroke-dasharray', 'stroke-linecap', 'stroke-dashoffset',\n 'stroke-linejoin', 'stroke-miterlimit',\n 'stroke-opacity', 'stroke-width',\n 'id', 'paint-order', 'vector-effect',\n 'instantiated_by_use', 'clip-path',\n];\n/* _FROM_SVG_END_ */\n\n/**\n * Pixel per Inch as a default value set to 96. Can be changed for more realistic conversion.\n */\nfabric.DPI = 96;\nfabric.reNum = '(?:[-+]?(?:\\\\d+|\\\\d*\\\\.\\\\d+)(?:[eE][-+]?\\\\d+)?)';\nfabric.commaWsp = '(?:\\\\s+,?\\\\s*|,\\\\s*)';\nfabric.rePathCommand = /([-+]?((\\d+\\.\\d+)|((\\d+)|(\\.\\d+)))(?:[eE][-+]?\\d+)?)/ig;\nfabric.reNonWord = /[ \\n\\.,;!\\?\\-]/;\nfabric.fontPaths = { };\nfabric.iMatrix = [1, 0, 0, 1, 0, 0];\nfabric.svgNS = 'http://www.w3.org/2000/svg';\n\n/**\n * Pixel limit for cache canvases. 1Mpx , 4Mpx should be fine.\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.perfLimitSizeTotal = 2097152;\n\n/**\n * Pixel limit for cache canvases width or height. IE fixes the maximum at 5000\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.maxCacheSideLimit = 4096;\n\n/**\n * Lowest pixel limit for cache canvases, set at 256PX\n * @since 1.7.14\n * @type Number\n * @default\n */\nfabric.minCacheSideLimit = 256;\n\n/**\n * Cache Object for widths of chars in text rendering.\n */\nfabric.charWidthsCache = { };\n\n/**\n * if webgl is enabled and available, textureSize will determine the size\n * of the canvas backend\n * @since 2.0.0\n * @type Number\n * @default\n */\nfabric.textureSize = 2048;\n\n/**\n * When 'true', style information is not retained when copy/pasting text, making\n * pasted text use destination style.\n * Defaults to 'false'.\n * @type Boolean\n * @default\n */\nfabric.disableStyleCopyPaste = false;\n\n/**\n * Enable webgl for filtering picture is available\n * A filtering backend will be initialized, this will both take memory and\n * time since a default 2048x2048 canvas will be created for the gl context\n * @since 2.0.0\n * @type Boolean\n * @default\n */\nfabric.enableGLFiltering = true;\n\n/**\n * Device Pixel Ratio\n * @see https://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/HTML-canvas-guide/SettingUptheCanvas/SettingUptheCanvas.html\n */\nfabric.devicePixelRatio = fabric.window.devicePixelRatio ||\n fabric.window.webkitDevicePixelRatio ||\n fabric.window.mozDevicePixelRatio ||\n 1;\n/**\n * Browser-specific constant to adjust CanvasRenderingContext2D.shadowBlur value,\n * which is unitless and not rendered equally across browsers.\n *\n * Values that work quite well (as of October 2017) are:\n * - Chrome: 1.5\n * - Edge: 1.75\n * - Firefox: 0.9\n * - Safari: 0.95\n *\n * @since 2.0.0\n * @type Number\n * @default 1\n */\nfabric.browserShadowBlurConstant = 1;\n\n/**\n * This object contains the result of arc to bezier conversion for faster retrieving if the same arc needs to be converted again.\n * It was an internal variable, is accessible since version 2.3.4\n */\nfabric.arcToSegmentsCache = { };\n\n/**\n * This object keeps the results of the boundsOfCurve calculation mapped by the joined arguments necessary to calculate it.\n * It does speed up calculation, if you parse and add always the same paths, but in case of heavy usage of freedrawing\n * you do not get any speed benefit and you get a big object in memory.\n * The object was a private variable before, while now is appended to the lib so that you have access to it and you\n * can eventually clear it.\n * It was an internal variable, is accessible since version 2.3.4\n */\nfabric.boundsOfCurveCache = { };\n\n/**\n * If disabled boundsOfCurveCache is not used. For apps that make heavy usage of pencil drawing probably disabling it is better\n * @default true\n */\nfabric.cachesBoundsOfCurve = true;\n\n/**\n * Skip performance testing of setupGLContext and force the use of putImageData that seems to be the one that works best on\n * Chrome + old hardware. if your users are experiencing empty images after filtering you may try to force this to true\n * this has to be set before instantiating the filtering backend ( before filtering the first image )\n * @type Boolean\n * @default false\n */\nfabric.forceGLPutImageData = false;\n\nfabric.initFilterBackend = function() {\n if (fabric.enableGLFiltering && fabric.isWebglSupported && fabric.isWebglSupported(fabric.textureSize)) {\n console.log('max texture size: ' + fabric.maxTextureSize);\n return (new fabric.WebglFilterBackend({ tileSize: fabric.textureSize }));\n }\n else if (fabric.Canvas2dFilterBackend) {\n return (new fabric.Canvas2dFilterBackend());\n }\n};\n\n\nif (typeof document !== 'undefined' && typeof window !== 'undefined') {\n // ensure globality even if entire library were function wrapped (as in Meteor.js packaging system)\n window.fabric = fabric;\n}\n\n\n/*:\n\t----------------------------------------------------\n\tevent.js : 1.1.5 : 2014/02/12 : MIT License\n\t----------------------------------------------------\n\thttps://github.com/mudcube/Event.js\n\t----------------------------------------------------\n\t1 : click, dblclick, dbltap\n\t1+ : tap, longpress, drag, swipe\n\t2+ : pinch, rotate\n\t : mousewheel, devicemotion, shake\n\t----------------------------------------------------\n\tIdeas for the future\n\t----------------------------------------------------\n\t* GamePad, and other input abstractions.\n\t* Event batching - i.e. for every x fingers down a new gesture is created.\n\t----------------------------------------------------\n\thttp://www.w3.org/TR/2011/WD-touch-events-20110505/\n\t----------------------------------------------------\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\n\n(function(root) { \"use strict\";\n\n// Add custom *EventListener commands to HTMLElements (set false to prevent funkiness).\nroot.modifyEventListener = false;\n\n// Add bulk *EventListener commands on NodeLists from querySelectorAll and others (set false to prevent funkiness).\nroot.modifySelectors = false;\n\nroot.configure = function(conf) {\n\tif (isFinite(conf.modifyEventListener)) root.modifyEventListener = conf.modifyEventListener;\n\tif (isFinite(conf.modifySelectors)) root.modifySelectors = conf.modifySelectors;\n\t/// Augment event listeners\n\tif (eventListenersAgumented === false && root.modifyEventListener) {\n\t\taugmentEventListeners();\n\t}\n\tif (selectorsAugmented === false && root.modifySelectors) {\n\t\taugmentSelectors();\n\t}\n};\n\n// Event maintenance.\nroot.add = function(target, type, listener, configure) {\n\treturn eventManager(target, type, listener, configure, \"add\");\n};\n\nroot.remove = function(target, type, listener, configure) {\n\treturn eventManager(target, type, listener, configure, \"remove\");\n};\n\nroot.returnFalse = function(event) {\n\treturn false;\n};\n\nroot.stop = function(event) {\n\tif (!event) return;\n\tif (event.stopPropagation) event.stopPropagation();\n\tevent.cancelBubble = true; // <= IE8\n\tevent.cancelBubbleCount = 0;\n};\n\nroot.prevent = function(event) {\n\tif (!event) return;\n\tif (event.preventDefault) {\n\t\tevent.preventDefault();\n\t} else if (event.preventManipulation) {\n\t\tevent.preventManipulation(); // MS\n\t} else {\n\t\tevent.returnValue = false; // <= IE8\n\t}\n};\n\nroot.cancel = function(event) {\n\troot.stop(event);\n\troot.prevent(event);\n};\n\nroot.blur = function() { // Blurs the focused element. Useful when using eventjs.cancel as canceling will prevent focused elements from being blurred.\n\tvar node = document.activeElement;\n\tif (!node) return;\n\tvar nodeName = document.activeElement.nodeName;\n\tif (nodeName === \"INPUT\" || nodeName === \"TEXTAREA\" || node.contentEditable === \"true\") {\n\t\tif (node.blur) node.blur();\n\t}\n};\n\n// Check whether event is natively supported (via @kangax)\nroot.getEventSupport = function (target, type) {\n\tif (typeof(target) === \"string\") {\n\t\ttype = target;\n\t\ttarget = window;\n\t}\n\ttype = \"on\" + type;\n\tif (type in target) return true;\n\tif (!target.setAttribute) target = document.createElement(\"div\");\n\tif (target.setAttribute && target.removeAttribute) {\n\t\ttarget.setAttribute(type, \"\");\n\t\tvar isSupported = typeof target[type] === \"function\";\n\t\tif (typeof target[type] !== \"undefined\") target[type] = null;\n\t\ttarget.removeAttribute(type);\n\t\treturn isSupported;\n\t}\n};\n\nvar clone = function (obj) {\n\tif (!obj || typeof (obj) !== 'object') return obj;\n\tvar temp = new obj.constructor();\n\tfor (var key in obj) {\n\t\tif (!obj[key] || typeof (obj[key]) !== 'object') {\n\t\t\ttemp[key] = obj[key];\n\t\t} else { // clone sub-object\n\t\t\ttemp[key] = clone(obj[key]);\n\t\t}\n\t}\n\treturn temp;\n};\n\n/// Handle custom *EventListener commands.\nvar eventManager = function(target, type, listener, configure, trigger, fromOverwrite) {\n\tconfigure = configure || {};\n\t// Check whether target is a configuration variable;\n\tif (String(target) === \"[object Object]\") {\n\t\tvar data = target;\n\t\ttarget = data.target; delete data.target;\n\t\t///\n\t\tif (data.type && data.listener) {\n\t\t\ttype = data.type; delete data.type;\n\t\t\tlistener = data.listener; delete data.listener;\n\t\t\tfor (var key in data) {\n\t\t\t\tconfigure[key] = data[key];\n\t\t\t}\n\t\t} else { // specialness\n\t\t\tfor (var param in data) {\n\t\t\t\tvar value = data[param];\n\t\t\t\tif (typeof(value) === \"function\") continue;\n\t\t\t\tconfigure[param] = value;\n\t\t\t}\n\t\t\t///\n\t\t\tvar ret = {};\n\t\t\tfor (var key in data) {\n\t\t\t\tvar param = key.split(\",\");\n\t\t\t\tvar o = data[key];\n\t\t\t\tvar conf = {};\n\t\t\t\tfor (var k in configure) { // clone base configuration\n\t\t\t\t\tconf[k] = configure[k];\n\t\t\t\t}\n\t\t\t\t///\n\t\t\t\tif (typeof(o) === \"function\") { // without configuration\n\t\t\t\t\tvar listener = o;\n\t\t\t\t} else if (typeof(o.listener) === \"function\") { // with configuration\n\t\t\t\t\tvar listener = o.listener;\n\t\t\t\t\tfor (var k in o) { // merge configure into base configuration\n\t\t\t\t\t\tif (typeof(o[k]) === \"function\") continue;\n\t\t\t\t\t\tconf[k] = o[k];\n\t\t\t\t\t}\n\t\t\t\t} else { // not a listener\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\t///\n\t\t\t\tfor (var n = 0; n < param.length; n ++) {\n\t\t\t\t\tret[key] = eventjs.add(target, param[n], listener, conf, trigger);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t}\n\t///\n\tif (!target || !type || !listener) return;\n\t// Check for element to load on interval (before onload).\n\tif (typeof(target) === \"string\" && type === \"ready\") {\n\t\tif (window.eventjs_stallOnReady) { /// force stall for scripts to load\n\t\t\ttype = \"load\";\n\t\t\ttarget = window;\n\t\t} else { //\n\t\t\tvar time = (new Date()).getTime();\n\t\t\tvar timeout = configure.timeout;\n\t\t\tvar ms = configure.interval || 1000 / 60;\n\t\t\tvar interval = window.setInterval(function() {\n\t\t\t\tif ((new Date()).getTime() - time > timeout) {\n\t\t\t\t\twindow.clearInterval(interval);\n\t\t\t\t}\n\t\t\t\tif (document.querySelector(target)) {\n\t\t\t\t\twindow.clearInterval(interval);\n\t\t\t\t\tsetTimeout(listener, 1);\n\t\t\t\t}\n\t\t\t}, ms);\n\t\t\treturn;\n\t\t}\n\t}\n\t// Get DOM element from Query Selector.\n\tif (typeof(target) === \"string\") {\n\t\ttarget = document.querySelectorAll(target);\n\t\tif (target.length === 0) return createError(\"Missing target on listener!\", arguments); // No results.\n\t\tif (target.length === 1) { // Single target.\n\t\t\ttarget = target[0];\n\t\t}\n\t}\n\n\t/// Handle multiple targets.\n\tvar event;\n\tvar events = {};\n\tif (target.length > 0 && target !== window) {\n\t\tfor (var n0 = 0, length0 = target.length; n0 < length0; n0 ++) {\n\t\t\tevent = eventManager(target[n0], type, listener, clone(configure), trigger);\n\t\t\tif (event) events[n0] = event;\n\t\t}\n\t\treturn createBatchCommands(events);\n\t}\n\n\t/// Check for multiple events in one string.\n\tif (typeof(type) === \"string\") {\n\t\ttype = type.toLowerCase();\n\t\tif (type.indexOf(\" \") !== -1) {\n\t\t\ttype = type.split(\" \");\n\t\t} else if (type.indexOf(\",\") !== -1) {\n\t\t\ttype = type.split(\",\");\n\t\t}\n\t}\n\n\t/// Attach or remove multiple events associated with a target.\n\tif (typeof(type) !== \"string\") { // Has multiple events.\n\t\tif (typeof(type.length) === \"number\") { // Handle multiple listeners glued together.\n\t\t\tfor (var n1 = 0, length1 = type.length; n1 < length1; n1 ++) { // Array [type]\n\t\t\t\tevent = eventManager(target, type[n1], listener, clone(configure), trigger);\n\t\t\t\tif (event) events[type[n1]] = event;\n\t\t\t}\n\t\t} else { // Handle multiple listeners.\n\t\t\tfor (var key in type) { // Object {type}\n\t\t\t\tif (typeof(type[key]) === \"function\") { // without configuration.\n\t\t\t\t\tevent = eventManager(target, key, type[key], clone(configure), trigger);\n\t\t\t\t} else { // with configuration.\n\t\t\t\t\tevent = eventManager(target, key, type[key].listener, clone(type[key]), trigger);\n\t\t\t\t}\n\t\t\t\tif (event) events[key] = event;\n\t\t\t}\n\t\t}\n\t\treturn createBatchCommands(events);\n\t} else if (type.indexOf(\"on\") === 0) { // to support things like \"onclick\" instead of \"click\"\n\t\ttype = type.slice(2);\n\t}\n\n\t// Ensure listener is a function.\n\tif (typeof(target) !== \"object\") return createError(\"Target is not defined!\", arguments);\n\tif (typeof(listener) !== \"function\") return createError(\"Listener is not a function!\", arguments);\n\n\t// Generate a unique wrapper identifier.\n\tvar useCapture = configure.useCapture || false;\n\tvar id = getID(target) + \".\" + getID(listener) + \".\" + (useCapture ? 1 : 0);\n\t// Handle the event.\n\tif (root.Gesture && root.Gesture._gestureHandlers[type]) { // Fire custom event.\n\t\tid = type + id;\n\t\tif (trigger === \"remove\") { // Remove event listener.\n\t\t\tif (!wrappers[id]) return; // Already removed.\n\t\t\twrappers[id].remove();\n\t\t\tdelete wrappers[id];\n\t\t} else if (trigger === \"add\") { // Attach event listener.\n\t\t\tif (wrappers[id]) {\n\t\t\t\twrappers[id].add();\n\t\t\t\treturn wrappers[id]; // Already attached.\n\t\t\t}\n\t\t\t// Retains \"this\" orientation.\n\t\t\tif (configure.useCall && !root.modifyEventListener) {\n\t\t\t\tvar tmp = listener;\n\t\t\t\tlistener = function(event, self) {\n\t\t\t\t\tfor (var key in self) event[key] = self[key];\n\t\t\t\t\treturn tmp.call(target, event);\n\t\t\t\t};\n\t\t\t}\n\t\t\t// Create listener proxy.\n\t\t\tconfigure.gesture = type;\n\t\t\tconfigure.target = target;\n\t\t\tconfigure.listener = listener;\n\t\t\tconfigure.fromOverwrite = fromOverwrite;\n\t\t\t// Record wrapper.\n\t\t\twrappers[id] = root.proxy[type](configure);\n\t\t}\n\t\treturn wrappers[id];\n\t} else { // Fire native event.\n\t\tvar eventList = getEventList(type);\n\t\tfor (var n = 0, eventId; n < eventList.length; n ++) {\n\t\t\ttype = eventList[n];\n\t\t\teventId = type + \".\" + id;\n\t\t\tif (trigger === \"remove\") { // Remove event listener.\n\t\t\t\tif (!wrappers[eventId]) continue; // Already removed.\n\t\t\t\ttarget[remove](type, listener, useCapture);\n\t\t\t\tdelete wrappers[eventId];\n\t\t\t} else if (trigger === \"add\") { // Attach event listener.\n\t\t\t\tif (wrappers[eventId]) return wrappers[eventId]; // Already attached.\n\t\t\t\ttarget[add](type, listener, useCapture);\n\t\t\t\t// Record wrapper.\n\t\t\t\twrappers[eventId] = {\n\t\t\t\t\tid: eventId,\n\t\t\t\t\ttype: type,\n\t\t\t\t\ttarget: target,\n\t\t\t\t\tlistener: listener,\n\t\t\t\t\tremove: function() {\n\t\t\t\t\t\tfor (var n = 0; n < eventList.length; n ++) {\n\t\t\t\t\t\t\troot.remove(target, eventList[n], listener, configure);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\treturn wrappers[eventId];\n\t}\n};\n\n/// Perform batch actions on multiple events.\nvar createBatchCommands = function(events) {\n\treturn {\n\t\tremove: function() { // Remove multiple events.\n\t\t\tfor (var key in events) {\n\t\t\t\tevents[key].remove();\n\t\t\t}\n\t\t},\n\t\tadd: function() { // Add multiple events.\n\t\t\tfor (var key in events) {\n\t\t\t\tevents[key].add();\n\t\t\t}\n\t\t}\n\t};\n};\n\n/// Display error message in console.\nvar createError = function(message, data) {\n\tif (typeof(console) === \"undefined\") return;\n\tif (typeof(console.error) === \"undefined\") return;\n\tconsole.error(message, data);\n};\n\n/// Handle naming discrepancies between platforms.\nvar pointerDefs = {\n\t\"msPointer\": [ \"MSPointerDown\", \"MSPointerMove\", \"MSPointerUp\" ],\n\t\"touch\": [ \"touchstart\", \"touchmove\", \"touchend\" ],\n\t\"mouse\": [ \"mousedown\", \"mousemove\", \"mouseup\" ]\n};\n\nvar pointerDetect = {\n\t// MSPointer\n\t\"MSPointerDown\": 0,\n\t\"MSPointerMove\": 1,\n\t\"MSPointerUp\": 2,\n\t// Touch\n\t\"touchstart\": 0,\n\t\"touchmove\": 1,\n\t\"touchend\": 2,\n\t// Mouse\n\t\"mousedown\": 0,\n\t\"mousemove\": 1,\n\t\"mouseup\": 2\n};\n\nvar getEventSupport = (function() {\n\troot.supports = {};\n\tif (window.navigator.msPointerEnabled) {\n\t\troot.supports.msPointer = true;\n\t}\n\tif (root.getEventSupport(\"touchstart\")) {\n\t\troot.supports.touch = true;\n\t}\n\tif (root.getEventSupport(\"mousedown\")) {\n\t\troot.supports.mouse = true;\n\t}\n})();\n\nvar getEventList = (function() {\n\treturn function(type) {\n\t\tvar prefix = document.addEventListener ? \"\" : \"on\"; // IE\n\t\tvar idx = pointerDetect[type];\n\t\tif (isFinite(idx)) {\n\t\t\tvar types = [];\n\t\t\tfor (var key in root.supports) {\n\t\t\t\ttypes.push(prefix + pointerDefs[key][idx]);\n\t\t\t}\n\t\t\treturn types;\n\t\t} else {\n\t\t\treturn [ prefix + type ];\n\t\t}\n\t};\n})();\n\n/// Event wrappers to keep track of all events placed in the window.\nvar wrappers = {};\nvar counter = 0;\nvar getID = function(object) {\n\tif (object === window) return \"#window\";\n\tif (object === document) return \"#document\";\n\tif (!object.uniqueID) object.uniqueID = \"e\" + counter ++;\n\treturn object.uniqueID;\n};\n\n/// Detect platforms native *EventListener command.\nvar add = document.addEventListener ? \"addEventListener\" : \"attachEvent\";\nvar remove = document.removeEventListener ? \"removeEventListener\" : \"detachEvent\";\n\n/*\n\tPointer.js\n\t----------------------------------------\n\tModified from; https://github.com/borismus/pointer.js\n*/\n\nroot.createPointerEvent = function (event, self, preventRecord) {\n\tvar eventName = self.gesture;\n\tvar target = self.target;\n\tvar pts = event.changedTouches || root.proxy.getCoords(event);\n\tif (pts.length) {\n\t\tvar pt = pts[0];\n\t\tself.pointers = preventRecord ? [] : pts;\n\t\tself.pageX = pt.pageX;\n\t\tself.pageY = pt.pageY;\n\t\tself.x = self.pageX;\n\t\tself.y = self.pageY;\n\t}\n\t///\n\tvar newEvent = document.createEvent(\"Event\");\n\tnewEvent.initEvent(eventName, true, true);\n\tnewEvent.originalEvent = event;\n\tfor (var k in self) {\n\t\tif (k === \"target\") continue;\n\t\tnewEvent[k] = self[k];\n\t}\n\t///\n\tvar type = newEvent.type;\n\tif (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events.\n//\t\ttarget.dispatchEvent(newEvent);\n\t\tself.oldListener.call(target, newEvent, self, false);\n\t}\n};\n\nvar eventListenersAgumented = false;\nvar augmentEventListeners = function() {\n\t/// Allows *EventListener to use custom event proxies.\n\tif (!window.HTMLElement) return;\n\tvar augmentEventListener = function(proto) {\n\t\tvar recall = function(trigger) { // overwrite native *EventListener's\n\t\t\tvar handle = trigger + \"EventListener\";\n\t\t\tvar handler = proto[handle];\n\t\t\tproto[handle] = function (type, listener, useCapture) {\n\t\t\t\tif (root.Gesture && root.Gesture._gestureHandlers[type]) { // capture custom events.\n\t\t\t\t\tvar configure = useCapture;\n\t\t\t\t\tif (typeof(useCapture) === \"object\") {\n\t\t\t\t\t\tconfigure.useCall = true;\n\t\t\t\t\t} else { // convert to configuration object.\n\t\t\t\t\t\tconfigure = {\n\t\t\t\t\t\t\tuseCall: true,\n\t\t\t\t\t\t\tuseCapture: useCapture\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\teventManager(this, type, listener, configure, trigger, true);\n//\t\t\t\t\thandler.call(this, type, listener, useCapture);\n\t\t\t\t} else { // use native function.\n\t\t\t\t\tvar types = getEventList(type);\n\t\t\t\t\tfor (var n = 0; n < types.length; n ++) {\n\t\t\t\t\t\thandler.call(this, types[n], listener, useCapture);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t};\n\t\trecall(\"add\");\n\t\trecall(\"remove\");\n\t};\n\t// NOTE: overwriting HTMLElement doesn't do anything in Firefox.\n\tif (navigator.userAgent.match(/Firefox/)) {\n\t\t// TODO: fix Firefox for the general case.\n\t\taugmentEventListener(HTMLDivElement.prototype);\n\t\taugmentEventListener(HTMLCanvasElement.prototype);\n\t} else {\n\t\taugmentEventListener(HTMLElement.prototype);\n\t}\n\taugmentEventListener(document);\n\taugmentEventListener(window);\n};\n\nvar selectorsAugmented = false;\nvar augmentSelectors = function() {\n/// Allows querySelectorAll and other NodeLists to perform *EventListener commands in bulk.\n\tvar proto = NodeList.prototype;\n\tproto.removeEventListener = function(type, listener, useCapture) {\n\t\tfor (var n = 0, length = this.length; n < length; n ++) {\n\t\t\tthis[n].removeEventListener(type, listener, useCapture);\n\t\t}\n\t};\n\tproto.addEventListener = function(type, listener, useCapture) {\n\t\tfor (var n = 0, length = this.length; n < length; n ++) {\n\t\t\tthis[n].addEventListener(type, listener, useCapture);\n\t\t}\n\t};\n};\n\nreturn root;\n\n})(eventjs);\n\n/*:\n\t----------------------------------------------------\n\teventjs.proxy : 0.4.2 : 2013/07/17 : MIT License\n\t----------------------------------------------------\n\thttps://github.com/mudcube/eventjs.js\n\t----------------------------------------------------\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\n/*\n\tCreate a new pointer gesture instance.\n*/\n\nroot.pointerSetup = function(conf, self) {\n\t/// Configure.\n\tconf.target = conf.target || window;\n\tconf.doc = conf.target.ownerDocument || conf.target; // Associated document.\n\tconf.minFingers = conf.minFingers || conf.fingers || 1; // Minimum required fingers.\n\tconf.maxFingers = conf.maxFingers || conf.fingers || Infinity; // Maximum allowed fingers.\n\tconf.position = conf.position || \"relative\"; // Determines what coordinate system points are returned.\n\tdelete conf.fingers; //-\n\t/// Convenience data.\n\tself = self || {};\n\tself.enabled = true;\n\tself.gesture = conf.gesture;\n\tself.target = conf.target;\n\tself.env = conf.env;\n\t///\n\tif (eventjs.modifyEventListener && conf.fromOverwrite) {\n\t\tconf.oldListener = conf.listener;\n\t\tconf.listener = eventjs.createPointerEvent;\n\t}\n\t/// Convenience commands.\n\tvar fingers = 0;\n\tvar type = self.gesture.indexOf(\"pointer\") === 0 && eventjs.modifyEventListener ? \"pointer\" : \"mouse\";\n\tif (conf.oldListener) self.oldListener = conf.oldListener;\n\t///\n\tself.listener = conf.listener;\n\tself.proxy = function(listener) {\n\t\tself.defaultListener = conf.listener;\n\t\tconf.listener = listener;\n\t\tlistener(conf.event, self);\n\t};\n\tself.add = function() {\n\t\tif (self.enabled === true) return;\n\t\tif (conf.onPointerDown) eventjs.add(conf.target, type + \"down\", conf.onPointerDown);\n\t\tif (conf.onPointerMove) eventjs.add(conf.doc, type + \"move\", conf.onPointerMove);\n\t\tif (conf.onPointerUp) eventjs.add(conf.doc, type + \"up\", conf.onPointerUp);\n\t\tself.enabled = true;\n\t};\n\tself.remove = function() {\n\t\tif (self.enabled === false) return;\n\t\tif (conf.onPointerDown) eventjs.remove(conf.target, type + \"down\", conf.onPointerDown);\n\t\tif (conf.onPointerMove) eventjs.remove(conf.doc, type + \"move\", conf.onPointerMove);\n\t\tif (conf.onPointerUp) eventjs.remove(conf.doc, type + \"up\", conf.onPointerUp);\n\t\tself.reset();\n\t\tself.enabled = false;\n\t};\n\tself.pause = function(opt) {\n\t\tif (conf.onPointerMove && (!opt || opt.move)) eventjs.remove(conf.doc, type + \"move\", conf.onPointerMove);\n\t\tif (conf.onPointerUp && (!opt || opt.up)) eventjs.remove(conf.doc, type + \"up\", conf.onPointerUp);\n\t\tfingers = conf.fingers;\n\t\tconf.fingers = 0;\n\t};\n\tself.resume = function(opt) {\n\t\tif (conf.onPointerMove && (!opt || opt.move)) eventjs.add(conf.doc, type + \"move\", conf.onPointerMove);\n\t\tif (conf.onPointerUp && (!opt || opt.up)) eventjs.add(conf.doc, type + \"up\", conf.onPointerUp);\n\t\tconf.fingers = fingers;\n\t};\n\tself.reset = function() {\n\t\tconf.tracker = {};\n\t\tconf.fingers = 0;\n\t};\n\t///\n\treturn self;\n};\n\n/*\n\tBegin proxied pointer command.\n*/\n\nvar sp = eventjs.supports; // Default pointerType\n///\neventjs.isMouse = !!sp.mouse;\neventjs.isMSPointer = !!sp.touch;\neventjs.isTouch = !!sp.msPointer;\n///\nroot.pointerStart = function(event, self, conf) {\n\t/// tracks multiple inputs\n\tvar type = (event.type || \"mousedown\").toUpperCase();\n\tif (type.indexOf(\"MOUSE\") === 0) {\n\t\teventjs.isMouse = true;\n\t\teventjs.isTouch = false;\n\t\teventjs.isMSPointer = false;\n\t} else if (type.indexOf(\"TOUCH\") === 0) {\n\t\teventjs.isMouse = false;\n\t\teventjs.isTouch = true;\n\t\teventjs.isMSPointer = false;\n\t} else if (type.indexOf(\"MSPOINTER\") === 0) {\n\t\teventjs.isMouse = false;\n\t\teventjs.isTouch = false;\n\t\teventjs.isMSPointer = true;\n\t}\n\t///\n\tvar addTouchStart = function(touch, sid) {\n\t\tvar bbox = conf.bbox;\n\t\tvar pt = track[sid] = {};\n\t\t///\n\t\tswitch(conf.position) {\n\t\t\tcase \"absolute\": // Absolute from within window.\n\t\t\t\tpt.offsetX = 0;\n\t\t\t\tpt.offsetY = 0;\n\t\t\t\tbreak;\n\t\t\tcase \"differenceFromLast\": // Since last coordinate recorded.\n\t\t\t\tpt.offsetX = touch.pageX;\n\t\t\t\tpt.offsetY = touch.pageY;\n\t\t\t\tbreak;\n\t\t\tcase \"difference\": // Relative from origin.\n\t\t\t\tpt.offsetX = touch.pageX;\n\t\t\t\tpt.offsetY = touch.pageY;\n\t\t\t\tbreak;\n\t\t\tcase \"move\": // Move target element.\n\t\t\t\tpt.offsetX = touch.pageX - bbox.x1;\n\t\t\t\tpt.offsetY = touch.pageY - bbox.y1;\n\t\t\t\tbreak;\n\t\t\tdefault: // Relative from within target.\n\t\t\t\tpt.offsetX = bbox.x1 - bbox.scrollLeft;\n\t\t\t\tpt.offsetY = bbox.y1 - bbox.scrollTop;\n\t\t\t\tbreak;\n\t\t}\n\t\t///\n\t\tvar x = touch.pageX - pt.offsetX;\n\t\tvar y = touch.pageY - pt.offsetY;\n\t\t///\n\t\tpt.rotation = 0;\n\t\tpt.scale = 1;\n\t\tpt.startTime = pt.moveTime = (new Date()).getTime();\n\t\tpt.move = { x: x, y: y };\n\t\tpt.start = { x: x, y: y };\n\t\t///\n\t\tconf.fingers ++;\n\t};\n\t///\n\tconf.event = event;\n\tif (self.defaultListener) {\n\t\tconf.listener = self.defaultListener;\n\t\tdelete self.defaultListener;\n\t}\n\t///\n\tvar isTouchStart = !conf.fingers;\n\tvar track = conf.tracker;\n\tvar touches = event.changedTouches || root.getCoords(event);\n\tvar length = touches.length;\n\t// Adding touch events to tracking.\n\tfor (var i = 0; i < length; i ++) {\n\t\tvar touch = touches[i];\n\t\tvar sid = touch.identifier || Infinity; // Touch ID.\n\t\t// Track the current state of the touches.\n\t\tif (conf.fingers) {\n\t\t\tif (conf.fingers >= conf.maxFingers) {\n\t\t\t\tvar ids = [];\n\t\t\t\tfor (var sid in conf.tracker) ids.push(sid);\n\t\t\t\tself.identifier = ids.join(\",\");\n\t\t\t\treturn isTouchStart;\n\t\t\t}\n\t\t\tvar fingers = 0; // Finger ID.\n\t\t\tfor (var rid in track) {\n\t\t\t\t// Replace removed finger.\n\t\t\t\tif (track[rid].up) {\n\t\t\t\t\tdelete track[rid];\n\t\t\t\t\taddTouchStart(touch, sid);\n\t\t\t\t\tconf.cancel = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tfingers ++;\n\t\t\t}\n\t\t\t// Add additional finger.\n\t\t\tif (track[sid]) continue;\n\t\t\taddTouchStart(touch, sid);\n\t\t} else { // Start tracking fingers.\n\t\t\ttrack = conf.tracker = {};\n\t\t\tself.bbox = conf.bbox = root.getBoundingBox(conf.target);\n\t\t\tconf.fingers = 0;\n\t\t\tconf.cancel = false;\n\t\t\taddTouchStart(touch, sid);\n\t\t}\n\t}\n\t///\n\tvar ids = [];\n\tfor (var sid in conf.tracker) ids.push(sid);\n\tself.identifier = ids.join(\",\");\n\t///\n\treturn isTouchStart;\n};\n\n/*\n\tEnd proxied pointer command.\n*/\n\nroot.pointerEnd = function(event, self, conf, onPointerUp) {\n\t// Record changed touches have ended (iOS changedTouches is not reliable).\n\tvar touches = event.touches || [];\n\tvar length = touches.length;\n\tvar exists = {};\n\tfor (var i = 0; i < length; i ++) {\n\t\tvar touch = touches[i];\n\t\tvar sid = touch.identifier;\n\t\texists[sid || Infinity] = true;\n\t}\n\tfor (var sid in conf.tracker) {\n\t\tvar track = conf.tracker[sid];\n\t\tif (exists[sid] || track.up) continue;\n\t\tif (onPointerUp) { // add changedTouches to mouse.\n\t\t\tonPointerUp({\n\t\t\t\tpageX: track.pageX,\n\t\t\t\tpageY: track.pageY,\n\t\t\t\tchangedTouches: [{\n\t\t\t\t\tpageX: track.pageX,\n\t\t\t\t\tpageY: track.pageY,\n\t\t\t\t\tidentifier: sid === \"Infinity\" ? Infinity : sid\n\t\t\t\t}]\n\t\t\t}, \"up\");\n\t\t}\n\t\ttrack.up = true;\n\t\tconf.fingers --;\n\t}\n/*\t// This should work but fails in Safari on iOS4 so not using it.\n\tvar touches = event.changedTouches || root.getCoords(event);\n\tvar length = touches.length;\n\t// Record changed touches have ended (this should work).\n\tfor (var i = 0; i < length; i ++) {\n\t\tvar touch = touches[i];\n\t\tvar sid = touch.identifier || Infinity;\n\t\tvar track = conf.tracker[sid];\n\t\tif (track && !track.up) {\n\t\t\tif (onPointerUp) { // add changedTouches to mouse.\n\t\t\t\tonPointerUp({\n\t\t\t\t\tchangedTouches: [{\n\t\t\t\t\t\tpageX: track.pageX,\n\t\t\t\t\t\tpageY: track.pageY,\n\t\t\t\t\t\tidentifier: sid === \"Infinity\" ? Infinity : sid\n\t\t\t\t\t}]\n\t\t\t\t}, \"up\");\n\t\t\t}\n\t\t\ttrack.up = true;\n\t\t\tconf.fingers --;\n\t\t}\n\t} */\n\t// Wait for all fingers to be released.\n\tif (conf.fingers !== 0) return false;\n\t// Record total number of fingers gesture used.\n\tvar ids = [];\n\tconf.gestureFingers = 0;\n\tfor (var sid in conf.tracker) {\n\t\tconf.gestureFingers ++;\n\t\tids.push(sid);\n\t}\n\tself.identifier = ids.join(\",\");\n\t// Our pointer gesture has ended.\n\treturn true;\n};\n\n/*\n\tReturns mouse coords in an array to match event.*Touches\n\t------------------------------------------------------------\n\tvar touch = event.changedTouches || root.getCoords(event);\n*/\n\nroot.getCoords = function(event) {\n\tif (typeof(event.pageX) !== \"undefined\") { // Desktop browsers.\n\t\troot.getCoords = function(event) {\n\t\t\treturn Array({\n\t\t\t\ttype: \"mouse\",\n\t\t\t\tx: event.pageX,\n\t\t\t\ty: event.pageY,\n\t\t\t\tpageX: event.pageX,\n\t\t\t\tpageY: event.pageY,\n\t\t\t\tidentifier: event.pointerId || Infinity // pointerId is MS\n\t\t\t});\n\t\t};\n\t} else { // Internet Explorer <= 8.0\n\t\troot.getCoords = function(event) {\n\t\t\tvar doc = document.documentElement;\n\t\t\tevent = event || window.event;\n\t\t\treturn Array({\n\t\t\t\ttype: \"mouse\",\n\t\t\t\tx: event.clientX + doc.scrollLeft,\n\t\t\t\ty: event.clientY + doc.scrollTop,\n\t\t\t\tpageX: event.clientX + doc.scrollLeft,\n\t\t\t\tpageY: event.clientY + doc.scrollTop,\n\t\t\t\tidentifier: Infinity\n\t\t\t});\n\t\t};\n\t}\n\treturn root.getCoords(event);\n};\n\n/*\n\tReturns single coords in an object.\n\t------------------------------------------------------------\n\tvar mouse = root.getCoord(event);\n*/\n\nroot.getCoord = function(event) {\n\tif (\"ontouchstart\" in window) { // Mobile browsers.\n\t\tvar pX = 0;\n\t\tvar pY = 0;\n\t\troot.getCoord = function(event) {\n\t\t\tvar touches = event.changedTouches;\n\t\t\tif (touches && touches.length) { // ontouchstart + ontouchmove\n\t\t\t\treturn {\n\t\t\t\t\tx: pX = touches[0].pageX,\n\t\t\t\t\ty: pY = touches[0].pageY\n\t\t\t\t};\n\t\t\t} else { // ontouchend\n\t\t\t\treturn {\n\t\t\t\t\tx: pX,\n\t\t\t\t\ty: pY\n\t\t\t\t};\n\t\t\t}\n\t\t};\n\t} else if(typeof(event.pageX) !== \"undefined\" && typeof(event.pageY) !== \"undefined\") { // Desktop browsers.\n\t\troot.getCoord = function(event) {\n\t\t\treturn {\n\t\t\t\tx: event.pageX,\n\t\t\t\ty: event.pageY\n\t\t\t};\n\t\t};\n\t} else { // Internet Explorer <=8.0\n\t\troot.getCoord = function(event) {\n\t\t\tvar doc = document.documentElement;\n\t\t\tevent = event || window.event;\n\t\t\treturn {\n\t\t\t\tx: event.clientX + doc.scrollLeft,\n\t\t\t\ty: event.clientY + doc.scrollTop\n\t\t\t};\n\t\t};\n\t}\n\treturn root.getCoord(event);\n};\n\n/*\n\tGet target scale and position in space.\n*/\n\nvar getPropertyAsFloat = function(o, type) {\n\tvar n = parseFloat(o.getPropertyValue(type), 10);\n\treturn isFinite(n) ? n : 0;\n};\n\nroot.getBoundingBox = function(o) {\n\tif (o === window || o === document) o = document.body;\n\t///\n\tvar bbox = {};\n\tvar bcr = o.getBoundingClientRect();\n\tbbox.width = bcr.width;\n\tbbox.height = bcr.height;\n\tbbox.x1 = bcr.left;\n\tbbox.y1 = bcr.top;\n\tbbox.scaleX = bcr.width / o.offsetWidth || 1;\n\tbbox.scaleY = bcr.height / o.offsetHeight || 1;\n\tbbox.scrollLeft = 0;\n\tbbox.scrollTop = 0;\n\t///\n\tvar style = window.getComputedStyle(o);\n\tvar borderBox = style.getPropertyValue(\"box-sizing\") === \"border-box\";\n\t///\n\tif (borderBox === false) {\n\t\tvar left = getPropertyAsFloat(style, \"border-left-width\");\n\t\tvar right = getPropertyAsFloat(style, \"border-right-width\");\n\t\tvar bottom = getPropertyAsFloat(style, \"border-bottom-width\");\n\t\tvar top = getPropertyAsFloat(style, \"border-top-width\");\n\t\tbbox.border = [ left, right, top, bottom ];\n\t\tbbox.x1 += left;\n\t\tbbox.y1 += top;\n\t\tbbox.width -= right + left;\n\t\tbbox.height -= bottom + top;\n\t}\n\n/*\tvar left = getPropertyAsFloat(style, \"padding-left\");\n\tvar right = getPropertyAsFloat(style, \"padding-right\");\n\tvar bottom = getPropertyAsFloat(style, \"padding-bottom\");\n\tvar top = getPropertyAsFloat(style, \"padding-top\");\n\tbbox.padding = [ left, right, top, bottom ];*/\n\t///\n\tbbox.x2 = bbox.x1 + bbox.width;\n\tbbox.y2 = bbox.y1 + bbox.height;\n\n\t/// Get the scroll of container element.\n\tvar position = style.getPropertyValue(\"position\");\n\tvar tmp = position === \"fixed\" ? o : o.parentNode;\n\twhile (tmp !== null) {\n\t\tif (tmp === document.body) break;\n\t\tif (tmp.scrollTop === undefined) break;\n\t\tvar style = window.getComputedStyle(tmp);\n\t\tvar position = style.getPropertyValue(\"position\");\n\t\tif (position === \"absolute\") {\n\n\t\t} else if (position === \"fixed\") {\n//\t\t\tbbox.scrollTop += document.body.scrollTop;\n//\t\t\tbbox.scrollLeft += document.body.scrollLeft;\n\t\t\tbbox.scrollTop -= tmp.parentNode.scrollTop;\n\t\t\tbbox.scrollLeft -= tmp.parentNode.scrollLeft;\n\t\t\tbreak;\n\t\t} else {\n\t\t\tbbox.scrollLeft += tmp.scrollLeft;\n\t\t\tbbox.scrollTop += tmp.scrollTop;\n\t\t}\n\t\t///\n\t\ttmp = tmp.parentNode;\n\t};\n\t///\n\tbbox.scrollBodyLeft = (window.pageXOffset !== undefined) ? window.pageXOffset : (document.documentElement || document.body.parentNode || document.body).scrollLeft;\n\tbbox.scrollBodyTop = (window.pageYOffset !== undefined) ? window.pageYOffset : (document.documentElement || document.body.parentNode || document.body).scrollTop;\n\t///\n\tbbox.scrollLeft -= bbox.scrollBodyLeft;\n\tbbox.scrollTop -= bbox.scrollBodyTop;\n\t///\n\treturn bbox;\n};\n\n/*\n\tKeep track of metaKey, the proper ctrlKey for users platform.\n\t----------------------------------------------------\n\thttp://www.quirksmode.org/js/keys.html\n\t-----------------------------------\n\thttp://unixpapa.com/js/key.html\n*/\n\n(function() {\n\tvar agent = navigator.userAgent.toLowerCase();\n\tvar mac = agent.indexOf(\"macintosh\") !== -1;\n\tvar metaKeys;\n\tif (mac && agent.indexOf(\"khtml\") !== -1) { // chrome, safari.\n\t\tmetaKeys = { 91: true, 93: true };\n\t} else if (mac && agent.indexOf(\"firefox\") !== -1) { // mac firefox.\n\t\tmetaKeys = { 224: true };\n\t} else { // windows, linux, or mac opera.\n\t\tmetaKeys = { 17: true };\n\t}\n\t(root.metaTrackerReset = function() {\n\t\teventjs.fnKey = root.fnKey = false;\n\t\teventjs.metaKey = root.metaKey = false;\n\t\teventjs.escKey = root.escKey = false;\n\t\teventjs.ctrlKey = root.ctrlKey = false;\n\t\teventjs.shiftKey = root.shiftKey = false;\n\t\teventjs.altKey = root.altKey = false;\n\t})();\n\troot.metaTracker = function(event) {\n\t\tvar isKeyDown = event.type === \"keydown\";\n\t\tif (event.keyCode === 27) eventjs.escKey = root.escKey = isKeyDown;\n\t\tif (metaKeys[event.keyCode]) eventjs.metaKey = root.metaKey = isKeyDown;\n\t\teventjs.ctrlKey = root.ctrlKey = event.ctrlKey;\n\t\teventjs.shiftKey = root.shiftKey = event.shiftKey;\n\t\teventjs.altKey = root.altKey = event.altKey;\n\t};\n})();\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t----------------------------------------------------\n\t\"MutationObserver\" event proxy.\n\t----------------------------------------------------\n\tauthor: Selvakumar Arumugam - MIT LICENSE\n\t src: http://stackoverflow.com/questions/10868104/can-you-have-a-javascript-hook-trigger-after-a-dom-elements-style-object-change\n\t----------------------------------------------------\n*/\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\n\neventjs.MutationObserver = (function() {\n\tvar MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;\n\tvar DOMAttrModifiedSupported = !MutationObserver && (function() {\n\t\tvar p = document.createElement(\"p\");\n\t\tvar flag = false;\n\t\tvar fn = function() { flag = true };\n\t\tif (p.addEventListener) {\n\t\t\tp.addEventListener(\"DOMAttrModified\", fn, false);\n\t\t} else if (p.attachEvent) {\n\t\t\tp.attachEvent(\"onDOMAttrModified\", fn);\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t\t///\n\t\tp.setAttribute(\"id\", \"target\");\n\t\t///\n\t\treturn flag;\n\t})();\n\t///\n\treturn function(container, callback) {\n\t\tif (MutationObserver) {\n\t\t\tvar options = {\n\t\t\t\tsubtree: false,\n\t\t\t\tattributes: true\n\t\t\t};\n\t\t\tvar observer = new MutationObserver(function(mutations) {\n\t\t\t\tmutations.forEach(function(e) {\n\t\t\t\t\tcallback.call(e.target, e.attributeName);\n\t\t\t\t});\n\t\t\t});\n\t\t\tobserver.observe(container, options)\n\t\t} else if (DOMAttrModifiedSupported) {\n\t\t\teventjs.add(container, \"DOMAttrModified\", function(e) {\n\t\t\t\tcallback.call(container, e.attrName);\n\t\t\t});\n\t\t} else if (\"onpropertychange\" in document.body) {\n\t\t\teventjs.add(container, \"propertychange\", function(e) {\n\t\t\t\tcallback.call(container, window.event.propertyName);\n\t\t\t});\n\t\t}\n\t}\n})();\n/*:\n\t\"Click\" event proxy.\n\t----------------------------------------------------\n\teventjs.add(window, \"click\", function(event, self) {});\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nroot.click = function(conf) {\n\tconf.gesture = conf.gesture || \"click\";\n\tconf.maxFingers = conf.maxFingers || conf.fingers || 1;\n\t/// Tracking the events.\n\tconf.onPointerDown = function (event) {\n\t\tif (root.pointerStart(event, self, conf)) {\n\t\t\teventjs.add(conf.target, \"mouseup\", conf.onPointerUp);\n\t\t}\n\t};\n\tconf.onPointerUp = function(event) {\n\t\tif (root.pointerEnd(event, self, conf)) {\n\t\t\teventjs.remove(conf.target, \"mouseup\", conf.onPointerUp);\n\t\t\tvar pointers = event.changedTouches || root.getCoords(event);\n\t\t\tvar pointer = pointers[0];\n\t\t\tvar bbox = conf.bbox;\n\t\t\tvar newbbox = root.getBoundingBox(conf.target);\n\t\t\tvar y = pointer.pageY - newbbox.scrollBodyTop;\n\t\t\tvar x = pointer.pageX - newbbox.scrollBodyLeft;\n\t\t\t////\n\t\t\tif (x > bbox.x1 && y > bbox.y1 &&\n\t\t\t\tx < bbox.x2 && y < bbox.y2 &&\n\t\t\t\tbbox.scrollTop === newbbox.scrollTop) { // has not been scrolled\n\t\t\t\t///\n\t\t\t\tfor (var key in conf.tracker) break; //- should be modularized? in dblclick too\n\t\t\t\tvar point = conf.tracker[key];\n\t\t\t\tself.x = point.start.x;\n\t\t\t\tself.y = point.start.y;\n\t\t\t\t///\n\t\t\t\tconf.listener(event, self);\n\t\t\t}\n\t\t}\n\t};\n\t// Generate maintenance commands, and other configurations.\n\tvar self = root.pointerSetup(conf);\n\tself.state = \"click\";\n\t// Attach events.\n\teventjs.add(conf.target, \"mousedown\", conf.onPointerDown);\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.click = root.click;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Double-Click\" aka \"Double-Tap\" event proxy.\n\t----------------------------------------------------\n\teventjs.add(window, \"dblclick\", function(event, self) {});\n\t----------------------------------------------------\n\tTouch an target twice for <= 700ms, with less than 25 pixel drift.\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nroot.dbltap =\nroot.dblclick = function(conf) {\n\tconf.gesture = conf.gesture || \"dbltap\";\n\tconf.maxFingers = conf.maxFingers || conf.fingers || 1;\n\t// Setting up local variables.\n\tvar delay = 700; // in milliseconds\n\tvar time0, time1, timeout;\n\tvar pointer0, pointer1;\n\t// Tracking the events.\n\tconf.onPointerDown = function (event) {\n\t\tvar pointers = event.changedTouches || root.getCoords(event);\n\t\tif (time0 && !time1) { // Click #2\n\t\t\tpointer1 = pointers[0];\n\t\t\ttime1 = (new Date()).getTime() - time0;\n\t\t} else { // Click #1\n\t\t\tpointer0 = pointers[0];\n\t\t\ttime0 = (new Date()).getTime();\n\t\t\ttime1 = 0;\n\t\t\tclearTimeout(timeout);\n\t\t\ttimeout = setTimeout(function() {\n\t\t\t\ttime0 = 0;\n\t\t\t}, delay);\n\t\t}\n\t\tif (root.pointerStart(event, self, conf)) {\n\t\t\teventjs.add(conf.target, \"mousemove\", conf.onPointerMove).listener(event);\n\t\t\teventjs.add(conf.target, \"mouseup\", conf.onPointerUp);\n\t\t}\n\t};\n\tconf.onPointerMove = function (event) {\n\t\tif (time0 && !time1) {\n\t\t\tvar pointers = event.changedTouches || root.getCoords(event);\n\t\t\tpointer1 = pointers[0];\n\t\t}\n\t\tvar bbox = conf.bbox;\n\t\tvar ax = (pointer1.pageX - bbox.x1);\n\t\tvar ay = (pointer1.pageY - bbox.y1);\n\t\tif (!(ax > 0 && ax < bbox.width && // Within target coordinates..\n\t\t\t ay > 0 && ay < bbox.height &&\n\t\t\t Math.abs(pointer1.pageX - pointer0.pageX) <= 25 && // Within drift deviance.\n\t\t\t Math.abs(pointer1.pageY - pointer0.pageY) <= 25)) {\n\t\t\t// Cancel out this listener.\n\t\t\teventjs.remove(conf.target, \"mousemove\", conf.onPointerMove);\n\t\t\tclearTimeout(timeout);\n\t\t\ttime0 = time1 = 0;\n\t\t}\n\t};\n\tconf.onPointerUp = function(event) {\n\t\tif (root.pointerEnd(event, self, conf)) {\n\t\t\teventjs.remove(conf.target, \"mousemove\", conf.onPointerMove);\n\t\t\teventjs.remove(conf.target, \"mouseup\", conf.onPointerUp);\n\t\t}\n\t\tif (time0 && time1) {\n\t\t\tif (time1 <= delay) { // && !(event.cancelBubble && ++event.cancelBubbleCount > 1)) {\n\t\t\t\tself.state = conf.gesture;\n\t\t\t\tfor (var key in conf.tracker) break;\n\t\t\t\tvar point = conf.tracker[key];\n\t\t\t\tself.x = point.start.x;\n\t\t\t\tself.y = point.start.y;\n\t\t\t\tconf.listener(event, self);\n\t\t\t}\n\t\t\tclearTimeout(timeout);\n\t\t\ttime0 = time1 = 0;\n\t\t}\n\t};\n\t// Generate maintenance commands, and other configurations.\n\tvar self = root.pointerSetup(conf);\n\tself.state = \"dblclick\";\n\t// Attach events.\n\teventjs.add(conf.target, \"mousedown\", conf.onPointerDown);\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.dbltap = root.dbltap;\neventjs.Gesture._gestureHandlers.dblclick = root.dblclick;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Drag\" event proxy (1+ fingers).\n\t----------------------------------------------------\n\tCONFIGURE: maxFingers, position.\n\t----------------------------------------------------\n\teventjs.add(window, \"drag\", function(event, self) {\n\t\tconsole.log(self.gesture, self.state, self.start, self.x, self.y, self.bbox);\n\t});\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nroot.dragElement = function(that, event) {\n\troot.drag({\n\t\tevent: event,\n\t\ttarget: that,\n\t\tposition: \"move\",\n\t\tlistener: function(event, self) {\n\t\t\tthat.style.left = self.x + \"px\";\n\t\t\tthat.style.top = self.y + \"px\";\n\t\t\teventjs.prevent(event);\n\t\t}\n\t});\n};\n\nroot.drag = function(conf) {\n\tconf.gesture = \"drag\";\n\tconf.onPointerDown = function (event) {\n\t\tif (root.pointerStart(event, self, conf)) {\n\t\t\tif (!conf.monitor) {\n\t\t\t\teventjs.add(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\t\teventjs.add(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t\t}\n\t\t}\n\t\t// Process event listener.\n\t\tconf.onPointerMove(event, \"down\");\n\t};\n\tconf.onPointerMove = function (event, state) {\n\t\tif (!conf.tracker) return conf.onPointerDown(event);\n\t\tvar bbox = conf.bbox;\n\t\tvar touches = event.changedTouches || root.getCoords(event);\n\t\tvar length = touches.length;\n\t\tfor (var i = 0; i < length; i ++) {\n\t\t\tvar touch = touches[i];\n\t\t\tvar identifier = touch.identifier || Infinity;\n\t\t\tvar pt = conf.tracker[identifier];\n\t\t\t// Identifier defined outside of listener.\n\t\t\tif (!pt) continue;\n\t\t\tpt.pageX = touch.pageX;\n\t\t\tpt.pageY = touch.pageY;\n\t\t\t// Record data.\n\t\t\tself.state = state || \"move\";\n\t\t\tself.identifier = identifier;\n\t\t\tself.start = pt.start;\n\t\t\tself.fingers = conf.fingers;\n\t\t\tif (conf.position === \"differenceFromLast\") {\n\t\t\t\tself.x = (pt.pageX - pt.offsetX);\n\t\t\t\tself.y = (pt.pageY - pt.offsetY);\n\t\t\t\tpt.offsetX = pt.pageX;\n\t\t\t\tpt.offsetY = pt.pageY;\n\t\t\t} else {\n\t\t\t\tself.x = (pt.pageX - pt.offsetX);\n\t\t\t\tself.y = (pt.pageY - pt.offsetY);\n\t\t\t}\n\t\t\t///\n\t\t\tconf.listener(event, self);\n\t\t}\n\t};\n\tconf.onPointerUp = function(event) {\n\t\t// Remove tracking for touch.\n\t\tif (root.pointerEnd(event, self, conf, conf.onPointerMove)) {\n\t\t\tif (!conf.monitor) {\n\t\t\t\teventjs.remove(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\t\teventjs.remove(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t\t}\n\t\t}\n\t};\n\t// Generate maintenance commands, and other configurations.\n\tvar self = root.pointerSetup(conf);\n\t// Attach events.\n\tif (conf.event) {\n\t\tconf.onPointerDown(conf.event);\n\t} else { //\n\t\teventjs.add(conf.target, \"mousedown\", conf.onPointerDown);\n\t\tif (conf.monitor) {\n\t\t\teventjs.add(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\teventjs.add(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t}\n\t}\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.drag = root.drag;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Gesture\" event proxy (2+ fingers).\n\t----------------------------------------------------\n\tCONFIGURE: minFingers, maxFingers.\n\t----------------------------------------------------\n\teventjs.add(window, \"gesture\", function(event, self) {\n\t\tconsole.log(\n\t\t\tself.x, // centroid\n\t\t\tself.y,\n\t\t\tself.rotation,\n\t\t\tself.scale,\n\t\t\tself.fingers,\n\t\t\tself.state\n\t\t);\n\t});\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nvar RAD_DEG = Math.PI / 180;\nvar getCentroid = function(self, points) {\n\tvar centroidx = 0;\n\tvar centroidy = 0;\n\tvar length = 0;\n\tfor (var sid in points) {\n\t\tvar touch = points[sid];\n\t\tif (touch.up) continue;\n\t\tcentroidx += touch.move.x;\n\t\tcentroidy += touch.move.y;\n\t\tlength ++;\n\t}\n\tself.x = centroidx /= length;\n\tself.y = centroidy /= length;\n\treturn self;\n};\n\nroot.gesture = function(conf) {\n\tconf.gesture = conf.gesture || \"gesture\";\n\tconf.minFingers = conf.minFingers || conf.fingers || 2;\n\t// Tracking the events.\n\tconf.onPointerDown = function (event) {\n\t\tvar fingers = conf.fingers;\n\t\tif (root.pointerStart(event, self, conf)) {\n\t\t\teventjs.add(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\teventjs.add(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t}\n\t\t// Record gesture start.\n\t\tif (conf.fingers === conf.minFingers && fingers !== conf.fingers) {\n\t\t\tself.fingers = conf.minFingers;\n\t\t\tself.scale = 1;\n\t\t\tself.rotation = 0;\n\t\t\tself.state = \"start\";\n\t\t\tvar sids = \"\"; //- FIXME(mud): can generate duplicate IDs.\n\t\t\tfor (var key in conf.tracker) sids += key;\n\t\t\tself.identifier = parseInt(sids);\n\t\t\tgetCentroid(self, conf.tracker);\n\t\t\tconf.listener(event, self);\n\t\t}\n\t};\n\t///\n\tconf.onPointerMove = function (event, state) {\n\t\tvar bbox = conf.bbox;\n\t\tvar points = conf.tracker;\n\t\tvar touches = event.changedTouches || root.getCoords(event);\n\t\tvar length = touches.length;\n\t\t// Update tracker coordinates.\n\t\tfor (var i = 0; i < length; i ++) {\n\t\t\tvar touch = touches[i];\n\t\t\tvar sid = touch.identifier || Infinity;\n\t\t\tvar pt = points[sid];\n\t\t\t// Check whether \"pt\" is used by another gesture.\n\t\t\tif (!pt) continue;\n\t\t\t// Find the actual coordinates.\n\t\t\tpt.move.x = (touch.pageX - bbox.x1);\n\t\t\tpt.move.y = (touch.pageY - bbox.y1);\n\t\t}\n\t\t///\n\t\tif (conf.fingers < conf.minFingers) return;\n\t\t///\n\t\tvar touches = [];\n\t\tvar scale = 0;\n\t\tvar rotation = 0;\n\n\t\t/// Calculate centroid of gesture.\n\t\tgetCentroid(self, points);\n\t\t///\n\t\tfor (var sid in points) {\n\t\t\tvar touch = points[sid];\n\t\t\tif (touch.up) continue;\n\t\t\tvar start = touch.start;\n\t\t\tif (!start.distance) {\n\t\t\t\tvar dx = start.x - self.x;\n\t\t\t\tvar dy = start.y - self.y;\n\t\t\t\tstart.distance = Math.sqrt(dx * dx + dy * dy);\n\t\t\t\tstart.angle = Math.atan2(dx, dy) / RAD_DEG;\n\t\t\t}\n\t\t\t// Calculate scale.\n\t\t\tvar dx = touch.move.x - self.x;\n\t\t\tvar dy = touch.move.y - self.y;\n\t\t\tvar distance = Math.sqrt(dx * dx + dy * dy);\n\t\t\t// If touch start.distance from centroid is 0, scale should not be updated.\n\t\t\t// This prevents dividing by 0 in cases where start.distance is oddly 0.\n\t\t\tif (start.distance !== 0) {\n\t\t\t scale += distance / start.distance;\n\t\t\t}\n\t\t\t// Calculate rotation.\n\t\t\tvar angle = Math.atan2(dx, dy) / RAD_DEG;\n\t\t\tvar rotate = (start.angle - angle + 360) % 360 - 180;\n\t\t\ttouch.DEG2 = touch.DEG1; // Previous degree.\n\t\t\ttouch.DEG1 = rotate > 0 ? rotate : -rotate; // Current degree.\n\t\t\tif (typeof(touch.DEG2) !== \"undefined\") {\n\t\t\t\tif (rotate > 0) {\n\t\t\t\t\ttouch.rotation += touch.DEG1 - touch.DEG2;\n\t\t\t\t} else {\n\t\t\t\t\ttouch.rotation -= touch.DEG1 - touch.DEG2;\n\t\t\t\t}\n\t\t\t\trotation += touch.rotation;\n\t\t\t}\n\t\t\t// Attach current points to self.\n\t\t\ttouches.push(touch.move);\n\t\t}\n\t\t///\n\t\tself.touches = touches;\n\t\tself.fingers = conf.fingers;\n\t\tself.scale = scale / conf.fingers;\n\t\tself.rotation = rotation / conf.fingers;\n\t\tself.state = \"change\";\n\t\tconf.listener(event, self);\n\t};\n\tconf.onPointerUp = function(event) {\n\t\t// Remove tracking for touch.\n\t\tvar fingers = conf.fingers;\n\t\tif (root.pointerEnd(event, self, conf)) {\n\t\t\teventjs.remove(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\teventjs.remove(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t}\n\t\t// Check whether fingers has dropped below minFingers.\n\t\tif (fingers === conf.minFingers && conf.fingers < conf.minFingers) {\n\t\t\tself.fingers = conf.fingers;\n\t\t\tself.state = \"end\";\n\t\t\tconf.listener(event, self);\n\t\t}\n\t};\n\t// Generate maintenance commands, and other configurations.\n\tvar self = root.pointerSetup(conf);\n\t// Attach events.\n\teventjs.add(conf.target, \"mousedown\", conf.onPointerDown);\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.gesture = root.gesture;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Pointer\" event proxy (1+ fingers).\n\t----------------------------------------------------\n\tCONFIGURE: minFingers, maxFingers.\n\t----------------------------------------------------\n\teventjs.add(window, \"gesture\", function(event, self) {\n\t\tconsole.log(self.rotation, self.scale, self.fingers, self.state);\n\t});\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nroot.pointerdown =\nroot.pointermove =\nroot.pointerup = function(conf) {\n\tconf.gesture = conf.gesture || \"pointer\";\n\tif (conf.target.isPointerEmitter) return;\n\t// Tracking the events.\n\tvar isDown = true;\n\tconf.onPointerDown = function (event) {\n\t\tisDown = false;\n\t\tself.gesture = \"pointerdown\";\n\t\tconf.listener(event, self);\n\t};\n\tconf.onPointerMove = function (event) {\n\t\tself.gesture = \"pointermove\";\n\t\tconf.listener(event, self, isDown);\n\t};\n\tconf.onPointerUp = function (event) {\n\t\tisDown = true;\n\t\tself.gesture = \"pointerup\";\n\t\tconf.listener(event, self, true);\n\t};\n\t// Generate maintenance commands, and other configurations.\n\tvar self = root.pointerSetup(conf);\n\t// Attach events.\n\teventjs.add(conf.target, \"mousedown\", conf.onPointerDown);\n\teventjs.add(conf.target, \"mousemove\", conf.onPointerMove);\n\teventjs.add(conf.doc, \"mouseup\", conf.onPointerUp);\n\t// Return this object.\n\tconf.target.isPointerEmitter = true;\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.pointerdown = root.pointerdown;\neventjs.Gesture._gestureHandlers.pointermove = root.pointermove;\neventjs.Gesture._gestureHandlers.pointerup = root.pointerup;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Device Motion\" and \"Shake\" event proxy.\n\t----------------------------------------------------\n\thttp://developer.android.com/reference/android/hardware/Sensoreventjs.html#values\n\t----------------------------------------------------\n\teventjs.add(window, \"shake\", function(event, self) {});\n\teventjs.add(window, \"devicemotion\", function(event, self) {\n\t\tconsole.log(self.acceleration, self.accelerationIncludingGravity);\n\t});\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nroot.shake = function(conf) {\n\t// Externally accessible data.\n\tvar self = {\n\t\tgesture: \"devicemotion\",\n\t\tacceleration: {},\n\t\taccelerationIncludingGravity: {},\n\t\ttarget: conf.target,\n\t\tlistener: conf.listener,\n\t\tremove: function() {\n\t\t\twindow.removeEventListener('devicemotion', onDeviceMotion, false);\n\t\t}\n\t};\n\t// Setting up local variables.\n\tvar threshold = 4; // Gravitational threshold.\n\tvar timeout = 1000; // Timeout between shake events.\n\tvar timeframe = 200; // Time between shakes.\n\tvar shakes = 3; // Minimum shakes to trigger event.\n\tvar lastShake = (new Date()).getTime();\n\tvar gravity = { x: 0, y: 0, z: 0 };\n\tvar delta = {\n\t\tx: { count: 0, value: 0 },\n\t\ty: { count: 0, value: 0 },\n\t\tz: { count: 0, value: 0 }\n\t};\n\t// Tracking the events.\n\tvar onDeviceMotion = function(e) {\n\t\tvar alpha = 0.8; // Low pass filter.\n\t\tvar o = e.accelerationIncludingGravity;\n\t\tgravity.x = alpha * gravity.x + (1 - alpha) * o.x;\n\t\tgravity.y = alpha * gravity.y + (1 - alpha) * o.y;\n\t\tgravity.z = alpha * gravity.z + (1 - alpha) * o.z;\n\t\tself.accelerationIncludingGravity = gravity;\n\t\tself.acceleration.x = o.x - gravity.x;\n\t\tself.acceleration.y = o.y - gravity.y;\n\t\tself.acceleration.z = o.z - gravity.z;\n\t\t///\n\t\tif (conf.gesture === \"devicemotion\") {\n\t\t\tconf.listener(e, self);\n\t\t\treturn;\n\t\t}\n\t\tvar data = \"xyz\";\n\t\tvar now = (new Date()).getTime();\n\t\tfor (var n = 0, length = data.length; n < length; n ++) {\n\t\t\tvar letter = data[n];\n\t\t\tvar ACCELERATION = self.acceleration[letter];\n\t\t\tvar DELTA = delta[letter];\n\t\t\tvar abs = Math.abs(ACCELERATION);\n\t\t\t/// Check whether another shake event was recently registered.\n\t\t\tif (now - lastShake < timeout) continue;\n\t\t\t/// Check whether delta surpasses threshold.\n\t\t\tif (abs > threshold) {\n\t\t\t\tvar idx = now * ACCELERATION / abs;\n\t\t\t\tvar span = Math.abs(idx + DELTA.value);\n\t\t\t\t// Check whether last delta was registered within timeframe.\n\t\t\t\tif (DELTA.value && span < timeframe) {\n\t\t\t\t\tDELTA.value = idx;\n\t\t\t\t\tDELTA.count ++;\n\t\t\t\t\t// Check whether delta count has enough shakes.\n\t\t\t\t\tif (DELTA.count === shakes) {\n\t\t\t\t\t\tconf.listener(e, self);\n\t\t\t\t\t\t// Reset tracking.\n\t\t\t\t\t\tlastShake = now;\n\t\t\t\t\t\tDELTA.value = 0;\n\t\t\t\t\t\tDELTA.count = 0;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t// Track first shake.\n\t\t\t\t\tDELTA.value = idx;\n\t\t\t\t\tDELTA.count = 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\t// Attach events.\n\tif (!window.addEventListener) return;\n\twindow.addEventListener('devicemotion', onDeviceMotion, false);\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.shake = root.shake;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Swipe\" event proxy (1+ fingers).\n\t----------------------------------------------------\n\tCONFIGURE: snap, threshold, maxFingers.\n\t----------------------------------------------------\n\teventjs.add(window, \"swipe\", function(event, self) {\n\t\tconsole.log(self.velocity, self.angle);\n\t});\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nvar RAD_DEG = Math.PI / 180;\n\nroot.swipe = function(conf) {\n\tconf.snap = conf.snap || 90; // angle snap.\n\tconf.threshold = conf.threshold || 1; // velocity threshold.\n\tconf.gesture = conf.gesture || \"swipe\";\n\t// Tracking the events.\n\tconf.onPointerDown = function (event) {\n\t\tif (root.pointerStart(event, self, conf)) {\n\t\t\teventjs.add(conf.doc, \"mousemove\", conf.onPointerMove).listener(event);\n\t\t\teventjs.add(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t}\n\t};\n\tconf.onPointerMove = function (event) {\n\t\tvar touches = event.changedTouches || root.getCoords(event);\n\t\tvar length = touches.length;\n\t\tfor (var i = 0; i < length; i ++) {\n\t\t\tvar touch = touches[i];\n\t\t\tvar sid = touch.identifier || Infinity;\n\t\t\tvar o = conf.tracker[sid];\n\t\t\t// Identifier defined outside of listener.\n\t\t\tif (!o) continue;\n\t\t\to.move.x = touch.pageX;\n\t\t\to.move.y = touch.pageY;\n\t\t\to.moveTime = (new Date()).getTime();\n\t\t}\n\t};\n\tconf.onPointerUp = function(event) {\n\t\tif (root.pointerEnd(event, self, conf)) {\n\t\t\teventjs.remove(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\teventjs.remove(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t\t///\n\t\t\tvar velocity1;\n\t\t\tvar velocity2\n\t\t\tvar degree1;\n\t\t\tvar degree2;\n\t\t\t/// Calculate centroid of gesture.\n\t\t\tvar start = { x: 0, y: 0 };\n\t\t\tvar endx = 0;\n\t\t\tvar endy = 0;\n\t\t\tvar length = 0;\n\t\t\t///\n\t\t\tfor (var sid in conf.tracker) {\n\t\t\t\tvar touch = conf.tracker[sid];\n\t\t\t\tvar xdist = touch.move.x - touch.start.x;\n\t\t\t\tvar ydist = touch.move.y - touch.start.y;\n\t\t\t\t///\n\t\t\t\tendx += touch.move.x;\n\t\t\t\tendy += touch.move.y;\n\t\t\t\tstart.x += touch.start.x;\n\t\t\t\tstart.y += touch.start.y;\n\t\t\t\tlength ++;\n\t\t\t\t///\n\t\t\t\tvar distance = Math.sqrt(xdist * xdist + ydist * ydist);\n\t\t\t\tvar ms = touch.moveTime - touch.startTime;\n\t\t\t\tvar degree2 = Math.atan2(xdist, ydist) / RAD_DEG + 180;\n\t\t\t\tvar velocity2 = ms ? distance / ms : 0;\n\t\t\t\tif (typeof(degree1) === \"undefined\") {\n\t\t\t\t\tdegree1 = degree2;\n\t\t\t\t\tvelocity1 = velocity2;\n\t\t\t\t} else if (Math.abs(degree2 - degree1) <= 20) {\n\t\t\t\t\tdegree1 = (degree1 + degree2) / 2;\n\t\t\t\t\tvelocity1 = (velocity1 + velocity2) / 2;\n\t\t\t\t} else {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\t///\n\t\t\tvar fingers = conf.gestureFingers;\n\t\t\tif (conf.minFingers <= fingers && conf.maxFingers >= fingers) {\n\t\t\t\tif (velocity1 > conf.threshold) {\n\t\t\t\t\tstart.x /= length;\n\t\t\t\t\tstart.y /= length;\n\t\t\t\t\tself.start = start;\n\t\t\t\t\tself.x = endx / length;\n\t\t\t\t\tself.y = endy / length;\n\t\t\t\t\tself.angle = -((((degree1 / conf.snap + 0.5) >> 0) * conf.snap || 360) - 360);\n\t\t\t\t\tself.velocity = velocity1;\n\t\t\t\t\tself.fingers = fingers;\n\t\t\t\t\tself.state = \"swipe\";\n\t\t\t\t\tconf.listener(event, self);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n\t// Generate maintenance commands, and other configurations.\n\tvar self = root.pointerSetup(conf);\n\t// Attach events.\n\teventjs.add(conf.target, \"mousedown\", conf.onPointerDown);\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.swipe = root.swipe;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Tap\" and \"Longpress\" event proxy.\n\t----------------------------------------------------\n\tCONFIGURE: delay (longpress), timeout (tap).\n\t----------------------------------------------------\n\teventjs.add(window, \"tap\", function(event, self) {\n\t\tconsole.log(self.fingers);\n\t});\n\t----------------------------------------------------\n\tmulti-finger tap // touch an target for <= 250ms.\n\tmulti-finger longpress // touch an target for >= 500ms\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nroot.longpress = function(conf) {\n\tconf.gesture = \"longpress\";\n\treturn root.tap(conf);\n};\n\nroot.tap = function(conf) {\n\tconf.delay = conf.delay || 500;\n\tconf.timeout = conf.timeout || 250;\n\tconf.driftDeviance = conf.driftDeviance || 10;\n\tconf.gesture = conf.gesture || \"tap\";\n\t// Setting up local variables.\n\tvar timestamp, timeout;\n\t// Tracking the events.\n\tconf.onPointerDown = function (event) {\n\t\tif (root.pointerStart(event, self, conf)) {\n\t\t\ttimestamp = (new Date()).getTime();\n\t\t\t// Initialize event listeners.\n\t\t\teventjs.add(conf.doc, \"mousemove\", conf.onPointerMove).listener(event);\n\t\t\teventjs.add(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t\t// Make sure this is a \"longpress\" event.\n\t\t\tif (conf.gesture !== \"longpress\") return;\n\t\t\ttimeout = setTimeout(function() {\n\t\t\t\tif (event.cancelBubble && ++event.cancelBubbleCount > 1) return;\n\t\t\t\t// Make sure no fingers have been changed.\n\t\t\t\tvar fingers = 0;\n\t\t\t\tfor (var key in conf.tracker) {\n\t\t\t\t\tvar point = conf.tracker[key];\n\t\t\t\t\tif (point.end === true) return;\n\t\t\t\t\tif (conf.cancel) return;\n\t\t\t\t\tfingers ++;\n\t\t\t\t}\n\t\t\t\t// Send callback.\n\t\t\t\tif (conf.minFingers <= fingers && conf.maxFingers >= fingers) {\n\t\t\t\t\tself.state = \"start\";\n\t\t\t\t\tself.fingers = fingers;\n\t\t\t\t\tself.x = point.start.x;\n\t\t\t\t\tself.y = point.start.y;\n\t\t\t\t\tconf.listener(event, self);\n\t\t\t\t}\n\t\t\t}, conf.delay);\n\t\t}\n\t};\n\tconf.onPointerMove = function (event) {\n\t\tvar bbox = conf.bbox;\n\t\tvar touches = event.changedTouches || root.getCoords(event);\n\t\tvar length = touches.length;\n\t\tfor (var i = 0; i < length; i ++) {\n\t\t\tvar touch = touches[i];\n\t\t\tvar identifier = touch.identifier || Infinity;\n\t\t\tvar pt = conf.tracker[identifier];\n\t\t\tif (!pt) continue;\n\t\t\tvar x = (touch.pageX - bbox.x1 - parseInt(window.scrollX));\n\t\t\tvar y = (touch.pageY - bbox.y1 - parseInt(window.scrollY));\n\t\t\t///\n\t\t\tvar dx = x - pt.start.x;\n\t\t\tvar dy = y - pt.start.y;\n\t\t\tvar distance = Math.sqrt(dx * dx + dy * dy);\n\t\t\tif (!(x > 0 && x < bbox.width && // Within target coordinates..\n\t\t\t\t y > 0 && y < bbox.height &&\n\t\t\t\t distance <= conf.driftDeviance)) { // Within drift deviance.\n\t\t\t\t// Cancel out this listener.\n\t\t\t\teventjs.remove(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\t\tconf.cancel = true;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t};\n\tconf.onPointerUp = function(event) {\n\t\tif (root.pointerEnd(event, self, conf)) {\n\t\t\tclearTimeout(timeout);\n\t\t\teventjs.remove(conf.doc, \"mousemove\", conf.onPointerMove);\n\t\t\teventjs.remove(conf.doc, \"mouseup\", conf.onPointerUp);\n\t\t\tif (event.cancelBubble && ++event.cancelBubbleCount > 1) return;\n\t\t\t// Callback release on longpress.\n\t\t\tif (conf.gesture === \"longpress\") {\n\t\t\t\tif (self.state === \"start\") {\n\t\t\t\t\tself.state = \"end\";\n\t\t\t\t\tconf.listener(event, self);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// Cancel event due to movement.\n\t\t\tif (conf.cancel) return;\n\t\t\t// Ensure delay is within margins.\n\t\t\tif ((new Date()).getTime() - timestamp > conf.timeout) return;\n\t\t\t// Send callback.\n\t\t\tvar fingers = conf.gestureFingers;\n\t\t\tif (conf.minFingers <= fingers && conf.maxFingers >= fingers) {\n\t\t\t\tself.state = \"tap\";\n\t\t\t\tself.fingers = conf.gestureFingers;\n\t\t\t\tconf.listener(event, self);\n\t\t\t}\n\t\t}\n\t};\n\t// Generate maintenance commands, and other configurations.\n\tvar self = root.pointerSetup(conf);\n\t// Attach events.\n\teventjs.add(conf.target, \"mousedown\", conf.onPointerDown);\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.tap = root.tap;\neventjs.Gesture._gestureHandlers.longpress = root.longpress;\n\nreturn root;\n\n})(eventjs.proxy);\n/*:\n\t\"Mouse Wheel\" event proxy.\n\t----------------------------------------------------\n\teventjs.add(window, \"wheel\", function(event, self) {\n\t\tconsole.log(self.state, self.wheelDelta);\n\t});\n*/\n\nif (typeof(eventjs) === \"undefined\") var eventjs = {};\nif (typeof(eventjs.proxy) === \"undefined\") eventjs.proxy = {};\n\neventjs.proxy = (function(root) { \"use strict\";\n\nroot.wheelPreventElasticBounce = function(el) {\n\tif (!el) return;\n\tif (typeof(el) === \"string\") el = document.querySelector(el);\n\teventjs.add(el, \"wheel\", function(event, self) {\n\t\tself.preventElasticBounce();\n\t\teventjs.stop(event);\n\t});\n};\n\nroot.wheel = function(conf) {\n\t// Configure event listener.\n\tvar interval;\n\tvar timeout = conf.timeout || 150;\n\tvar count = 0;\n\t// Externally accessible data.\n\tvar self = {\n\t\tgesture: \"wheel\",\n\t\tstate: \"start\",\n\t\twheelDelta: 0,\n\t\ttarget: conf.target,\n\t\tlistener: conf.listener,\n\t\tpreventElasticBounce: function(event) {\n\t\t\tvar target = this.target;\n\t\t\tvar scrollTop = target.scrollTop;\n\t\t\tvar top = scrollTop + target.offsetHeight;\n\t\t\tvar height = target.scrollHeight;\n\t\t\tif (top === height && this.wheelDelta <= 0) eventjs.cancel(event);\n\t\t\telse if (scrollTop === 0 && this.wheelDelta >= 0) eventjs.cancel(event);\n\t\t\teventjs.stop(event);\n\t\t},\n\t\tadd: function() {\n\t\t\tconf.target[add](type, onMouseWheel, false);\n\t\t},\n\t\tremove: function() {\n\t\t\tconf.target[remove](type, onMouseWheel, false);\n\t\t}\n\t};\n\t// Tracking the events.\n\tvar onMouseWheel = function(event) {\n\t\tevent = event || window.event;\n\t\tself.state = count++ ? \"change\" : \"start\";\n\t\tself.wheelDelta = event.detail ? event.detail * -20 : event.wheelDelta;\n\t\tconf.listener(event, self);\n\t\tclearTimeout(interval);\n\t\tinterval = setTimeout(function() {\n\t\t\tcount = 0;\n\t\t\tself.state = \"end\";\n\t\t\tself.wheelDelta = 0;\n\t\t\tconf.listener(event, self);\n\t\t}, timeout);\n\t};\n\t// Attach events.\n\tvar add = document.addEventListener ? \"addEventListener\" : \"attachEvent\";\n\tvar remove = document.removeEventListener ? \"removeEventListener\" : \"detachEvent\";\n\tvar type = eventjs.getEventSupport(\"mousewheel\") ? \"mousewheel\" : \"DOMMouseScroll\";\n\tconf.target[add](type, onMouseWheel, false);\n\t// Return this object.\n\treturn self;\n};\n\neventjs.Gesture = eventjs.Gesture || {};\neventjs.Gesture._gestureHandlers = eventjs.Gesture._gestureHandlers || {};\neventjs.Gesture._gestureHandlers.wheel = root.wheel;\n\nreturn root;\n\n})(eventjs.proxy);\n/*\n\t\"Orientation Change\"\n\t----------------------------------------------------\n\thttps://developer.apple.com/library/safari/documentation/SafariDOMAdditions/Reference/DeviceOrientationEventClassRef/DeviceOrientationEvent/DeviceOrientationEvent.html#//apple_ref/doc/uid/TP40010526\n\t----------------------------------------------------\n\tEvent.add(window, \"deviceorientation\", function(event, self) {});\n*/\n\nif (typeof(Event) === \"undefined\") var Event = {};\nif (typeof(Event.proxy) === \"undefined\") Event.proxy = {};\n\nEvent.proxy = (function(root) { \"use strict\";\n\nroot.orientation = function(conf) {\n\t// Externally accessible data.\n\tvar self = {\n\t\tgesture: \"orientationchange\",\n\t\tprevious: null, /* Report the previous orientation */\n\t\tcurrent: window.orientation,\n\t\ttarget: conf.target,\n\t\tlistener: conf.listener,\n\t\tremove: function() {\n\t\t\twindow.removeEventListener('orientationchange', onOrientationChange, false);\n\t\t}\n\t};\n\n\t// Tracking the events.\n\tvar onOrientationChange = function(e) {\n\n\t\tself.previous = self.current;\n\t\tself.current = window.orientation;\n\t if(self.previous !== null && self.previous != self.current) {\n\t\t\tconf.listener(e, self);\n\t\t\treturn;\n\t }\n\n\n\t};\n\t// Attach events.\n\tif (window.DeviceOrientationEvent) {\n \twindow.addEventListener(\"orientationchange\", onOrientationChange, false);\n \t}\n\t// Return this object.\n\treturn self;\n};\n\nEvent.Gesture = Event.Gesture || {};\nEvent.Gesture._gestureHandlers = Event.Gesture._gestureHandlers || {};\nEvent.Gesture._gestureHandlers.orientation = root.orientation;\n\nreturn root;\n\n})(Event.proxy);\n\n\n(function() {\n\n /**\n * @private\n * @param {String} eventName\n * @param {Function} handler\n */\n function _removeEventListener(eventName, handler) {\n if (!this.__eventListeners[eventName]) {\n return;\n }\n var eventListener = this.__eventListeners[eventName];\n if (handler) {\n eventListener[eventListener.indexOf(handler)] = false;\n }\n else {\n fabric.util.array.fill(eventListener, false);\n }\n }\n\n /**\n * Observes specified event\n * @memberOf fabric.Observable\n * @alias on\n * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n * @param {Function} handler Function that receives a notification when an event of the specified type occurs\n * @return {Self} thisArg\n * @chainable\n */\n function on(eventName, handler) {\n if (!this.__eventListeners) {\n this.__eventListeners = { };\n }\n // one object with key/value pairs was passed\n if (arguments.length === 1) {\n for (var prop in eventName) {\n this.on(prop, eventName[prop]);\n }\n }\n else {\n if (!this.__eventListeners[eventName]) {\n this.__eventListeners[eventName] = [];\n }\n this.__eventListeners[eventName].push(handler);\n }\n return this;\n }\n\n function _once(eventName, handler) {\n var _handler = function () {\n handler.apply(this, arguments);\n this.off(eventName, _handler);\n }.bind(this);\n this.on(eventName, _handler);\n }\n\n function once(eventName, handler) {\n // one object with key/value pairs was passed\n if (arguments.length === 1) {\n for (var prop in eventName) {\n _once.call(this, prop, eventName[prop]);\n }\n }\n else {\n _once.call(this, eventName, handler);\n }\n return this;\n }\n\n /**\n * Stops event observing for a particular event handler. Calling this method\n * without arguments removes all handlers for all events\n * @memberOf fabric.Observable\n * @alias off\n * @param {String|Object} eventName Event name (eg. 'after:render') or object with key/value pairs (eg. {'after:render': handler, 'selection:cleared': handler})\n * @param {Function} handler Function to be deleted from EventListeners\n * @return {Self} thisArg\n * @chainable\n */\n function off(eventName, handler) {\n if (!this.__eventListeners) {\n return this;\n }\n\n // remove all key/value pairs (event name -> event handler)\n if (arguments.length === 0) {\n for (eventName in this.__eventListeners) {\n _removeEventListener.call(this, eventName);\n }\n }\n // one object with key/value pairs was passed\n else if (arguments.length === 1 && typeof arguments[0] === 'object') {\n for (var prop in eventName) {\n _removeEventListener.call(this, prop, eventName[prop]);\n }\n }\n else {\n _removeEventListener.call(this, eventName, handler);\n }\n return this;\n }\n\n /**\n * Fires event with an optional options object\n * @memberOf fabric.Observable\n * @param {String} eventName Event name to fire\n * @param {Object} [options] Options object\n * @return {Self} thisArg\n * @chainable\n */\n function fire(eventName, options) {\n if (!this.__eventListeners) {\n return this;\n }\n\n var listenersForEvent = this.__eventListeners[eventName];\n if (!listenersForEvent) {\n return this;\n }\n\n for (var i = 0, len = listenersForEvent.length; i < len; i++) {\n listenersForEvent[i] && listenersForEvent[i].call(this, options || { });\n }\n this.__eventListeners[eventName] = listenersForEvent.filter(function(value) {\n return value !== false;\n });\n return this;\n }\n\n /**\n * @namespace fabric.Observable\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#events}\n * @see {@link http://fabricjs.com/events|Events demo}\n */\n fabric.Observable = {\n fire: fire,\n on: on,\n once: once,\n off: off,\n };\n})();\n\n\n/**\n * @namespace fabric.Collection\n */\nfabric.Collection = {\n\n _objects: [],\n\n /**\n * Adds objects to collection, Canvas or Group, then renders canvas\n * (if `renderOnAddRemove` is not `false`).\n * in case of Group no changes to bounding box are made.\n * Objects should be instances of (or inherit from) fabric.Object\n * Use of this function is highly discouraged for groups.\n * you can add a bunch of objects with the add method but then you NEED\n * to run a addWithUpdate call for the Group class or position/bbox will be wrong.\n * @param {...fabric.Object} object Zero or more fabric instances\n * @return {Self} thisArg\n * @chainable\n */\n add: function () {\n this._objects.push.apply(this._objects, arguments);\n if (this._onObjectAdded) {\n for (var i = 0, length = arguments.length; i < length; i++) {\n this._onObjectAdded(arguments[i]);\n }\n }\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * Inserts an object into collection at specified index, then renders canvas (if `renderOnAddRemove` is not `false`)\n * An object should be an instance of (or inherit from) fabric.Object\n * Use of this function is highly discouraged for groups.\n * you can add a bunch of objects with the insertAt method but then you NEED\n * to run a addWithUpdate call for the Group class or position/bbox will be wrong.\n * @param {Object} object Object to insert\n * @param {Number} index Index to insert object at\n * @param {Boolean} nonSplicing When `true`, no splicing (shifting) of objects occurs\n * @return {Self} thisArg\n * @chainable\n */\n insertAt: function (object, index, nonSplicing) {\n var objects = this._objects;\n if (nonSplicing) {\n objects[index] = object;\n }\n else {\n objects.splice(index, 0, object);\n }\n this._onObjectAdded && this._onObjectAdded(object);\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * Removes objects from a collection, then renders canvas (if `renderOnAddRemove` is not `false`)\n * @param {...fabric.Object} object Zero or more fabric instances\n * @return {Self} thisArg\n * @chainable\n */\n remove: function() {\n var objects = this._objects,\n index, somethingRemoved = false;\n\n for (var i = 0, length = arguments.length; i < length; i++) {\n index = objects.indexOf(arguments[i]);\n\n // only call onObjectRemoved if an object was actually removed\n if (index !== -1) {\n somethingRemoved = true;\n objects.splice(index, 1);\n this._onObjectRemoved && this._onObjectRemoved(arguments[i]);\n }\n }\n\n this.renderOnAddRemove && somethingRemoved && this.requestRenderAll();\n return this;\n },\n\n /**\n * Executes given function for each object in this group\n * @param {Function} callback\n * Callback invoked with current object as first argument,\n * index - as second and an array of all objects - as third.\n * Callback is invoked in a context of Global Object (e.g. `window`)\n * when no `context` argument is given\n *\n * @param {Object} context Context (aka thisObject)\n * @return {Self} thisArg\n * @chainable\n */\n forEachObject: function(callback, context) {\n var objects = this.getObjects();\n for (var i = 0, len = objects.length; i < len; i++) {\n callback.call(context, objects[i], i, objects);\n }\n return this;\n },\n\n /**\n * Returns an array of children objects of this instance\n * Type parameter introduced in 1.3.10\n * since 2.3.5 this method return always a COPY of the array;\n * @param {String} [type] When specified, only objects of this type are returned\n * @return {Array}\n */\n getObjects: function(type) {\n if (typeof type === 'undefined') {\n return this._objects.concat();\n }\n return this._objects.filter(function(o) {\n return o.type === type;\n });\n },\n\n /**\n * Returns object at specified index\n * @param {Number} index\n * @return {Self} thisArg\n */\n item: function (index) {\n return this._objects[index];\n },\n\n /**\n * Returns true if collection contains no objects\n * @return {Boolean} true if collection is empty\n */\n isEmpty: function () {\n return this._objects.length === 0;\n },\n\n /**\n * Returns a size of a collection (i.e: length of an array containing its objects)\n * @return {Number} Collection size\n */\n size: function() {\n return this._objects.length;\n },\n\n /**\n * Returns true if collection contains an object\n * @param {Object} object Object to check against\n * @param {Boolean} [deep=false] `true` to check all descendants, `false` to check only `_objects`\n * @return {Boolean} `true` if collection contains an object\n */\n contains: function (object, deep) {\n if (this._objects.indexOf(object) > -1) {\n return true;\n }\n else if (deep) {\n return this._objects.some(function (obj) {\n return typeof obj.contains === 'function' && obj.contains(object, true);\n });\n }\n return false;\n },\n\n /**\n * Returns number representation of a collection complexity\n * @return {Number} complexity\n */\n complexity: function () {\n return this._objects.reduce(function (memo, current) {\n memo += current.complexity ? current.complexity() : 0;\n return memo;\n }, 0);\n }\n};\n\n\n/**\n * @namespace fabric.CommonMethods\n */\nfabric.CommonMethods = {\n\n /**\n * Sets object's properties from options\n * @param {Object} [options] Options object\n */\n _setOptions: function(options) {\n for (var prop in options) {\n this.set(prop, options[prop]);\n }\n },\n\n /**\n * @private\n * @param {Object} [filler] Options object\n * @param {String} [property] property to set the Gradient to\n */\n _initGradient: function(filler, property) {\n if (filler && filler.colorStops && !(filler instanceof fabric.Gradient)) {\n this.set(property, new fabric.Gradient(filler));\n }\n },\n\n /**\n * @private\n * @param {Object} [filler] Options object\n * @param {String} [property] property to set the Pattern to\n * @param {Function} [callback] callback to invoke after pattern load\n */\n _initPattern: function(filler, property, callback) {\n if (filler && filler.source && !(filler instanceof fabric.Pattern)) {\n this.set(property, new fabric.Pattern(filler, callback));\n }\n else {\n callback && callback();\n }\n },\n\n /**\n * @private\n */\n _setObject: function(obj) {\n for (var prop in obj) {\n this._set(prop, obj[prop]);\n }\n },\n\n /**\n * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.\n * @param {String|Object} key Property name or object (if object, iterate over the object properties)\n * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)\n * @return {fabric.Object} thisArg\n * @chainable\n */\n set: function(key, value) {\n if (typeof key === 'object') {\n this._setObject(key);\n }\n else {\n this._set(key, value);\n }\n return this;\n },\n\n _set: function(key, value) {\n this[key] = value;\n },\n\n /**\n * Toggles specified property from `true` to `false` or from `false` to `true`\n * @param {String} property Property to toggle\n * @return {fabric.Object} thisArg\n * @chainable\n */\n toggle: function(property) {\n var value = this.get(property);\n if (typeof value === 'boolean') {\n this.set(property, !value);\n }\n return this;\n },\n\n /**\n * Basic getter\n * @param {String} property Property name\n * @return {*} value of a property\n */\n get: function(property) {\n return this[property];\n }\n};\n\n\n(function(global) {\n\n var sqrt = Math.sqrt,\n atan2 = Math.atan2,\n pow = Math.pow,\n PiBy180 = Math.PI / 180,\n PiBy2 = Math.PI / 2;\n\n /**\n * @namespace fabric.util\n */\n fabric.util = {\n\n /**\n * Calculate the cos of an angle, avoiding returning floats for known results\n * @static\n * @memberOf fabric.util\n * @param {Number} angle the angle in radians or in degree\n * @return {Number}\n */\n cos: function(angle) {\n if (angle === 0) { return 1; }\n if (angle < 0) {\n // cos(a) = cos(-a)\n angle = -angle;\n }\n var angleSlice = angle / PiBy2;\n switch (angleSlice) {\n case 1: case 3: return 0;\n case 2: return -1;\n }\n return Math.cos(angle);\n },\n\n /**\n * Calculate the sin of an angle, avoiding returning floats for known results\n * @static\n * @memberOf fabric.util\n * @param {Number} angle the angle in radians or in degree\n * @return {Number}\n */\n sin: function(angle) {\n if (angle === 0) { return 0; }\n var angleSlice = angle / PiBy2, sign = 1;\n if (angle < 0) {\n // sin(-a) = -sin(a)\n sign = -1;\n }\n switch (angleSlice) {\n case 1: return sign;\n case 2: return 0;\n case 3: return -sign;\n }\n return Math.sin(angle);\n },\n\n /**\n * Removes value from an array.\n * Presence of value (and its position in an array) is determined via `Array.prototype.indexOf`\n * @static\n * @memberOf fabric.util\n * @param {Array} array\n * @param {*} value\n * @return {Array} original array\n */\n removeFromArray: function(array, value) {\n var idx = array.indexOf(value);\n if (idx !== -1) {\n array.splice(idx, 1);\n }\n return array;\n },\n\n /**\n * Returns random number between 2 specified ones.\n * @static\n * @memberOf fabric.util\n * @param {Number} min lower limit\n * @param {Number} max upper limit\n * @return {Number} random value (between min and max)\n */\n getRandomInt: function(min, max) {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n },\n\n /**\n * Transforms degrees to radians.\n * @static\n * @memberOf fabric.util\n * @param {Number} degrees value in degrees\n * @return {Number} value in radians\n */\n degreesToRadians: function(degrees) {\n return degrees * PiBy180;\n },\n\n /**\n * Transforms radians to degrees.\n * @static\n * @memberOf fabric.util\n * @param {Number} radians value in radians\n * @return {Number} value in degrees\n */\n radiansToDegrees: function(radians) {\n return radians / PiBy180;\n },\n\n /**\n * Rotates `point` around `origin` with `radians`\n * @static\n * @memberOf fabric.util\n * @param {fabric.Point} point The point to rotate\n * @param {fabric.Point} origin The origin of the rotation\n * @param {Number} radians The radians of the angle for the rotation\n * @return {fabric.Point} The new rotated point\n */\n rotatePoint: function(point, origin, radians) {\n var newPoint = new fabric.Point(point.x - origin.x, point.y - origin.y),\n v = fabric.util.rotateVector(newPoint, radians);\n return new fabric.Point(v.x, v.y).addEquals(origin);\n },\n\n /**\n * Rotates `vector` with `radians`\n * @static\n * @memberOf fabric.util\n * @param {Object} vector The vector to rotate (x and y)\n * @param {Number} radians The radians of the angle for the rotation\n * @return {Object} The new rotated point\n */\n rotateVector: function(vector, radians) {\n var sin = fabric.util.sin(radians),\n cos = fabric.util.cos(radians),\n rx = vector.x * cos - vector.y * sin,\n ry = vector.x * sin + vector.y * cos;\n return {\n x: rx,\n y: ry\n };\n },\n\n /**\n * Creates a vetor from points represented as a point\n * @static\n * @memberOf fabric.util\n *\n * @typedef {Object} Point\n * @property {number} x\n * @property {number} y\n *\n * @param {Point} from\n * @param {Point} to\n * @returns {Point} vector\n */\n createVector: function (from, to) {\n return new fabric.Point(to.x - from.x, to.y - from.y);\n },\n\n /**\n * Calculates angle between 2 vectors using dot product\n * @static\n * @memberOf fabric.util\n * @param {Point} a\n * @param {Point} b\n * @returns the angle in radian between the vectors\n */\n calcAngleBetweenVectors: function (a, b) {\n return Math.acos((a.x * b.x + a.y * b.y) / (Math.hypot(a.x, a.y) * Math.hypot(b.x, b.y)));\n },\n\n /**\n * @static\n * @memberOf fabric.util\n * @param {Point} v\n * @returns {Point} vector representing the unit vector of pointing to the direction of `v`\n */\n getHatVector: function (v) {\n return new fabric.Point(v.x, v.y).multiply(1 / Math.hypot(v.x, v.y));\n },\n\n /**\n * @static\n * @memberOf fabric.util\n * @param {Point} A\n * @param {Point} B\n * @param {Point} C\n * @returns {{ vector: Point, angle: number }} vector representing the bisector of A and A's angle\n */\n getBisector: function (A, B, C) {\n var AB = fabric.util.createVector(A, B), AC = fabric.util.createVector(A, C);\n var alpha = fabric.util.calcAngleBetweenVectors(AB, AC);\n // check if alpha is relative to AB->BC\n var ro = fabric.util.calcAngleBetweenVectors(fabric.util.rotateVector(AB, alpha), AC);\n var phi = alpha * (ro === 0 ? 1 : -1) / 2;\n return {\n vector: fabric.util.getHatVector(fabric.util.rotateVector(AB, phi)),\n angle: alpha\n };\n },\n\n /**\n * Project stroke width on points returning 2 projections for each point as follows:\n * - `miter`: 2 points corresponding to the outer boundary and the inner boundary of stroke.\n * - `bevel`: 2 points corresponding to the bevel boundaries, tangent to the bisector.\n * - `round`: same as `bevel`\n * Used to calculate object's bounding box\n * @static\n * @memberOf fabric.util\n * @param {Point[]} points\n * @param {Object} options\n * @param {number} options.strokeWidth\n * @param {'miter'|'bevel'|'round'} options.strokeLineJoin\n * @param {number} options.strokeMiterLimit https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-miterlimit\n * @param {boolean} options.strokeUniform\n * @param {number} options.scaleX\n * @param {number} options.scaleY\n * @param {boolean} [openPath] whether the shape is open or not, affects the calculations of the first and last points\n * @returns {fabric.Point[]} array of size 2n/4n of all suspected points\n */\n projectStrokeOnPoints: function (points, options, openPath) {\n var coords = [], s = options.strokeWidth / 2,\n strokeUniformScalar = options.strokeUniform ?\n new fabric.Point(1 / options.scaleX, 1 / options.scaleY) : new fabric.Point(1, 1),\n getStrokeHatVector = function (v) {\n var scalar = s / (Math.hypot(v.x, v.y));\n return new fabric.Point(v.x * scalar * strokeUniformScalar.x, v.y * scalar * strokeUniformScalar.y);\n };\n if (points.length <= 1) {return coords;}\n points.forEach(function (p, index) {\n var A = new fabric.Point(p.x, p.y), B, C;\n if (index === 0) {\n C = points[index + 1];\n B = openPath ? getStrokeHatVector(fabric.util.createVector(C, A)).addEquals(A) : points[points.length - 1];\n }\n else if (index === points.length - 1) {\n B = points[index - 1];\n C = openPath ? getStrokeHatVector(fabric.util.createVector(B, A)).addEquals(A) : points[0];\n }\n else {\n B = points[index - 1];\n C = points[index + 1];\n }\n var bisector = fabric.util.getBisector(A, B, C),\n bisectorVector = bisector.vector,\n alpha = bisector.angle,\n scalar,\n miterVector;\n if (options.strokeLineJoin === 'miter') {\n scalar = -s / Math.sin(alpha / 2);\n miterVector = new fabric.Point(\n bisectorVector.x * scalar * strokeUniformScalar.x,\n bisectorVector.y * scalar * strokeUniformScalar.y\n );\n if (Math.hypot(miterVector.x, miterVector.y) / s <= options.strokeMiterLimit) {\n coords.push(A.add(miterVector));\n coords.push(A.subtract(miterVector));\n return;\n }\n }\n scalar = -s * Math.SQRT2;\n miterVector = new fabric.Point(\n bisectorVector.x * scalar * strokeUniformScalar.x,\n bisectorVector.y * scalar * strokeUniformScalar.y\n );\n coords.push(A.add(miterVector));\n coords.push(A.subtract(miterVector));\n });\n return coords;\n },\n\n /**\n * Apply transform t to point p\n * @static\n * @memberOf fabric.util\n * @param {fabric.Point} p The point to transform\n * @param {Array} t The transform\n * @param {Boolean} [ignoreOffset] Indicates that the offset should not be applied\n * @return {fabric.Point} The transformed point\n */\n transformPoint: function(p, t, ignoreOffset) {\n if (ignoreOffset) {\n return new fabric.Point(\n t[0] * p.x + t[2] * p.y,\n t[1] * p.x + t[3] * p.y\n );\n }\n return new fabric.Point(\n t[0] * p.x + t[2] * p.y + t[4],\n t[1] * p.x + t[3] * p.y + t[5]\n );\n },\n\n /**\n * Returns coordinates of points's bounding rectangle (left, top, width, height)\n * @param {Array} points 4 points array\n * @param {Array} [transform] an array of 6 numbers representing a 2x3 transform matrix\n * @return {Object} Object with left, top, width, height properties\n */\n makeBoundingBoxFromPoints: function(points, transform) {\n if (transform) {\n for (var i = 0; i < points.length; i++) {\n points[i] = fabric.util.transformPoint(points[i], transform);\n }\n }\n var xPoints = [points[0].x, points[1].x, points[2].x, points[3].x],\n minX = fabric.util.array.min(xPoints),\n maxX = fabric.util.array.max(xPoints),\n width = maxX - minX,\n yPoints = [points[0].y, points[1].y, points[2].y, points[3].y],\n minY = fabric.util.array.min(yPoints),\n maxY = fabric.util.array.max(yPoints),\n height = maxY - minY;\n\n return {\n left: minX,\n top: minY,\n width: width,\n height: height\n };\n },\n\n /**\n * Invert transformation t\n * @static\n * @memberOf fabric.util\n * @param {Array} t The transform\n * @return {Array} The inverted transform\n */\n invertTransform: function(t) {\n var a = 1 / (t[0] * t[3] - t[1] * t[2]),\n r = [a * t[3], -a * t[1], -a * t[2], a * t[0]],\n o = fabric.util.transformPoint({ x: t[4], y: t[5] }, r, true);\n r[4] = -o.x;\n r[5] = -o.y;\n return r;\n },\n\n /**\n * A wrapper around Number#toFixed, which contrary to native method returns number, not string.\n * @static\n * @memberOf fabric.util\n * @param {Number|String} number number to operate on\n * @param {Number} fractionDigits number of fraction digits to \"leave\"\n * @return {Number}\n */\n toFixed: function(number, fractionDigits) {\n return parseFloat(Number(number).toFixed(fractionDigits));\n },\n\n /**\n * Converts from attribute value to pixel value if applicable.\n * Returns converted pixels or original value not converted.\n * @param {Number|String} value number to operate on\n * @param {Number} fontSize\n * @return {Number|String}\n */\n parseUnit: function(value, fontSize) {\n var unit = /\\D{0,2}$/.exec(value),\n number = parseFloat(value);\n if (!fontSize) {\n fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;\n }\n switch (unit[0]) {\n case 'mm':\n return number * fabric.DPI / 25.4;\n\n case 'cm':\n return number * fabric.DPI / 2.54;\n\n case 'in':\n return number * fabric.DPI;\n\n case 'pt':\n return number * fabric.DPI / 72; // or * 4 / 3\n\n case 'pc':\n return number * fabric.DPI / 72 * 12; // or * 16\n\n case 'em':\n return number * fontSize;\n\n default:\n return number;\n }\n },\n\n /**\n * Function which always returns `false`.\n * @static\n * @memberOf fabric.util\n * @return {Boolean}\n */\n falseFunction: function() {\n return false;\n },\n\n /**\n * Returns klass \"Class\" object of given namespace\n * @memberOf fabric.util\n * @param {String} type Type of object (eg. 'circle')\n * @param {String} namespace Namespace to get klass \"Class\" object from\n * @return {Object} klass \"Class\"\n */\n getKlass: function(type, namespace) {\n // capitalize first letter only\n type = fabric.util.string.camelize(type.charAt(0).toUpperCase() + type.slice(1));\n return fabric.util.resolveNamespace(namespace)[type];\n },\n\n /**\n * Returns array of attributes for given svg that fabric parses\n * @memberOf fabric.util\n * @param {String} type Type of svg element (eg. 'circle')\n * @return {Array} string names of supported attributes\n */\n getSvgAttributes: function(type) {\n var attributes = [\n 'instantiated_by_use',\n 'style',\n 'id',\n 'class'\n ];\n switch (type) {\n case 'linearGradient':\n attributes = attributes.concat(['x1', 'y1', 'x2', 'y2', 'gradientUnits', 'gradientTransform']);\n break;\n case 'radialGradient':\n attributes = attributes.concat(['gradientUnits', 'gradientTransform', 'cx', 'cy', 'r', 'fx', 'fy', 'fr']);\n break;\n case 'stop':\n attributes = attributes.concat(['offset', 'stop-color', 'stop-opacity']);\n break;\n }\n return attributes;\n },\n\n /**\n * Returns object of given namespace\n * @memberOf fabric.util\n * @param {String} namespace Namespace string e.g. 'fabric.Image.filter' or 'fabric'\n * @return {Object} Object for given namespace (default fabric)\n */\n resolveNamespace: function(namespace) {\n if (!namespace) {\n return fabric;\n }\n\n var parts = namespace.split('.'),\n len = parts.length, i,\n obj = global || fabric.window;\n\n for (i = 0; i < len; ++i) {\n obj = obj[parts[i]];\n }\n\n return obj;\n },\n\n /**\n * Loads image element from given url and passes it to a callback\n * @memberOf fabric.util\n * @param {String} url URL representing an image\n * @param {Function} callback Callback; invoked with loaded image\n * @param {*} [context] Context to invoke callback in\n * @param {Object} [crossOrigin] crossOrigin value to set image element to\n */\n loadImage: function(url, callback, context, crossOrigin) {\n if (!url) {\n callback && callback.call(context, url);\n return;\n }\n\n var img = fabric.util.createImage();\n\n /** @ignore */\n var onLoadCallback = function () {\n callback && callback.call(context, img, false);\n img = img.onload = img.onerror = null;\n };\n\n img.onload = onLoadCallback;\n /** @ignore */\n img.onerror = function() {\n fabric.log('Error loading ' + img.src);\n callback && callback.call(context, null, true);\n img = img.onload = img.onerror = null;\n };\n\n // data-urls appear to be buggy with crossOrigin\n // https://github.com/kangax/fabric.js/commit/d0abb90f1cd5c5ef9d2a94d3fb21a22330da3e0a#commitcomment-4513767\n // see https://code.google.com/p/chromium/issues/detail?id=315152\n // https://bugzilla.mozilla.org/show_bug.cgi?id=935069\n // crossOrigin null is the same as not set.\n if (url.indexOf('data') !== 0 &&\n crossOrigin !== undefined &&\n crossOrigin !== null) {\n img.crossOrigin = crossOrigin;\n }\n\n // IE10 / IE11-Fix: SVG contents from data: URI\n // will only be available if the IMG is present\n // in the DOM (and visible)\n if (url.substring(0,14) === 'data:image/svg') {\n img.onload = null;\n fabric.util.loadImageInDom(img, onLoadCallback);\n }\n\n img.src = url;\n },\n\n /**\n * Attaches SVG image with data: URL to the dom\n * @memberOf fabric.util\n * @param {Object} img Image object with data:image/svg src\n * @param {Function} callback Callback; invoked with loaded image\n * @return {Object} DOM element (div containing the SVG image)\n */\n loadImageInDom: function(img, onLoadCallback) {\n var div = fabric.document.createElement('div');\n div.style.width = div.style.height = '1px';\n div.style.left = div.style.top = '-100%';\n div.style.position = 'absolute';\n div.appendChild(img);\n fabric.document.querySelector('body').appendChild(div);\n /**\n * Wrap in function to:\n * 1. Call existing callback\n * 2. Cleanup DOM\n */\n img.onload = function () {\n onLoadCallback();\n div.parentNode.removeChild(div);\n div = null;\n };\n },\n\n /**\n * Creates corresponding fabric instances from their object representations\n * @static\n * @memberOf fabric.util\n * @param {Array} objects Objects to enliven\n * @param {Function} callback Callback to invoke when all objects are created\n * @param {String} namespace Namespace to get klass \"Class\" object from\n * @param {Function} reviver Method for further parsing of object elements,\n * called after each fabric object created.\n */\n enlivenObjects: function(objects, callback, namespace, reviver) {\n objects = objects || [];\n\n var enlivenedObjects = [],\n numLoadedObjects = 0,\n numTotalObjects = objects.length;\n\n function onLoaded() {\n if (++numLoadedObjects === numTotalObjects) {\n callback && callback(enlivenedObjects.filter(function(obj) {\n // filter out undefined objects (objects that gave error)\n return obj;\n }));\n }\n }\n\n if (!numTotalObjects) {\n callback && callback(enlivenedObjects);\n return;\n }\n\n objects.forEach(function (o, index) {\n // if sparse array\n if (!o || !o.type) {\n onLoaded();\n return;\n }\n var klass = fabric.util.getKlass(o.type, namespace);\n klass.fromObject(o, function (obj, error) {\n error || (enlivenedObjects[index] = obj);\n reviver && reviver(o, obj, error);\n onLoaded();\n });\n });\n },\n\n /**\n * Creates corresponding fabric instances residing in an object, e.g. `clipPath`\n * @see {@link fabric.Object.ENLIVEN_PROPS}\n * @param {Object} object\n * @param {Object} [context] assign enlived props to this object (pass null to skip this)\n * @param {(objects:fabric.Object[]) => void} callback\n */\n enlivenObjectEnlivables: function (object, context, callback) {\n var enlivenProps = fabric.Object.ENLIVEN_PROPS.filter(function (key) { return !!object[key]; });\n fabric.util.enlivenObjects(enlivenProps.map(function (key) { return object[key]; }), function (enlivedProps) {\n var objects = {};\n enlivenProps.forEach(function (key, index) {\n objects[key] = enlivedProps[index];\n context && (context[key] = enlivedProps[index]);\n });\n callback && callback(objects);\n });\n },\n\n /**\n * Create and wait for loading of patterns\n * @static\n * @memberOf fabric.util\n * @param {Array} patterns Objects to enliven\n * @param {Function} callback Callback to invoke when all objects are created\n * called after each fabric object created.\n */\n enlivenPatterns: function(patterns, callback) {\n patterns = patterns || [];\n\n function onLoaded() {\n if (++numLoadedPatterns === numPatterns) {\n callback && callback(enlivenedPatterns);\n }\n }\n\n var enlivenedPatterns = [],\n numLoadedPatterns = 0,\n numPatterns = patterns.length;\n\n if (!numPatterns) {\n callback && callback(enlivenedPatterns);\n return;\n }\n\n patterns.forEach(function (p, index) {\n if (p && p.source) {\n new fabric.Pattern(p, function(pattern) {\n enlivenedPatterns[index] = pattern;\n onLoaded();\n });\n }\n else {\n enlivenedPatterns[index] = p;\n onLoaded();\n }\n });\n },\n\n /**\n * Groups SVG elements (usually those retrieved from SVG document)\n * @static\n * @memberOf fabric.util\n * @param {Array} elements SVG elements to group\n * @param {Object} [options] Options object\n * @param {String} path Value to set sourcePath to\n * @return {fabric.Object|fabric.Group}\n */\n groupSVGElements: function(elements, options, path) {\n var object;\n if (elements && elements.length === 1) {\n return elements[0];\n }\n if (options) {\n if (options.width && options.height) {\n options.centerPoint = {\n x: options.width / 2,\n y: options.height / 2\n };\n }\n else {\n delete options.width;\n delete options.height;\n }\n }\n object = new fabric.Group(elements, options);\n if (typeof path !== 'undefined') {\n object.sourcePath = path;\n }\n return object;\n },\n\n /**\n * Populates an object with properties of another object\n * @static\n * @memberOf fabric.util\n * @param {Object} source Source object\n * @param {Object} destination Destination object\n * @return {Array} properties Properties names to include\n */\n populateWithProperties: function(source, destination, properties) {\n if (properties && Array.isArray(properties)) {\n for (var i = 0, len = properties.length; i < len; i++) {\n if (properties[i] in source) {\n destination[properties[i]] = source[properties[i]];\n }\n }\n }\n },\n\n /**\n * Creates canvas element\n * @static\n * @memberOf fabric.util\n * @return {CanvasElement} initialized canvas element\n */\n createCanvasElement: function() {\n return fabric.document.createElement('canvas');\n },\n\n /**\n * Creates a canvas element that is a copy of another and is also painted\n * @param {CanvasElement} canvas to copy size and content of\n * @static\n * @memberOf fabric.util\n * @return {CanvasElement} initialized canvas element\n */\n copyCanvasElement: function(canvas) {\n var newCanvas = fabric.util.createCanvasElement();\n newCanvas.width = canvas.width;\n newCanvas.height = canvas.height;\n newCanvas.getContext('2d').drawImage(canvas, 0, 0);\n return newCanvas;\n },\n\n /**\n * since 2.6.0 moved from canvas instance to utility.\n * @param {CanvasElement} canvasEl to copy size and content of\n * @param {String} format 'jpeg' or 'png', in some browsers 'webp' is ok too\n * @param {Number} quality <= 1 and > 0\n * @static\n * @memberOf fabric.util\n * @return {String} data url\n */\n toDataURL: function(canvasEl, format, quality) {\n return canvasEl.toDataURL('image/' + format, quality);\n },\n\n /**\n * Creates image element (works on client and node)\n * @static\n * @memberOf fabric.util\n * @return {HTMLImageElement} HTML image element\n */\n createImage: function() {\n return fabric.document.createElement('img');\n },\n\n /**\n * Multiply matrix A by matrix B to nest transformations\n * @static\n * @memberOf fabric.util\n * @param {Array} a First transformMatrix\n * @param {Array} b Second transformMatrix\n * @param {Boolean} is2x2 flag to multiply matrices as 2x2 matrices\n * @return {Array} The product of the two transform matrices\n */\n multiplyTransformMatrices: function(a, b, is2x2) {\n // Matrix multiply a * b\n return [\n a[0] * b[0] + a[2] * b[1],\n a[1] * b[0] + a[3] * b[1],\n a[0] * b[2] + a[2] * b[3],\n a[1] * b[2] + a[3] * b[3],\n is2x2 ? 0 : a[0] * b[4] + a[2] * b[5] + a[4],\n is2x2 ? 0 : a[1] * b[4] + a[3] * b[5] + a[5]\n ];\n },\n\n /**\n * Decomposes standard 2x3 matrix into transform components\n * @static\n * @memberOf fabric.util\n * @param {Array} a transformMatrix\n * @return {Object} Components of transform\n */\n qrDecompose: function(a) {\n var angle = atan2(a[1], a[0]),\n denom = pow(a[0], 2) + pow(a[1], 2),\n scaleX = sqrt(denom),\n scaleY = (a[0] * a[3] - a[2] * a[1]) / scaleX,\n skewX = atan2(a[0] * a[2] + a[1] * a [3], denom);\n return {\n angle: angle / PiBy180,\n scaleX: scaleX,\n scaleY: scaleY,\n skewX: skewX / PiBy180,\n skewY: 0,\n translateX: a[4],\n translateY: a[5]\n };\n },\n\n /**\n * Returns a transform matrix starting from an object of the same kind of\n * the one returned from qrDecompose, useful also if you want to calculate some\n * transformations from an object that is not enlived yet\n * @static\n * @memberOf fabric.util\n * @param {Object} options\n * @param {Number} [options.angle] angle in degrees\n * @return {Number[]} transform matrix\n */\n calcRotateMatrix: function(options) {\n if (!options.angle) {\n return fabric.iMatrix.concat();\n }\n var theta = fabric.util.degreesToRadians(options.angle),\n cos = fabric.util.cos(theta),\n sin = fabric.util.sin(theta);\n return [cos, sin, -sin, cos, 0, 0];\n },\n\n /**\n * Returns a transform matrix starting from an object of the same kind of\n * the one returned from qrDecompose, useful also if you want to calculate some\n * transformations from an object that is not enlived yet.\n * is called DimensionsTransformMatrix because those properties are the one that influence\n * the size of the resulting box of the object.\n * @static\n * @memberOf fabric.util\n * @param {Object} options\n * @param {Number} [options.scaleX]\n * @param {Number} [options.scaleY]\n * @param {Boolean} [options.flipX]\n * @param {Boolean} [options.flipY]\n * @param {Number} [options.skewX]\n * @param {Number} [options.skewY]\n * @return {Number[]} transform matrix\n */\n calcDimensionsMatrix: function(options) {\n var scaleX = typeof options.scaleX === 'undefined' ? 1 : options.scaleX,\n scaleY = typeof options.scaleY === 'undefined' ? 1 : options.scaleY,\n scaleMatrix = [\n options.flipX ? -scaleX : scaleX,\n 0,\n 0,\n options.flipY ? -scaleY : scaleY,\n 0,\n 0],\n multiply = fabric.util.multiplyTransformMatrices,\n degreesToRadians = fabric.util.degreesToRadians;\n if (options.skewX) {\n scaleMatrix = multiply(\n scaleMatrix,\n [1, 0, Math.tan(degreesToRadians(options.skewX)), 1],\n true);\n }\n if (options.skewY) {\n scaleMatrix = multiply(\n scaleMatrix,\n [1, Math.tan(degreesToRadians(options.skewY)), 0, 1],\n true);\n }\n return scaleMatrix;\n },\n\n /**\n * Returns a transform matrix starting from an object of the same kind of\n * the one returned from qrDecompose, useful also if you want to calculate some\n * transformations from an object that is not enlived yet\n * @static\n * @memberOf fabric.util\n * @param {Object} options\n * @param {Number} [options.angle]\n * @param {Number} [options.scaleX]\n * @param {Number} [options.scaleY]\n * @param {Boolean} [options.flipX]\n * @param {Boolean} [options.flipY]\n * @param {Number} [options.skewX]\n * @param {Number} [options.skewX]\n * @param {Number} [options.translateX]\n * @param {Number} [options.translateY]\n * @return {Number[]} transform matrix\n */\n composeMatrix: function(options) {\n var matrix = [1, 0, 0, 1, options.translateX || 0, options.translateY || 0],\n multiply = fabric.util.multiplyTransformMatrices;\n if (options.angle) {\n matrix = multiply(matrix, fabric.util.calcRotateMatrix(options));\n }\n if (options.scaleX !== 1 || options.scaleY !== 1 ||\n options.skewX || options.skewY || options.flipX || options.flipY) {\n matrix = multiply(matrix, fabric.util.calcDimensionsMatrix(options));\n }\n return matrix;\n },\n\n /**\n * reset an object transform state to neutral. Top and left are not accounted for\n * @static\n * @memberOf fabric.util\n * @param {fabric.Object} target object to transform\n */\n resetObjectTransform: function (target) {\n target.scaleX = 1;\n target.scaleY = 1;\n target.skewX = 0;\n target.skewY = 0;\n target.flipX = false;\n target.flipY = false;\n target.rotate(0);\n },\n\n /**\n * Extract Object transform values\n * @static\n * @memberOf fabric.util\n * @param {fabric.Object} target object to read from\n * @return {Object} Components of transform\n */\n saveObjectTransform: function (target) {\n return {\n scaleX: target.scaleX,\n scaleY: target.scaleY,\n skewX: target.skewX,\n skewY: target.skewY,\n angle: target.angle,\n left: target.left,\n flipX: target.flipX,\n flipY: target.flipY,\n top: target.top\n };\n },\n\n /**\n * Returns true if context has transparent pixel\n * at specified location (taking tolerance into account)\n * @param {CanvasRenderingContext2D} ctx context\n * @param {Number} x x coordinate\n * @param {Number} y y coordinate\n * @param {Number} tolerance Tolerance\n */\n isTransparent: function(ctx, x, y, tolerance) {\n\n // If tolerance is > 0 adjust start coords to take into account.\n // If moves off Canvas fix to 0\n if (tolerance > 0) {\n if (x > tolerance) {\n x -= tolerance;\n }\n else {\n x = 0;\n }\n if (y > tolerance) {\n y -= tolerance;\n }\n else {\n y = 0;\n }\n }\n\n var _isTransparent = true, i, temp,\n imageData = ctx.getImageData(x, y, (tolerance * 2) || 1, (tolerance * 2) || 1),\n l = imageData.data.length;\n\n // Split image data - for tolerance > 1, pixelDataSize = 4;\n for (i = 3; i < l; i += 4) {\n temp = imageData.data[i];\n _isTransparent = temp <= 0;\n if (_isTransparent === false) {\n break; // Stop if colour found\n }\n }\n\n imageData = null;\n\n return _isTransparent;\n },\n\n /**\n * Parse preserveAspectRatio attribute from element\n * @param {string} attribute to be parsed\n * @return {Object} an object containing align and meetOrSlice attribute\n */\n parsePreserveAspectRatioAttribute: function(attribute) {\n var meetOrSlice = 'meet', alignX = 'Mid', alignY = 'Mid',\n aspectRatioAttrs = attribute.split(' '), align;\n\n if (aspectRatioAttrs && aspectRatioAttrs.length) {\n meetOrSlice = aspectRatioAttrs.pop();\n if (meetOrSlice !== 'meet' && meetOrSlice !== 'slice') {\n align = meetOrSlice;\n meetOrSlice = 'meet';\n }\n else if (aspectRatioAttrs.length) {\n align = aspectRatioAttrs.pop();\n }\n }\n //divide align in alignX and alignY\n alignX = align !== 'none' ? align.slice(1, 4) : 'none';\n alignY = align !== 'none' ? align.slice(5, 8) : 'none';\n return {\n meetOrSlice: meetOrSlice,\n alignX: alignX,\n alignY: alignY\n };\n },\n\n /**\n * Clear char widths cache for the given font family or all the cache if no\n * fontFamily is specified.\n * Use it if you know you are loading fonts in a lazy way and you are not waiting\n * for custom fonts to load properly when adding text objects to the canvas.\n * If a text object is added when its own font is not loaded yet, you will get wrong\n * measurement and so wrong bounding boxes.\n * After the font cache is cleared, either change the textObject text content or call\n * initDimensions() to trigger a recalculation\n * @memberOf fabric.util\n * @param {String} [fontFamily] font family to clear\n */\n clearFabricFontCache: function(fontFamily) {\n fontFamily = (fontFamily || '').toLowerCase();\n if (!fontFamily) {\n fabric.charWidthsCache = { };\n }\n else if (fabric.charWidthsCache[fontFamily]) {\n delete fabric.charWidthsCache[fontFamily];\n }\n },\n\n /**\n * Given current aspect ratio, determines the max width and height that can\n * respect the total allowed area for the cache.\n * @memberOf fabric.util\n * @param {Number} ar aspect ratio\n * @param {Number} maximumArea Maximum area you want to achieve\n * @return {Object.x} Limited dimensions by X\n * @return {Object.y} Limited dimensions by Y\n */\n limitDimsByArea: function(ar, maximumArea) {\n var roughWidth = Math.sqrt(maximumArea * ar),\n perfLimitSizeY = Math.floor(maximumArea / roughWidth);\n return { x: Math.floor(roughWidth), y: perfLimitSizeY };\n },\n\n capValue: function(min, value, max) {\n return Math.max(min, Math.min(value, max));\n },\n\n /**\n * Finds the scale for the object source to fit inside the object destination,\n * keeping aspect ratio intact.\n * respect the total allowed area for the cache.\n * @memberOf fabric.util\n * @param {Object | fabric.Object} source\n * @param {Number} source.height natural unscaled height of the object\n * @param {Number} source.width natural unscaled width of the object\n * @param {Object | fabric.Object} destination\n * @param {Number} destination.height natural unscaled height of the object\n * @param {Number} destination.width natural unscaled width of the object\n * @return {Number} scale factor to apply to source to fit into destination\n */\n findScaleToFit: function(source, destination) {\n return Math.min(destination.width / source.width, destination.height / source.height);\n },\n\n /**\n * Finds the scale for the object source to cover entirely the object destination,\n * keeping aspect ratio intact.\n * respect the total allowed area for the cache.\n * @memberOf fabric.util\n * @param {Object | fabric.Object} source\n * @param {Number} source.height natural unscaled height of the object\n * @param {Number} source.width natural unscaled width of the object\n * @param {Object | fabric.Object} destination\n * @param {Number} destination.height natural unscaled height of the object\n * @param {Number} destination.width natural unscaled width of the object\n * @return {Number} scale factor to apply to source to cover destination\n */\n findScaleToCover: function(source, destination) {\n return Math.max(destination.width / source.width, destination.height / source.height);\n },\n\n /**\n * given an array of 6 number returns something like `\"matrix(...numbers)\"`\n * @memberOf fabric.util\n * @param {Array} transform an array with 6 numbers\n * @return {String} transform matrix for svg\n * @return {Object.y} Limited dimensions by Y\n */\n matrixToSVG: function(transform) {\n return 'matrix(' + transform.map(function(value) {\n return fabric.util.toFixed(value, fabric.Object.NUM_FRACTION_DIGITS);\n }).join(' ') + ')';\n },\n\n /**\n * given an object and a transform, apply the inverse transform to the object,\n * this is equivalent to remove from that object that transformation, so that\n * added in a space with the removed transform, the object will be the same as before.\n * Removing from an object a transform that scale by 2 is like scaling it by 1/2.\n * Removing from an object a transfrom that rotate by 30deg is like rotating by 30deg\n * in the opposite direction.\n * This util is used to add objects inside transformed groups or nested groups.\n * @memberOf fabric.util\n * @param {fabric.Object} object the object you want to transform\n * @param {Array} transform the destination transform\n */\n removeTransformFromObject: function(object, transform) {\n var inverted = fabric.util.invertTransform(transform),\n finalTransform = fabric.util.multiplyTransformMatrices(inverted, object.calcOwnMatrix());\n fabric.util.applyTransformToObject(object, finalTransform);\n },\n\n /**\n * given an object and a transform, apply the transform to the object.\n * this is equivalent to change the space where the object is drawn.\n * Adding to an object a transform that scale by 2 is like scaling it by 2.\n * This is used when removing an object from an active selection for example.\n * @memberOf fabric.util\n * @param {fabric.Object} object the object you want to transform\n * @param {Array} transform the destination transform\n */\n addTransformToObject: function(object, transform) {\n fabric.util.applyTransformToObject(\n object,\n fabric.util.multiplyTransformMatrices(transform, object.calcOwnMatrix())\n );\n },\n\n /**\n * discard an object transform state and apply the one from the matrix.\n * @memberOf fabric.util\n * @param {fabric.Object} object the object you want to transform\n * @param {Array} transform the destination transform\n */\n applyTransformToObject: function(object, transform) {\n var options = fabric.util.qrDecompose(transform),\n center = new fabric.Point(options.translateX, options.translateY);\n object.flipX = false;\n object.flipY = false;\n object.set('scaleX', options.scaleX);\n object.set('scaleY', options.scaleY);\n object.skewX = options.skewX;\n object.skewY = options.skewY;\n object.angle = options.angle;\n object.setPositionByOrigin(center, 'center', 'center');\n },\n\n /**\n * given a width and height, return the size of the bounding box\n * that can contains the box with width/height with applied transform\n * described in options.\n * Use to calculate the boxes around objects for controls.\n * @memberOf fabric.util\n * @param {Number} width\n * @param {Number} height\n * @param {Object} options\n * @param {Number} options.scaleX\n * @param {Number} options.scaleY\n * @param {Number} options.skewX\n * @param {Number} options.skewY\n * @return {Object.x} width of containing\n * @return {Object.y} height of containing\n */\n sizeAfterTransform: function(width, height, options) {\n var dimX = width / 2, dimY = height / 2,\n points = [\n {\n x: -dimX,\n y: -dimY\n },\n {\n x: dimX,\n y: -dimY\n },\n {\n x: -dimX,\n y: dimY\n },\n {\n x: dimX,\n y: dimY\n }],\n transformMatrix = fabric.util.calcDimensionsMatrix(options),\n bbox = fabric.util.makeBoundingBoxFromPoints(points, transformMatrix);\n return {\n x: bbox.width,\n y: bbox.height,\n };\n },\n\n /**\n * Merges 2 clip paths into one visually equal clip path\n *\n * **IMPORTANT**:\\\n * Does **NOT** clone the arguments, clone them proir if necessary.\n *\n * Creates a wrapper (group) that contains one clip path and is clipped by the other so content is kept where both overlap.\n * Use this method if both the clip paths may have nested clip paths of their own, so assigning one to the other's clip path property is not possible.\n *\n * In order to handle the `inverted` property we follow logic described in the following cases:\\\n * **(1)** both clip paths are inverted - the clip paths pass the inverted prop to the wrapper and loose it themselves.\\\n * **(2)** one is inverted and the other isn't - the wrapper shouldn't become inverted and the inverted clip path must clip the non inverted one to produce an identical visual effect.\\\n * **(3)** both clip paths are not inverted - wrapper and clip paths remain unchanged.\n *\n * @memberOf fabric.util\n * @param {fabric.Object} c1\n * @param {fabric.Object} c2\n * @returns {fabric.Object} merged clip path\n */\n mergeClipPaths: function (c1, c2) {\n var a = c1, b = c2;\n if (a.inverted && !b.inverted) {\n // case (2)\n a = c2;\n b = c1;\n }\n // `b` becomes `a`'s clip path so we transform `b` to `a` coordinate plane\n fabric.util.applyTransformToObject(\n b,\n fabric.util.multiplyTransformMatrices(\n fabric.util.invertTransform(a.calcTransformMatrix()),\n b.calcTransformMatrix()\n )\n );\n // assign the `inverted` prop to the wrapping group\n var inverted = a.inverted && b.inverted;\n if (inverted) {\n // case (1)\n a.inverted = b.inverted = false;\n }\n return new fabric.Group([a], { clipPath: b, inverted: inverted });\n },\n };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n var _join = Array.prototype.join,\n commandLengths = {\n m: 2,\n l: 2,\n h: 1,\n v: 1,\n c: 6,\n s: 4,\n q: 4,\n t: 2,\n a: 7\n },\n repeatedCommands = {\n m: 'l',\n M: 'L'\n };\n function segmentToBezier(th2, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY) {\n var costh2 = fabric.util.cos(th2),\n sinth2 = fabric.util.sin(th2),\n costh3 = fabric.util.cos(th3),\n sinth3 = fabric.util.sin(th3),\n toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1,\n toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1,\n cp1X = fromX + mT * ( -cosTh * rx * sinth2 - sinTh * ry * costh2),\n cp1Y = fromY + mT * ( -sinTh * rx * sinth2 + cosTh * ry * costh2),\n cp2X = toX + mT * ( cosTh * rx * sinth3 + sinTh * ry * costh3),\n cp2Y = toY + mT * ( sinTh * rx * sinth3 - cosTh * ry * costh3);\n\n return ['C',\n cp1X, cp1Y,\n cp2X, cp2Y,\n toX, toY\n ];\n }\n\n /* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp\n * by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here\n * http://mozilla.org/MPL/2.0/\n */\n function arcToSegments(toX, toY, rx, ry, large, sweep, rotateX) {\n var PI = Math.PI, th = rotateX * PI / 180,\n sinTh = fabric.util.sin(th),\n cosTh = fabric.util.cos(th),\n fromX = 0, fromY = 0;\n\n rx = Math.abs(rx);\n ry = Math.abs(ry);\n\n var px = -cosTh * toX * 0.5 - sinTh * toY * 0.5,\n py = -cosTh * toY * 0.5 + sinTh * toX * 0.5,\n rx2 = rx * rx, ry2 = ry * ry, py2 = py * py, px2 = px * px,\n pl = rx2 * ry2 - rx2 * py2 - ry2 * px2,\n root = 0;\n\n if (pl < 0) {\n var s = Math.sqrt(1 - pl / (rx2 * ry2));\n rx *= s;\n ry *= s;\n }\n else {\n root = (large === sweep ? -1.0 : 1.0) *\n Math.sqrt( pl / (rx2 * py2 + ry2 * px2));\n }\n\n var cx = root * rx * py / ry,\n cy = -root * ry * px / rx,\n cx1 = cosTh * cx - sinTh * cy + toX * 0.5,\n cy1 = sinTh * cx + cosTh * cy + toY * 0.5,\n mTheta = calcVectorAngle(1, 0, (px - cx) / rx, (py - cy) / ry),\n dtheta = calcVectorAngle((px - cx) / rx, (py - cy) / ry, (-px - cx) / rx, (-py - cy) / ry);\n\n if (sweep === 0 && dtheta > 0) {\n dtheta -= 2 * PI;\n }\n else if (sweep === 1 && dtheta < 0) {\n dtheta += 2 * PI;\n }\n\n // Convert into cubic bezier segments <= 90deg\n var segments = Math.ceil(Math.abs(dtheta / PI * 2)),\n result = [], mDelta = dtheta / segments,\n mT = 8 / 3 * Math.sin(mDelta / 4) * Math.sin(mDelta / 4) / Math.sin(mDelta / 2),\n th3 = mTheta + mDelta;\n\n for (var i = 0; i < segments; i++) {\n result[i] = segmentToBezier(mTheta, th3, cosTh, sinTh, rx, ry, cx1, cy1, mT, fromX, fromY);\n fromX = result[i][5];\n fromY = result[i][6];\n mTheta = th3;\n th3 += mDelta;\n }\n return result;\n }\n\n /*\n * Private\n */\n function calcVectorAngle(ux, uy, vx, vy) {\n var ta = Math.atan2(uy, ux),\n tb = Math.atan2(vy, vx);\n if (tb >= ta) {\n return tb - ta;\n }\n else {\n return 2 * Math.PI - (ta - tb);\n }\n }\n\n /**\n * Calculate bounding box of a beziercurve\n * @param {Number} x0 starting point\n * @param {Number} y0\n * @param {Number} x1 first control point\n * @param {Number} y1\n * @param {Number} x2 secondo control point\n * @param {Number} y2\n * @param {Number} x3 end of bezier\n * @param {Number} y3\n */\n // taken from http://jsbin.com/ivomiq/56/edit no credits available for that.\n // TODO: can we normalize this with the starting points set at 0 and then translated the bbox?\n function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) {\n var argsString;\n if (fabric.cachesBoundsOfCurve) {\n argsString = _join.call(arguments);\n if (fabric.boundsOfCurveCache[argsString]) {\n return fabric.boundsOfCurveCache[argsString];\n }\n }\n\n var sqrt = Math.sqrt,\n min = Math.min, max = Math.max,\n abs = Math.abs, tvalues = [],\n bounds = [[], []],\n a, b, c, t, t1, t2, b2ac, sqrtb2ac;\n\n b = 6 * x0 - 12 * x1 + 6 * x2;\n a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;\n c = 3 * x1 - 3 * x0;\n\n for (var i = 0; i < 2; ++i) {\n if (i > 0) {\n b = 6 * y0 - 12 * y1 + 6 * y2;\n a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;\n c = 3 * y1 - 3 * y0;\n }\n\n if (abs(a) < 1e-12) {\n if (abs(b) < 1e-12) {\n continue;\n }\n t = -c / b;\n if (0 < t && t < 1) {\n tvalues.push(t);\n }\n continue;\n }\n b2ac = b * b - 4 * c * a;\n if (b2ac < 0) {\n continue;\n }\n sqrtb2ac = sqrt(b2ac);\n t1 = (-b + sqrtb2ac) / (2 * a);\n if (0 < t1 && t1 < 1) {\n tvalues.push(t1);\n }\n t2 = (-b - sqrtb2ac) / (2 * a);\n if (0 < t2 && t2 < 1) {\n tvalues.push(t2);\n }\n }\n\n var x, y, j = tvalues.length, jlen = j, mt;\n while (j--) {\n t = tvalues[j];\n mt = 1 - t;\n x = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);\n bounds[0][j] = x;\n\n y = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);\n bounds[1][j] = y;\n }\n\n bounds[0][jlen] = x0;\n bounds[1][jlen] = y0;\n bounds[0][jlen + 1] = x3;\n bounds[1][jlen + 1] = y3;\n var result = [\n {\n x: min.apply(null, bounds[0]),\n y: min.apply(null, bounds[1])\n },\n {\n x: max.apply(null, bounds[0]),\n y: max.apply(null, bounds[1])\n }\n ];\n if (fabric.cachesBoundsOfCurve) {\n fabric.boundsOfCurveCache[argsString] = result;\n }\n return result;\n }\n\n /**\n * Converts arc to a bunch of bezier curves\n * @param {Number} fx starting point x\n * @param {Number} fy starting point y\n * @param {Array} coords Arc command\n */\n function fromArcToBeziers(fx, fy, coords) {\n var rx = coords[1],\n ry = coords[2],\n rot = coords[3],\n large = coords[4],\n sweep = coords[5],\n tx = coords[6],\n ty = coords[7],\n segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);\n\n for (var i = 0, len = segsNorm.length; i < len; i++) {\n segsNorm[i][1] += fx;\n segsNorm[i][2] += fy;\n segsNorm[i][3] += fx;\n segsNorm[i][4] += fy;\n segsNorm[i][5] += fx;\n segsNorm[i][6] += fy;\n }\n return segsNorm;\n };\n\n /**\n * This function take a parsed SVG path and make it simpler for fabricJS logic.\n * simplification consist of: only UPPERCASE absolute commands ( relative converted to absolute )\n * S converted in C, T converted in Q, A converted in C.\n * @param {Array} path the array of commands of a parsed svg path for fabric.Path\n * @return {Array} the simplified array of commands of a parsed svg path for fabric.Path\n */\n function makePathSimpler(path) {\n // x and y represent the last point of the path. the previous command point.\n // we add them to each relative command to make it an absolute comment.\n // we also swap the v V h H with L, because are easier to transform.\n var x = 0, y = 0, len = path.length,\n // x1 and y1 represent the last point of the subpath. the subpath is started with\n // m or M command. When a z or Z command is drawn, x and y need to be resetted to\n // the last x1 and y1.\n x1 = 0, y1 = 0, current, i, converted,\n // previous will host the letter of the previous command, to handle S and T.\n // controlX and controlY will host the previous reflected control point\n destinationPath = [], previous, controlX, controlY;\n for (i = 0; i < len; ++i) {\n converted = false;\n current = path[i].slice(0);\n switch (current[0]) { // first letter\n case 'l': // lineto, relative\n current[0] = 'L';\n current[1] += x;\n current[2] += y;\n // falls through\n case 'L':\n x = current[1];\n y = current[2];\n break;\n case 'h': // horizontal lineto, relative\n current[1] += x;\n // falls through\n case 'H':\n current[0] = 'L';\n current[2] = y;\n x = current[1];\n break;\n case 'v': // vertical lineto, relative\n current[1] += y;\n // falls through\n case 'V':\n current[0] = 'L';\n y = current[1];\n current[1] = x;\n current[2] = y;\n break;\n case 'm': // moveTo, relative\n current[0] = 'M';\n current[1] += x;\n current[2] += y;\n // falls through\n case 'M':\n x = current[1];\n y = current[2];\n x1 = current[1];\n y1 = current[2];\n break;\n case 'c': // bezierCurveTo, relative\n current[0] = 'C';\n current[1] += x;\n current[2] += y;\n current[3] += x;\n current[4] += y;\n current[5] += x;\n current[6] += y;\n // falls through\n case 'C':\n controlX = current[3];\n controlY = current[4];\n x = current[5];\n y = current[6];\n break;\n case 's': // shorthand cubic bezierCurveTo, relative\n current[0] = 'S';\n current[1] += x;\n current[2] += y;\n current[3] += x;\n current[4] += y;\n // falls through\n case 'S':\n // would be sScC but since we are swapping sSc for C, we check just that.\n if (previous === 'C') {\n // calculate reflection of previous control points\n controlX = 2 * x - controlX;\n controlY = 2 * y - controlY;\n }\n else {\n // If there is no previous command or if the previous command was not a C, c, S, or s,\n // the control point is coincident with the current point\n controlX = x;\n controlY = y;\n }\n x = current[3];\n y = current[4];\n current[0] = 'C';\n current[5] = current[3];\n current[6] = current[4];\n current[3] = current[1];\n current[4] = current[2];\n current[1] = controlX;\n current[2] = controlY;\n // current[3] and current[4] are NOW the second control point.\n // we keep it for the next reflection.\n controlX = current[3];\n controlY = current[4];\n break;\n case 'q': // quadraticCurveTo, relative\n current[0] = 'Q';\n current[1] += x;\n current[2] += y;\n current[3] += x;\n current[4] += y;\n // falls through\n case 'Q':\n controlX = current[1];\n controlY = current[2];\n x = current[3];\n y = current[4];\n break;\n case 't': // shorthand quadraticCurveTo, relative\n current[0] = 'T';\n current[1] += x;\n current[2] += y;\n // falls through\n case 'T':\n if (previous === 'Q') {\n // calculate reflection of previous control point\n controlX = 2 * x - controlX;\n controlY = 2 * y - controlY;\n }\n else {\n // If there is no previous command or if the previous command was not a Q, q, T or t,\n // assume the control point is coincident with the current point\n controlX = x;\n controlY = y;\n }\n current[0] = 'Q';\n x = current[1];\n y = current[2];\n current[1] = controlX;\n current[2] = controlY;\n current[3] = x;\n current[4] = y;\n break;\n case 'a':\n current[0] = 'A';\n current[6] += x;\n current[7] += y;\n // falls through\n case 'A':\n converted = true;\n destinationPath = destinationPath.concat(fromArcToBeziers(x, y, current));\n x = current[6];\n y = current[7];\n break;\n case 'z':\n case 'Z':\n x = x1;\n y = y1;\n break;\n default:\n }\n if (!converted) {\n destinationPath.push(current);\n }\n previous = current[0];\n }\n return destinationPath;\n };\n\n /**\n * Calc length from point x1,y1 to x2,y2\n * @param {Number} x1 starting point x\n * @param {Number} y1 starting point y\n * @param {Number} x2 starting point x\n * @param {Number} y2 starting point y\n * @return {Number} length of segment\n */\n function calcLineLength(x1, y1, x2, y2) {\n return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));\n }\n\n // functions for the Cubic beizer\n // taken from: https://github.com/konvajs/konva/blob/7.0.5/src/shapes/Path.ts#L350\n function CB1(t) {\n return t * t * t;\n }\n function CB2(t) {\n return 3 * t * t * (1 - t);\n }\n function CB3(t) {\n return 3 * t * (1 - t) * (1 - t);\n }\n function CB4(t) {\n return (1 - t) * (1 - t) * (1 - t);\n }\n\n function getPointOnCubicBezierIterator(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) {\n return function(pct) {\n var c1 = CB1(pct), c2 = CB2(pct), c3 = CB3(pct), c4 = CB4(pct);\n return {\n x: p4x * c1 + p3x * c2 + p2x * c3 + p1x * c4,\n y: p4y * c1 + p3y * c2 + p2y * c3 + p1y * c4\n };\n };\n }\n\n function getTangentCubicIterator(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) {\n return function (pct) {\n var invT = 1 - pct,\n tangentX = (3 * invT * invT * (p2x - p1x)) + (6 * invT * pct * (p3x - p2x)) +\n (3 * pct * pct * (p4x - p3x)),\n tangentY = (3 * invT * invT * (p2y - p1y)) + (6 * invT * pct * (p3y - p2y)) +\n (3 * pct * pct * (p4y - p3y));\n return Math.atan2(tangentY, tangentX);\n };\n }\n\n function QB1(t) {\n return t * t;\n }\n\n function QB2(t) {\n return 2 * t * (1 - t);\n }\n\n function QB3(t) {\n return (1 - t) * (1 - t);\n }\n\n function getPointOnQuadraticBezierIterator(p1x, p1y, p2x, p2y, p3x, p3y) {\n return function(pct) {\n var c1 = QB1(pct), c2 = QB2(pct), c3 = QB3(pct);\n return {\n x: p3x * c1 + p2x * c2 + p1x * c3,\n y: p3y * c1 + p2y * c2 + p1y * c3\n };\n };\n }\n\n function getTangentQuadraticIterator(p1x, p1y, p2x, p2y, p3x, p3y) {\n return function (pct) {\n var invT = 1 - pct,\n tangentX = (2 * invT * (p2x - p1x)) + (2 * pct * (p3x - p2x)),\n tangentY = (2 * invT * (p2y - p1y)) + (2 * pct * (p3y - p2y));\n return Math.atan2(tangentY, tangentX);\n };\n }\n\n\n // this will run over a path segment ( a cubic or quadratic segment) and approximate it\n // with 100 segemnts. This will good enough to calculate the length of the curve\n function pathIterator(iterator, x1, y1) {\n var tempP = { x: x1, y: y1 }, p, tmpLen = 0, perc;\n for (perc = 1; perc <= 100; perc += 1) {\n p = iterator(perc / 100);\n tmpLen += calcLineLength(tempP.x, tempP.y, p.x, p.y);\n tempP = p;\n }\n return tmpLen;\n }\n\n /**\n * Given a pathInfo, and a distance in pixels, find the percentage from 0 to 1\n * that correspond to that pixels run over the path.\n * The percentage will be then used to find the correct point on the canvas for the path.\n * @param {Array} segInfo fabricJS collection of information on a parsed path\n * @param {Number} distance from starting point, in pixels.\n * @return {Object} info object with x and y ( the point on canvas ) and angle, the tangent on that point;\n */\n function findPercentageForDistance(segInfo, distance) {\n var perc = 0, tmpLen = 0, iterator = segInfo.iterator, tempP = { x: segInfo.x, y: segInfo.y },\n p, nextLen, nextStep = 0.01, angleFinder = segInfo.angleFinder, lastPerc;\n // nextStep > 0.0001 covers 0.00015625 that 1/64th of 1/100\n // the path\n while (tmpLen < distance && nextStep > 0.0001) {\n p = iterator(perc);\n lastPerc = perc;\n nextLen = calcLineLength(tempP.x, tempP.y, p.x, p.y);\n // compare tmpLen each cycle with distance, decide next perc to test.\n if ((nextLen + tmpLen) > distance) {\n // we discard this step and we make smaller steps.\n perc -= nextStep;\n nextStep /= 2;\n }\n else {\n tempP = p;\n perc += nextStep;\n tmpLen += nextLen;\n }\n }\n p.angle = angleFinder(lastPerc);\n return p;\n }\n\n /**\n * Run over a parsed and simplifed path and extrac some informations.\n * informations are length of each command and starting point\n * @param {Array} path fabricJS parsed path commands\n * @return {Array} path commands informations\n */\n function getPathSegmentsInfo(path) {\n var totalLength = 0, len = path.length, current,\n //x2 and y2 are the coords of segment start\n //x1 and y1 are the coords of the current point\n x1 = 0, y1 = 0, x2 = 0, y2 = 0, info = [], iterator, tempInfo, angleFinder;\n for (var i = 0; i < len; i++) {\n current = path[i];\n tempInfo = {\n x: x1,\n y: y1,\n command: current[0],\n };\n switch (current[0]) { //first letter\n case 'M':\n tempInfo.length = 0;\n x2 = x1 = current[1];\n y2 = y1 = current[2];\n break;\n case 'L':\n tempInfo.length = calcLineLength(x1, y1, current[1], current[2]);\n x1 = current[1];\n y1 = current[2];\n break;\n case 'C':\n iterator = getPointOnCubicBezierIterator(\n x1,\n y1,\n current[1],\n current[2],\n current[3],\n current[4],\n current[5],\n current[6]\n );\n angleFinder = getTangentCubicIterator(\n x1,\n y1,\n current[1],\n current[2],\n current[3],\n current[4],\n current[5],\n current[6]\n );\n tempInfo.iterator = iterator;\n tempInfo.angleFinder = angleFinder;\n tempInfo.length = pathIterator(iterator, x1, y1);\n x1 = current[5];\n y1 = current[6];\n break;\n case 'Q':\n iterator = getPointOnQuadraticBezierIterator(\n x1,\n y1,\n current[1],\n current[2],\n current[3],\n current[4]\n );\n angleFinder = getTangentQuadraticIterator(\n x1,\n y1,\n current[1],\n current[2],\n current[3],\n current[4]\n );\n tempInfo.iterator = iterator;\n tempInfo.angleFinder = angleFinder;\n tempInfo.length = pathIterator(iterator, x1, y1);\n x1 = current[3];\n y1 = current[4];\n break;\n case 'Z':\n case 'z':\n // we add those in order to ease calculations later\n tempInfo.destX = x2;\n tempInfo.destY = y2;\n tempInfo.length = calcLineLength(x1, y1, x2, y2);\n x1 = x2;\n y1 = y2;\n break;\n }\n totalLength += tempInfo.length;\n info.push(tempInfo);\n }\n info.push({ length: totalLength, x: x1, y: y1 });\n return info;\n }\n\n function getPointOnPath(path, distance, infos) {\n if (!infos) {\n infos = getPathSegmentsInfo(path);\n }\n var i = 0;\n while ((distance - infos[i].length > 0) && i < (infos.length - 2)) {\n distance -= infos[i].length;\n i++;\n }\n // var distance = infos[infos.length - 1] * perc;\n var segInfo = infos[i], segPercent = distance / segInfo.length,\n command = segInfo.command, segment = path[i], info;\n\n switch (command) {\n case 'M':\n return { x: segInfo.x, y: segInfo.y, angle: 0 };\n case 'Z':\n case 'z':\n info = new fabric.Point(segInfo.x, segInfo.y).lerp(\n new fabric.Point(segInfo.destX, segInfo.destY),\n segPercent\n );\n info.angle = Math.atan2(segInfo.destY - segInfo.y, segInfo.destX - segInfo.x);\n return info;\n case 'L':\n info = new fabric.Point(segInfo.x, segInfo.y).lerp(\n new fabric.Point(segment[1], segment[2]),\n segPercent\n );\n info.angle = Math.atan2(segment[2] - segInfo.y, segment[1] - segInfo.x);\n return info;\n case 'C':\n return findPercentageForDistance(segInfo, distance);\n case 'Q':\n return findPercentageForDistance(segInfo, distance);\n }\n }\n\n /**\n *\n * @param {string} pathString\n * @return {(string|number)[][]} An array of SVG path commands\n * @example Usage\n * parsePath('M 3 4 Q 3 5 2 1 4 0 Q 9 12 2 1 4 0') === [\n * ['M', 3, 4],\n * ['Q', 3, 5, 2, 1, 4, 0],\n * ['Q', 9, 12, 2, 1, 4, 0],\n * ];\n *\n */\n function parsePath(pathString) {\n var result = [],\n coords = [],\n currentPath,\n parsed,\n re = fabric.rePathCommand,\n rNumber = '[-+]?(?:\\\\d*\\\\.\\\\d+|\\\\d+\\\\.?)(?:[eE][-+]?\\\\d+)?\\\\s*',\n rNumberCommaWsp = '(' + rNumber + ')' + fabric.commaWsp,\n rFlagCommaWsp = '([01])' + fabric.commaWsp + '?',\n rArcSeq = rNumberCommaWsp + '?' + rNumberCommaWsp + '?' + rNumberCommaWsp + rFlagCommaWsp + rFlagCommaWsp +\n rNumberCommaWsp + '?(' + rNumber + ')',\n regArcArgumentSequence = new RegExp(rArcSeq, 'g'),\n match,\n coordsStr,\n // one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values)\n path;\n if (!pathString || !pathString.match) {\n return result;\n }\n path = pathString.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);\n\n for (var i = 0, coordsParsed, len = path.length; i < len; i++) {\n currentPath = path[i];\n\n coordsStr = currentPath.slice(1).trim();\n coords.length = 0;\n\n var command = currentPath.charAt(0);\n coordsParsed = [command];\n\n if (command.toLowerCase() === 'a') {\n // arcs have special flags that apparently don't require spaces so handle special\n for (var args; (args = regArcArgumentSequence.exec(coordsStr));) {\n for (var j = 1; j < args.length; j++) {\n coords.push(args[j]);\n }\n }\n }\n else {\n while ((match = re.exec(coordsStr))) {\n coords.push(match[0]);\n }\n }\n\n for (var j = 0, jlen = coords.length; j < jlen; j++) {\n parsed = parseFloat(coords[j]);\n if (!isNaN(parsed)) {\n coordsParsed.push(parsed);\n }\n }\n\n var commandLength = commandLengths[command.toLowerCase()],\n repeatedCommand = repeatedCommands[command] || command;\n\n if (coordsParsed.length - 1 > commandLength) {\n for (var k = 1, klen = coordsParsed.length; k < klen; k += commandLength) {\n result.push([command].concat(coordsParsed.slice(k, k + commandLength)));\n command = repeatedCommand;\n }\n }\n else {\n result.push(coordsParsed);\n }\n }\n\n return result;\n };\n\n /**\n *\n * Converts points to a smooth SVG path\n * @param {{ x: number,y: number }[]} points Array of points\n * @param {number} [correction] Apply a correction to the path (usually we use `width / 1000`). If value is undefined 0 is used as the correction value.\n * @return {(string|number)[][]} An array of SVG path commands\n */\n function getSmoothPathFromPoints(points, correction) {\n var path = [], i,\n p1 = new fabric.Point(points[0].x, points[0].y),\n p2 = new fabric.Point(points[1].x, points[1].y),\n len = points.length, multSignX = 1, multSignY = 0, manyPoints = len > 2;\n correction = correction || 0;\n\n if (manyPoints) {\n multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;\n multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1;\n }\n path.push(['M', p1.x - multSignX * correction, p1.y - multSignY * correction]);\n for (i = 1; i < len; i++) {\n if (!p1.eq(p2)) {\n var midPoint = p1.midPointFrom(p2);\n // p1 is our bezier control point\n // midpoint is our endpoint\n // start point is p(i-1) value.\n path.push(['Q', p1.x, p1.y, midPoint.x, midPoint.y]);\n }\n p1 = points[i];\n if ((i + 1) < points.length) {\n p2 = points[i + 1];\n }\n }\n if (manyPoints) {\n multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;\n multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;\n }\n path.push(['L', p1.x + multSignX * correction, p1.y + multSignY * correction]);\n return path;\n }\n /**\n * Transform a path by transforming each segment.\n * it has to be a simplified path or it won't work.\n * WARNING: this depends from pathOffset for correct operation\n * @param {Array} path fabricJS parsed and simplified path commands\n * @param {Array} transform matrix that represent the transformation\n * @param {Object} [pathOffset] the fabric.Path pathOffset\n * @param {Number} pathOffset.x\n * @param {Number} pathOffset.y\n * @returns {Array} the transformed path\n */\n function transformPath(path, transform, pathOffset) {\n if (pathOffset) {\n transform = fabric.util.multiplyTransformMatrices(\n transform,\n [1, 0, 0, 1, -pathOffset.x, -pathOffset.y]\n );\n }\n return path.map(function(pathSegment) {\n var newSegment = pathSegment.slice(0), point = {};\n for (var i = 1; i < pathSegment.length - 1; i += 2) {\n point.x = pathSegment[i];\n point.y = pathSegment[i + 1];\n point = fabric.util.transformPoint(point, transform);\n newSegment[i] = point.x;\n newSegment[i + 1] = point.y;\n }\n return newSegment;\n });\n }\n\n /**\n * Join path commands to go back to svg format\n * @param {Array} pathData fabricJS parsed path commands\n * @return {String} joined path 'M 0 0 L 20 30'\n */\n fabric.util.joinPath = function(pathData) {\n return pathData.map(function (segment) { return segment.join(' '); }).join(' ');\n };\n fabric.util.parsePath = parsePath;\n fabric.util.makePathSimpler = makePathSimpler;\n fabric.util.getSmoothPathFromPoints = getSmoothPathFromPoints;\n fabric.util.getPathSegmentsInfo = getPathSegmentsInfo;\n fabric.util.getBoundsOfCurve = getBoundsOfCurve;\n fabric.util.getPointOnPath = getPointOnPath;\n fabric.util.transformPath = transformPath;\n})();\n\n\n(function() {\n\n var slice = Array.prototype.slice;\n\n /**\n * Invokes method on all items in a given array\n * @memberOf fabric.util.array\n * @param {Array} array Array to iterate over\n * @param {String} method Name of a method to invoke\n * @return {Array}\n */\n function invoke(array, method) {\n var args = slice.call(arguments, 2), result = [];\n for (var i = 0, len = array.length; i < len; i++) {\n result[i] = args.length ? array[i][method].apply(array[i], args) : array[i][method].call(array[i]);\n }\n return result;\n }\n\n /**\n * Finds maximum value in array (not necessarily \"first\" one)\n * @memberOf fabric.util.array\n * @param {Array} array Array to iterate over\n * @param {String} byProperty\n * @return {*}\n */\n function max(array, byProperty) {\n return find(array, byProperty, function(value1, value2) {\n return value1 >= value2;\n });\n }\n\n /**\n * Finds minimum value in array (not necessarily \"first\" one)\n * @memberOf fabric.util.array\n * @param {Array} array Array to iterate over\n * @param {String} byProperty\n * @return {*}\n */\n function min(array, byProperty) {\n return find(array, byProperty, function(value1, value2) {\n return value1 < value2;\n });\n }\n\n /**\n * @private\n */\n function fill(array, value) {\n var k = array.length;\n while (k--) {\n array[k] = value;\n }\n return array;\n }\n\n /**\n * @private\n */\n function find(array, byProperty, condition) {\n if (!array || array.length === 0) {\n return;\n }\n\n var i = array.length - 1,\n result = byProperty ? array[i][byProperty] : array[i];\n if (byProperty) {\n while (i--) {\n if (condition(array[i][byProperty], result)) {\n result = array[i][byProperty];\n }\n }\n }\n else {\n while (i--) {\n if (condition(array[i], result)) {\n result = array[i];\n }\n }\n }\n return result;\n }\n\n /**\n * @namespace fabric.util.array\n */\n fabric.util.array = {\n fill: fill,\n invoke: invoke,\n min: min,\n max: max\n };\n\n})();\n\n\n(function() {\n /**\n * Copies all enumerable properties of one js object to another\n * this does not and cannot compete with generic utils.\n * Does not clone or extend fabric.Object subclasses.\n * This is mostly for internal use and has extra handling for fabricJS objects\n * it skips the canvas and group properties in deep cloning.\n * @memberOf fabric.util.object\n * @param {Object} destination Where to copy to\n * @param {Object} source Where to copy from\n * @param {Boolean} [deep] Whether to extend nested objects\n * @return {Object}\n */\n\n function extend(destination, source, deep) {\n // JScript DontEnum bug is not taken care of\n // the deep clone is for internal use, is not meant to avoid\n // javascript traps or cloning html element or self referenced objects.\n if (deep) {\n if (!fabric.isLikelyNode && source instanceof Element) {\n // avoid cloning deep images, canvases,\n destination = source;\n }\n else if (source instanceof Array) {\n destination = [];\n for (var i = 0, len = source.length; i < len; i++) {\n destination[i] = extend({ }, source[i], deep);\n }\n }\n else if (source && typeof source === 'object') {\n for (var property in source) {\n if (property === 'canvas' || property === 'group') {\n // we do not want to clone this props at all.\n // we want to keep the keys in the copy\n destination[property] = null;\n }\n else if (source.hasOwnProperty(property)) {\n destination[property] = extend({ }, source[property], deep);\n }\n }\n }\n else {\n // this sounds odd for an extend but is ok for recursive use\n destination = source;\n }\n }\n else {\n for (var property in source) {\n destination[property] = source[property];\n }\n }\n return destination;\n }\n\n /**\n * Creates an empty object and copies all enumerable properties of another object to it\n * This method is mostly for internal use, and not intended for duplicating shapes in canvas. \n * @memberOf fabric.util.object\n * @param {Object} object Object to clone\n * @param {Boolean} [deep] Whether to clone nested objects\n * @return {Object}\n */\n\n //TODO: this function return an empty object if you try to clone null\n function clone(object, deep) {\n return extend({ }, object, deep);\n }\n\n /** @namespace fabric.util.object */\n fabric.util.object = {\n extend: extend,\n clone: clone\n };\n fabric.util.object.extend(fabric.util, fabric.Observable);\n})();\n\n\n(function() {\n\n /**\n * Camelizes a string\n * @memberOf fabric.util.string\n * @param {String} string String to camelize\n * @return {String} Camelized version of a string\n */\n function camelize(string) {\n return string.replace(/-+(.)?/g, function(match, character) {\n return character ? character.toUpperCase() : '';\n });\n }\n\n /**\n * Capitalizes a string\n * @memberOf fabric.util.string\n * @param {String} string String to capitalize\n * @param {Boolean} [firstLetterOnly] If true only first letter is capitalized\n * and other letters stay untouched, if false first letter is capitalized\n * and other letters are converted to lowercase.\n * @return {String} Capitalized version of a string\n */\n function capitalize(string, firstLetterOnly) {\n return string.charAt(0).toUpperCase() +\n (firstLetterOnly ? string.slice(1) : string.slice(1).toLowerCase());\n }\n\n /**\n * Escapes XML in a string\n * @memberOf fabric.util.string\n * @param {String} string String to escape\n * @return {String} Escaped version of a string\n */\n function escapeXml(string) {\n return string.replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(//g, '>');\n }\n\n /**\n * Divide a string in the user perceived single units\n * @memberOf fabric.util.string\n * @param {String} textstring String to escape\n * @return {Array} array containing the graphemes\n */\n function graphemeSplit(textstring) {\n var i = 0, chr, graphemes = [];\n for (i = 0, chr; i < textstring.length; i++) {\n if ((chr = getWholeChar(textstring, i)) === false) {\n continue;\n }\n graphemes.push(chr);\n }\n return graphemes;\n }\n\n // taken from mdn in the charAt doc page.\n function getWholeChar(str, i) {\n var code = str.charCodeAt(i);\n\n if (isNaN(code)) {\n return ''; // Position not found\n }\n if (code < 0xD800 || code > 0xDFFF) {\n return str.charAt(i);\n }\n\n // High surrogate (could change last hex to 0xDB7F to treat high private\n // surrogates as single characters)\n if (0xD800 <= code && code <= 0xDBFF) {\n if (str.length <= (i + 1)) {\n throw 'High surrogate without following low surrogate';\n }\n var next = str.charCodeAt(i + 1);\n if (0xDC00 > next || next > 0xDFFF) {\n throw 'High surrogate without following low surrogate';\n }\n return str.charAt(i) + str.charAt(i + 1);\n }\n // Low surrogate (0xDC00 <= code && code <= 0xDFFF)\n if (i === 0) {\n throw 'Low surrogate without preceding high surrogate';\n }\n var prev = str.charCodeAt(i - 1);\n\n // (could change last hex to 0xDB7F to treat high private\n // surrogates as single characters)\n if (0xD800 > prev || prev > 0xDBFF) {\n throw 'Low surrogate without preceding high surrogate';\n }\n // We can pass over low surrogates now as the second component\n // in a pair which we have already processed\n return false;\n }\n\n\n /**\n * String utilities\n * @namespace fabric.util.string\n */\n fabric.util.string = {\n camelize: camelize,\n capitalize: capitalize,\n escapeXml: escapeXml,\n graphemeSplit: graphemeSplit\n };\n})();\n\n\n(function() {\n\n var slice = Array.prototype.slice, emptyFunction = function() { },\n\n IS_DONTENUM_BUGGY = (function() {\n for (var p in { toString: 1 }) {\n if (p === 'toString') {\n return false;\n }\n }\n return true;\n })(),\n\n /** @ignore */\n addMethods = function(klass, source, parent) {\n for (var property in source) {\n\n if (property in klass.prototype &&\n typeof klass.prototype[property] === 'function' &&\n (source[property] + '').indexOf('callSuper') > -1) {\n\n klass.prototype[property] = (function(property) {\n return function() {\n\n var superclass = this.constructor.superclass;\n this.constructor.superclass = parent;\n var returnValue = source[property].apply(this, arguments);\n this.constructor.superclass = superclass;\n\n if (property !== 'initialize') {\n return returnValue;\n }\n };\n })(property);\n }\n else {\n klass.prototype[property] = source[property];\n }\n\n if (IS_DONTENUM_BUGGY) {\n if (source.toString !== Object.prototype.toString) {\n klass.prototype.toString = source.toString;\n }\n if (source.valueOf !== Object.prototype.valueOf) {\n klass.prototype.valueOf = source.valueOf;\n }\n }\n }\n };\n\n function Subclass() { }\n\n function callSuper(methodName) {\n var parentMethod = null,\n _this = this;\n\n // climb prototype chain to find method not equal to callee's method\n while (_this.constructor.superclass) {\n var superClassMethod = _this.constructor.superclass.prototype[methodName];\n if (_this[methodName] !== superClassMethod) {\n parentMethod = superClassMethod;\n break;\n }\n // eslint-disable-next-line\n _this = _this.constructor.superclass.prototype;\n }\n\n if (!parentMethod) {\n return console.log('tried to callSuper ' + methodName + ', method not found in prototype chain', this);\n }\n\n return (arguments.length > 1)\n ? parentMethod.apply(this, slice.call(arguments, 1))\n : parentMethod.call(this);\n }\n\n /**\n * Helper for creation of \"classes\".\n * @memberOf fabric.util\n * @param {Function} [parent] optional \"Class\" to inherit from\n * @param {Object} [properties] Properties shared by all instances of this class\n * (be careful modifying objects defined here as this would affect all instances)\n */\n function createClass() {\n var parent = null,\n properties = slice.call(arguments, 0);\n\n if (typeof properties[0] === 'function') {\n parent = properties.shift();\n }\n function klass() {\n this.initialize.apply(this, arguments);\n }\n\n klass.superclass = parent;\n klass.subclasses = [];\n\n if (parent) {\n Subclass.prototype = parent.prototype;\n klass.prototype = new Subclass();\n parent.subclasses.push(klass);\n }\n for (var i = 0, length = properties.length; i < length; i++) {\n addMethods(klass, properties[i], parent);\n }\n if (!klass.prototype.initialize) {\n klass.prototype.initialize = emptyFunction;\n }\n klass.prototype.constructor = klass;\n klass.prototype.callSuper = callSuper;\n return klass;\n }\n\n fabric.util.createClass = createClass;\n})();\n\n\n(function () {\n // since ie11 can use addEventListener but they do not support options, i need to check\n var couldUseAttachEvent = !!fabric.document.createElement('div').attachEvent,\n touchEvents = ['touchstart', 'touchmove', 'touchend'];\n /**\n * Adds an event listener to an element\n * @function\n * @memberOf fabric.util\n * @param {HTMLElement} element\n * @param {String} eventName\n * @param {Function} handler\n */\n fabric.util.addListener = function(element, eventName, handler, options) {\n element && element.addEventListener(eventName, handler, couldUseAttachEvent ? false : options);\n };\n\n /**\n * Removes an event listener from an element\n * @function\n * @memberOf fabric.util\n * @param {HTMLElement} element\n * @param {String} eventName\n * @param {Function} handler\n */\n fabric.util.removeListener = function(element, eventName, handler, options) {\n element && element.removeEventListener(eventName, handler, couldUseAttachEvent ? false : options);\n };\n\n function getTouchInfo(event) {\n var touchProp = event.changedTouches;\n if (touchProp && touchProp[0]) {\n return touchProp[0];\n }\n return event;\n }\n\n fabric.util.getPointer = function(event) {\n var element = event.target,\n scroll = fabric.util.getScrollLeftTop(element),\n _evt = getTouchInfo(event);\n return {\n x: _evt.clientX + scroll.left,\n y: _evt.clientY + scroll.top\n };\n };\n\n fabric.util.isTouchEvent = function(event) {\n return touchEvents.indexOf(event.type) > -1 || event.pointerType === 'touch';\n };\n})();\n\n\n(function () {\n\n /**\n * Cross-browser wrapper for setting element's style\n * @memberOf fabric.util\n * @param {HTMLElement} element\n * @param {Object} styles\n * @return {HTMLElement} Element that was passed as a first argument\n */\n function setStyle(element, styles) {\n var elementStyle = element.style;\n if (!elementStyle) {\n return element;\n }\n if (typeof styles === 'string') {\n element.style.cssText += ';' + styles;\n return styles.indexOf('opacity') > -1\n ? setOpacity(element, styles.match(/opacity:\\s*(\\d?\\.?\\d*)/)[1])\n : element;\n }\n for (var property in styles) {\n if (property === 'opacity') {\n setOpacity(element, styles[property]);\n }\n else {\n var normalizedProperty = (property === 'float' || property === 'cssFloat')\n ? (typeof elementStyle.styleFloat === 'undefined' ? 'cssFloat' : 'styleFloat')\n : property;\n elementStyle[normalizedProperty] = styles[property];\n }\n }\n return element;\n }\n\n var parseEl = fabric.document.createElement('div'),\n supportsOpacity = typeof parseEl.style.opacity === 'string',\n supportsFilters = typeof parseEl.style.filter === 'string',\n reOpacity = /alpha\\s*\\(\\s*opacity\\s*=\\s*([^\\)]+)\\)/,\n\n /** @ignore */\n setOpacity = function (element) { return element; };\n\n if (supportsOpacity) {\n /** @ignore */\n setOpacity = function(element, value) {\n element.style.opacity = value;\n return element;\n };\n }\n else if (supportsFilters) {\n /** @ignore */\n setOpacity = function(element, value) {\n var es = element.style;\n if (element.currentStyle && !element.currentStyle.hasLayout) {\n es.zoom = 1;\n }\n if (reOpacity.test(es.filter)) {\n value = value >= 0.9999 ? '' : ('alpha(opacity=' + (value * 100) + ')');\n es.filter = es.filter.replace(reOpacity, value);\n }\n else {\n es.filter += ' alpha(opacity=' + (value * 100) + ')';\n }\n return element;\n };\n }\n\n fabric.util.setStyle = setStyle;\n\n})();\n\n\n(function() {\n\n var _slice = Array.prototype.slice;\n\n /**\n * Takes id and returns an element with that id (if one exists in a document)\n * @memberOf fabric.util\n * @param {String|HTMLElement} id\n * @return {HTMLElement|null}\n */\n function getById(id) {\n return typeof id === 'string' ? fabric.document.getElementById(id) : id;\n }\n\n var sliceCanConvertNodelists,\n /**\n * Converts an array-like object (e.g. arguments or NodeList) to an array\n * @memberOf fabric.util\n * @param {Object} arrayLike\n * @return {Array}\n */\n toArray = function(arrayLike) {\n return _slice.call(arrayLike, 0);\n };\n\n try {\n sliceCanConvertNodelists = toArray(fabric.document.childNodes) instanceof Array;\n }\n catch (err) { }\n\n if (!sliceCanConvertNodelists) {\n toArray = function(arrayLike) {\n var arr = new Array(arrayLike.length), i = arrayLike.length;\n while (i--) {\n arr[i] = arrayLike[i];\n }\n return arr;\n };\n }\n\n /**\n * Creates specified element with specified attributes\n * @memberOf fabric.util\n * @param {String} tagName Type of an element to create\n * @param {Object} [attributes] Attributes to set on an element\n * @return {HTMLElement} Newly created element\n */\n function makeElement(tagName, attributes) {\n var el = fabric.document.createElement(tagName);\n for (var prop in attributes) {\n if (prop === 'class') {\n el.className = attributes[prop];\n }\n else if (prop === 'for') {\n el.htmlFor = attributes[prop];\n }\n else {\n el.setAttribute(prop, attributes[prop]);\n }\n }\n return el;\n }\n\n /**\n * Adds class to an element\n * @memberOf fabric.util\n * @param {HTMLElement} element Element to add class to\n * @param {String} className Class to add to an element\n */\n function addClass(element, className) {\n if (element && (' ' + element.className + ' ').indexOf(' ' + className + ' ') === -1) {\n element.className += (element.className ? ' ' : '') + className;\n }\n }\n\n /**\n * Wraps element with another element\n * @memberOf fabric.util\n * @param {HTMLElement} element Element to wrap\n * @param {HTMLElement|String} wrapper Element to wrap with\n * @param {Object} [attributes] Attributes to set on a wrapper\n * @return {HTMLElement} wrapper\n */\n function wrapElement(element, wrapper, attributes) {\n if (typeof wrapper === 'string') {\n wrapper = makeElement(wrapper, attributes);\n }\n if (element.parentNode) {\n element.parentNode.replaceChild(wrapper, element);\n }\n wrapper.appendChild(element);\n return wrapper;\n }\n\n /**\n * Returns element scroll offsets\n * @memberOf fabric.util\n * @param {HTMLElement} element Element to operate on\n * @return {Object} Object with left/top values\n */\n function getScrollLeftTop(element) {\n\n var left = 0,\n top = 0,\n docElement = fabric.document.documentElement,\n body = fabric.document.body || {\n scrollLeft: 0, scrollTop: 0\n };\n\n // While loop checks (and then sets element to) .parentNode OR .host\n // to account for ShadowDOM. We still want to traverse up out of ShadowDOM,\n // but the .parentNode of a root ShadowDOM node will always be null, instead\n // it should be accessed through .host. See http://stackoverflow.com/a/24765528/4383938\n while (element && (element.parentNode || element.host)) {\n\n // Set element to element parent, or 'host' in case of ShadowDOM\n element = element.parentNode || element.host;\n\n if (element === fabric.document) {\n left = body.scrollLeft || docElement.scrollLeft || 0;\n top = body.scrollTop || docElement.scrollTop || 0;\n }\n else {\n left += element.scrollLeft || 0;\n top += element.scrollTop || 0;\n }\n\n if (element.nodeType === 1 && element.style.position === 'fixed') {\n break;\n }\n }\n\n return { left: left, top: top };\n }\n\n /**\n * Returns offset for a given element\n * @function\n * @memberOf fabric.util\n * @param {HTMLElement} element Element to get offset for\n * @return {Object} Object with \"left\" and \"top\" properties\n */\n function getElementOffset(element) {\n var docElem,\n doc = element && element.ownerDocument,\n box = { left: 0, top: 0 },\n offset = { left: 0, top: 0 },\n scrollLeftTop,\n offsetAttributes = {\n borderLeftWidth: 'left',\n borderTopWidth: 'top',\n paddingLeft: 'left',\n paddingTop: 'top'\n };\n\n if (!doc) {\n return offset;\n }\n\n for (var attr in offsetAttributes) {\n offset[offsetAttributes[attr]] += parseInt(getElementStyle(element, attr), 10) || 0;\n }\n\n docElem = doc.documentElement;\n if ( typeof element.getBoundingClientRect !== 'undefined' ) {\n box = element.getBoundingClientRect();\n }\n\n scrollLeftTop = getScrollLeftTop(element);\n\n return {\n left: box.left + scrollLeftTop.left - (docElem.clientLeft || 0) + offset.left,\n top: box.top + scrollLeftTop.top - (docElem.clientTop || 0) + offset.top\n };\n }\n\n /**\n * Returns style attribute value of a given element\n * @memberOf fabric.util\n * @param {HTMLElement} element Element to get style attribute for\n * @param {String} attr Style attribute to get for element\n * @return {String} Style attribute value of the given element.\n */\n var getElementStyle;\n if (fabric.document.defaultView && fabric.document.defaultView.getComputedStyle) {\n getElementStyle = function(element, attr) {\n var style = fabric.document.defaultView.getComputedStyle(element, null);\n return style ? style[attr] : undefined;\n };\n }\n else {\n getElementStyle = function(element, attr) {\n var value = element.style[attr];\n if (!value && element.currentStyle) {\n value = element.currentStyle[attr];\n }\n return value;\n };\n }\n\n (function () {\n var style = fabric.document.documentElement.style,\n selectProp = 'userSelect' in style\n ? 'userSelect'\n : 'MozUserSelect' in style\n ? 'MozUserSelect'\n : 'WebkitUserSelect' in style\n ? 'WebkitUserSelect'\n : 'KhtmlUserSelect' in style\n ? 'KhtmlUserSelect'\n : '';\n\n /**\n * Makes element unselectable\n * @memberOf fabric.util\n * @param {HTMLElement} element Element to make unselectable\n * @return {HTMLElement} Element that was passed in\n */\n function makeElementUnselectable(element) {\n if (typeof element.onselectstart !== 'undefined') {\n element.onselectstart = fabric.util.falseFunction;\n }\n if (selectProp) {\n element.style[selectProp] = 'none';\n }\n else if (typeof element.unselectable === 'string') {\n element.unselectable = 'on';\n }\n return element;\n }\n\n /**\n * Makes element selectable\n * @memberOf fabric.util\n * @param {HTMLElement} element Element to make selectable\n * @return {HTMLElement} Element that was passed in\n */\n function makeElementSelectable(element) {\n if (typeof element.onselectstart !== 'undefined') {\n element.onselectstart = null;\n }\n if (selectProp) {\n element.style[selectProp] = '';\n }\n else if (typeof element.unselectable === 'string') {\n element.unselectable = '';\n }\n return element;\n }\n\n fabric.util.makeElementUnselectable = makeElementUnselectable;\n fabric.util.makeElementSelectable = makeElementSelectable;\n })();\n\n function getNodeCanvas(element) {\n var impl = fabric.jsdomImplForWrapper(element);\n return impl._canvas || impl._image;\n };\n\n function cleanUpJsdomNode(element) {\n if (!fabric.isLikelyNode) {\n return;\n }\n var impl = fabric.jsdomImplForWrapper(element);\n if (impl) {\n impl._image = null;\n impl._canvas = null;\n // unsure if necessary\n impl._currentSrc = null;\n impl._attributes = null;\n impl._classList = null;\n }\n }\n\n function setImageSmoothing(ctx, value) {\n ctx.imageSmoothingEnabled = ctx.imageSmoothingEnabled || ctx.webkitImageSmoothingEnabled\n || ctx.mozImageSmoothingEnabled || ctx.msImageSmoothingEnabled || ctx.oImageSmoothingEnabled;\n ctx.imageSmoothingEnabled = value;\n }\n\n /**\n * setImageSmoothing sets the context imageSmoothingEnabled property.\n * Used by canvas and by ImageObject.\n * @memberOf fabric.util\n * @since 4.0.0\n * @param {HTMLRenderingContext2D} ctx to set on\n * @param {Boolean} value true or false\n */\n fabric.util.setImageSmoothing = setImageSmoothing;\n fabric.util.getById = getById;\n fabric.util.toArray = toArray;\n fabric.util.addClass = addClass;\n fabric.util.makeElement = makeElement;\n fabric.util.wrapElement = wrapElement;\n fabric.util.getScrollLeftTop = getScrollLeftTop;\n fabric.util.getElementOffset = getElementOffset;\n fabric.util.getNodeCanvas = getNodeCanvas;\n fabric.util.cleanUpJsdomNode = cleanUpJsdomNode;\n\n})();\n\n\n(function() {\n\n function addParamToUrl(url, param) {\n return url + (/\\?/.test(url) ? '&' : '?') + param;\n }\n\n function emptyFn() { }\n\n /**\n * Cross-browser abstraction for sending XMLHttpRequest\n * @memberOf fabric.util\n * @param {String} url URL to send XMLHttpRequest to\n * @param {Object} [options] Options object\n * @param {String} [options.method=\"GET\"]\n * @param {String} [options.parameters] parameters to append to url in GET or in body\n * @param {String} [options.body] body to send with POST or PUT request\n * @param {Function} options.onComplete Callback to invoke when request is completed\n * @return {XMLHttpRequest} request\n */\n function request(url, options) {\n options || (options = { });\n\n var method = options.method ? options.method.toUpperCase() : 'GET',\n onComplete = options.onComplete || function() { },\n xhr = new fabric.window.XMLHttpRequest(),\n body = options.body || options.parameters;\n\n /** @ignore */\n xhr.onreadystatechange = function() {\n if (xhr.readyState === 4) {\n onComplete(xhr);\n xhr.onreadystatechange = emptyFn;\n }\n };\n\n if (method === 'GET') {\n body = null;\n if (typeof options.parameters === 'string') {\n url = addParamToUrl(url, options.parameters);\n }\n }\n\n xhr.open(method, url, true);\n\n if (method === 'POST' || method === 'PUT') {\n xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');\n }\n\n xhr.send(body);\n return xhr;\n }\n\n fabric.util.request = request;\n})();\n\n\n/**\n * Wrapper around `console.log` (when available)\n * @param {*} [values] Values to log\n */\nfabric.log = console.log;\n\n/**\n * Wrapper around `console.warn` (when available)\n * @param {*} [values] Values to log as a warning\n */\nfabric.warn = console.warn;\n\n\n(function () {\n\n var extend = fabric.util.object.extend,\n clone = fabric.util.object.clone;\n\n /**\n * @typedef {Object} AnimationOptions\n * Animation of a value or list of values.\n * When using lists, think of something like this:\n * fabric.util.animate({\n * startValue: [1, 2, 3],\n * endValue: [2, 4, 6],\n * onChange: function([a, b, c]) {\n * canvas.zoomToPoint({x: b, y: c}, a)\n * canvas.renderAll()\n * }\n * });\n * @example\n * @property {Function} [onChange] Callback; invoked on every value change\n * @property {Function} [onComplete] Callback; invoked when value change is completed\n * @example\n * // Note: startValue, endValue, and byValue must match the type\n * var animationOptions = { startValue: 0, endValue: 1, byValue: 0.25 }\n * var animationOptions = { startValue: [0, 1], endValue: [1, 2], byValue: [0.25, 0.25] }\n * @property {number | number[]} [startValue=0] Starting value\n * @property {number | number[]} [endValue=100] Ending value\n * @property {number | number[]} [byValue=100] Value to modify the property by\n * @property {Function} [easing] Easing function\n * @property {Number} [duration=500] Duration of change (in ms)\n * @property {Function} [abort] Additional function with logic. If returns true, animation aborts.\n *\n * @typedef {() => void} CancelFunction\n *\n * @typedef {Object} AnimationCurrentState\n * @property {number | number[]} currentValue value in range [`startValue`, `endValue`]\n * @property {number} completionRate value in range [0, 1]\n * @property {number} durationRate value in range [0, 1]\n *\n * @typedef {(AnimationOptions & AnimationCurrentState & { cancel: CancelFunction }} AnimationContext\n */\n\n /**\n * Array holding all running animations\n * @memberof fabric\n * @type {AnimationContext[]}\n */\n var RUNNING_ANIMATIONS = [];\n fabric.util.object.extend(RUNNING_ANIMATIONS, {\n\n /**\n * cancel all running animations at the next requestAnimFrame\n * @returns {AnimationContext[]}\n */\n cancelAll: function () {\n var animations = this.splice(0);\n animations.forEach(function (animation) {\n animation.cancel();\n });\n return animations;\n },\n\n /**\n * cancel all running animations attached to canvas at the next requestAnimFrame\n * @param {fabric.Canvas} canvas\n * @returns {AnimationContext[]}\n */\n cancelByCanvas: function (canvas) {\n if (!canvas) {\n return [];\n }\n var cancelled = this.filter(function (animation) {\n return typeof animation.target === 'object' && animation.target.canvas === canvas;\n });\n cancelled.forEach(function (animation) {\n animation.cancel();\n });\n return cancelled;\n },\n\n /**\n * cancel all running animations for target at the next requestAnimFrame\n * @param {*} target\n * @returns {AnimationContext[]}\n */\n cancelByTarget: function (target) {\n var cancelled = this.findAnimationsByTarget(target);\n cancelled.forEach(function (animation) {\n animation.cancel();\n });\n return cancelled;\n },\n\n /**\n *\n * @param {CancelFunction} cancelFunc the function returned by animate\n * @returns {number}\n */\n findAnimationIndex: function (cancelFunc) {\n return this.indexOf(this.findAnimation(cancelFunc));\n },\n\n /**\n *\n * @param {CancelFunction} cancelFunc the function returned by animate\n * @returns {AnimationContext | undefined} animation's options object\n */\n findAnimation: function (cancelFunc) {\n return this.find(function (animation) {\n return animation.cancel === cancelFunc;\n });\n },\n\n /**\n *\n * @param {*} target the object that is assigned to the target property of the animation context\n * @returns {AnimationContext[]} array of animation options object associated with target\n */\n findAnimationsByTarget: function (target) {\n if (!target) {\n return [];\n }\n return this.filter(function (animation) {\n return animation.target === target;\n });\n }\n });\n\n function noop() {\n return false;\n }\n\n function defaultEasing(t, b, c, d) {\n return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;\n }\n\n /**\n * Changes value from one to another within certain period of time, invoking callbacks as value is being changed.\n * @memberOf fabric.util\n * @param {AnimationOptions} [options] Animation options\n * @example\n * // Note: startValue, endValue, and byValue must match the type\n * fabric.util.animate({ startValue: 0, endValue: 1, byValue: 0.25 })\n * fabric.util.animate({ startValue: [0, 1], endValue: [1, 2], byValue: [0.25, 0.25] })\n * @returns {CancelFunction} cancel function\n */\n function animate(options) {\n options || (options = {});\n var cancel = false,\n context,\n removeFromRegistry = function () {\n var index = fabric.runningAnimations.indexOf(context);\n return index > -1 && fabric.runningAnimations.splice(index, 1)[0];\n };\n\n context = extend(clone(options), {\n cancel: function () {\n cancel = true;\n return removeFromRegistry();\n },\n currentValue: 'startValue' in options ? options.startValue : 0,\n completionRate: 0,\n durationRate: 0\n });\n fabric.runningAnimations.push(context);\n\n requestAnimFrame(function(timestamp) {\n var start = timestamp || +new Date(),\n duration = options.duration || 500,\n finish = start + duration, time,\n onChange = options.onChange || noop,\n abort = options.abort || noop,\n onComplete = options.onComplete || noop,\n easing = options.easing || defaultEasing,\n isMany = 'startValue' in options ? options.startValue.length > 0 : false,\n startValue = 'startValue' in options ? options.startValue : 0,\n endValue = 'endValue' in options ? options.endValue : 100,\n byValue = options.byValue || (isMany ? startValue.map(function(value, i) {\n return endValue[i] - startValue[i];\n }) : endValue - startValue);\n\n options.onStart && options.onStart();\n\n (function tick(ticktime) {\n time = ticktime || +new Date();\n var currentTime = time > finish ? duration : (time - start),\n timePerc = currentTime / duration,\n current = isMany ? startValue.map(function(_value, i) {\n return easing(currentTime, startValue[i], byValue[i], duration);\n }) : easing(currentTime, startValue, byValue, duration),\n valuePerc = isMany ? Math.abs((current[0] - startValue[0]) / byValue[0])\n : Math.abs((current - startValue) / byValue);\n // update context\n context.currentValue = isMany ? current.slice() : current;\n context.completionRate = valuePerc;\n context.durationRate = timePerc;\n if (cancel) {\n return;\n }\n if (abort(current, valuePerc, timePerc)) {\n removeFromRegistry();\n return;\n }\n if (time > finish) {\n // update context\n context.currentValue = isMany ? endValue.slice() : endValue;\n context.completionRate = 1;\n context.durationRate = 1;\n // execute callbacks\n onChange(isMany ? endValue.slice() : endValue, 1, 1);\n onComplete(endValue, 1, 1);\n removeFromRegistry();\n return;\n }\n else {\n onChange(current, valuePerc, timePerc);\n requestAnimFrame(tick);\n }\n })(start);\n });\n\n return context.cancel;\n }\n\n var _requestAnimFrame = fabric.window.requestAnimationFrame ||\n fabric.window.webkitRequestAnimationFrame ||\n fabric.window.mozRequestAnimationFrame ||\n fabric.window.oRequestAnimationFrame ||\n fabric.window.msRequestAnimationFrame ||\n function(callback) {\n return fabric.window.setTimeout(callback, 1000 / 60);\n };\n\n var _cancelAnimFrame = fabric.window.cancelAnimationFrame || fabric.window.clearTimeout;\n\n /**\n * requestAnimationFrame polyfill based on http://paulirish.com/2011/requestanimationframe-for-smart-animating/\n * In order to get a precise start time, `requestAnimFrame` should be called as an entry into the method\n * @memberOf fabric.util\n * @param {Function} callback Callback to invoke\n * @param {DOMElement} element optional Element to associate with animation\n */\n function requestAnimFrame() {\n return _requestAnimFrame.apply(fabric.window, arguments);\n }\n\n function cancelAnimFrame() {\n return _cancelAnimFrame.apply(fabric.window, arguments);\n }\n\n fabric.util.animate = animate;\n fabric.util.requestAnimFrame = requestAnimFrame;\n fabric.util.cancelAnimFrame = cancelAnimFrame;\n fabric.runningAnimations = RUNNING_ANIMATIONS;\n})();\n\n\n(function() {\n // Calculate an in-between color. Returns a \"rgba()\" string.\n // Credit: Edwin Martin \n // http://www.bitstorm.org/jquery/color-animation/jquery.animate-colors.js\n function calculateColor(begin, end, pos) {\n var color = 'rgba('\n + parseInt((begin[0] + pos * (end[0] - begin[0])), 10) + ','\n + parseInt((begin[1] + pos * (end[1] - begin[1])), 10) + ','\n + parseInt((begin[2] + pos * (end[2] - begin[2])), 10);\n\n color += ',' + (begin && end ? parseFloat(begin[3] + pos * (end[3] - begin[3])) : 1);\n color += ')';\n return color;\n }\n\n /**\n * Changes the color from one to another within certain period of time, invoking callbacks as value is being changed.\n * @memberOf fabric.util\n * @param {String} fromColor The starting color in hex or rgb(a) format.\n * @param {String} toColor The starting color in hex or rgb(a) format.\n * @param {Number} [duration] Duration of change (in ms).\n * @param {Object} [options] Animation options\n * @param {Function} [options.onChange] Callback; invoked on every value change\n * @param {Function} [options.onComplete] Callback; invoked when value change is completed\n * @param {Function} [options.colorEasing] Easing function. Note that this function only take two arguments (currentTime, duration). Thus the regular animation easing functions cannot be used.\n * @param {Function} [options.abort] Additional function with logic. If returns true, onComplete is called.\n * @returns {Function} abort function\n */\n function animateColor(fromColor, toColor, duration, options) {\n var startColor = new fabric.Color(fromColor).getSource(),\n endColor = new fabric.Color(toColor).getSource(),\n originalOnComplete = options.onComplete,\n originalOnChange = options.onChange;\n options = options || {};\n\n return fabric.util.animate(fabric.util.object.extend(options, {\n duration: duration || 500,\n startValue: startColor,\n endValue: endColor,\n byValue: endColor,\n easing: function (currentTime, startValue, byValue, duration) {\n var posValue = options.colorEasing\n ? options.colorEasing(currentTime, duration)\n : 1 - Math.cos(currentTime / duration * (Math.PI / 2));\n return calculateColor(startValue, byValue, posValue);\n },\n // has to take in account for color restoring;\n onComplete: function(current, valuePerc, timePerc) {\n if (originalOnComplete) {\n return originalOnComplete(\n calculateColor(endColor, endColor, 0),\n valuePerc,\n timePerc\n );\n }\n },\n onChange: function(current, valuePerc, timePerc) {\n if (originalOnChange) {\n if (Array.isArray(current)) {\n return originalOnChange(\n calculateColor(current, current, 0),\n valuePerc,\n timePerc\n );\n }\n originalOnChange(current, valuePerc, timePerc);\n }\n }\n }));\n }\n\n fabric.util.animateColor = animateColor;\n\n})();\n\n\n(function() {\n\n function normalize(a, c, p, s) {\n if (a < Math.abs(c)) {\n a = c;\n s = p / 4;\n }\n else {\n //handle the 0/0 case:\n if (c === 0 && a === 0) {\n s = p / (2 * Math.PI) * Math.asin(1);\n }\n else {\n s = p / (2 * Math.PI) * Math.asin(c / a);\n }\n }\n return { a: a, c: c, p: p, s: s };\n }\n\n function elastic(opts, t, d) {\n return opts.a *\n Math.pow(2, 10 * (t -= 1)) *\n Math.sin( (t * d - opts.s) * (2 * Math.PI) / opts.p );\n }\n\n /**\n * Cubic easing out\n * @memberOf fabric.util.ease\n */\n function easeOutCubic(t, b, c, d) {\n return c * ((t = t / d - 1) * t * t + 1) + b;\n }\n\n /**\n * Cubic easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutCubic(t, b, c, d) {\n t /= d / 2;\n if (t < 1) {\n return c / 2 * t * t * t + b;\n }\n return c / 2 * ((t -= 2) * t * t + 2) + b;\n }\n\n /**\n * Quartic easing in\n * @memberOf fabric.util.ease\n */\n function easeInQuart(t, b, c, d) {\n return c * (t /= d) * t * t * t + b;\n }\n\n /**\n * Quartic easing out\n * @memberOf fabric.util.ease\n */\n function easeOutQuart(t, b, c, d) {\n return -c * ((t = t / d - 1) * t * t * t - 1) + b;\n }\n\n /**\n * Quartic easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutQuart(t, b, c, d) {\n t /= d / 2;\n if (t < 1) {\n return c / 2 * t * t * t * t + b;\n }\n return -c / 2 * ((t -= 2) * t * t * t - 2) + b;\n }\n\n /**\n * Quintic easing in\n * @memberOf fabric.util.ease\n */\n function easeInQuint(t, b, c, d) {\n return c * (t /= d) * t * t * t * t + b;\n }\n\n /**\n * Quintic easing out\n * @memberOf fabric.util.ease\n */\n function easeOutQuint(t, b, c, d) {\n return c * ((t = t / d - 1) * t * t * t * t + 1) + b;\n }\n\n /**\n * Quintic easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutQuint(t, b, c, d) {\n t /= d / 2;\n if (t < 1) {\n return c / 2 * t * t * t * t * t + b;\n }\n return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;\n }\n\n /**\n * Sinusoidal easing in\n * @memberOf fabric.util.ease\n */\n function easeInSine(t, b, c, d) {\n return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;\n }\n\n /**\n * Sinusoidal easing out\n * @memberOf fabric.util.ease\n */\n function easeOutSine(t, b, c, d) {\n return c * Math.sin(t / d * (Math.PI / 2)) + b;\n }\n\n /**\n * Sinusoidal easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutSine(t, b, c, d) {\n return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;\n }\n\n /**\n * Exponential easing in\n * @memberOf fabric.util.ease\n */\n function easeInExpo(t, b, c, d) {\n return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;\n }\n\n /**\n * Exponential easing out\n * @memberOf fabric.util.ease\n */\n function easeOutExpo(t, b, c, d) {\n return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;\n }\n\n /**\n * Exponential easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutExpo(t, b, c, d) {\n if (t === 0) {\n return b;\n }\n if (t === d) {\n return b + c;\n }\n t /= d / 2;\n if (t < 1) {\n return c / 2 * Math.pow(2, 10 * (t - 1)) + b;\n }\n return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;\n }\n\n /**\n * Circular easing in\n * @memberOf fabric.util.ease\n */\n function easeInCirc(t, b, c, d) {\n return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;\n }\n\n /**\n * Circular easing out\n * @memberOf fabric.util.ease\n */\n function easeOutCirc(t, b, c, d) {\n return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;\n }\n\n /**\n * Circular easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutCirc(t, b, c, d) {\n t /= d / 2;\n if (t < 1) {\n return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;\n }\n return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;\n }\n\n /**\n * Elastic easing in\n * @memberOf fabric.util.ease\n */\n function easeInElastic(t, b, c, d) {\n var s = 1.70158, p = 0, a = c;\n if (t === 0) {\n return b;\n }\n t /= d;\n if (t === 1) {\n return b + c;\n }\n if (!p) {\n p = d * 0.3;\n }\n var opts = normalize(a, c, p, s);\n return -elastic(opts, t, d) + b;\n }\n\n /**\n * Elastic easing out\n * @memberOf fabric.util.ease\n */\n function easeOutElastic(t, b, c, d) {\n var s = 1.70158, p = 0, a = c;\n if (t === 0) {\n return b;\n }\n t /= d;\n if (t === 1) {\n return b + c;\n }\n if (!p) {\n p = d * 0.3;\n }\n var opts = normalize(a, c, p, s);\n return opts.a * Math.pow(2, -10 * t) * Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) + opts.c + b;\n }\n\n /**\n * Elastic easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutElastic(t, b, c, d) {\n var s = 1.70158, p = 0, a = c;\n if (t === 0) {\n return b;\n }\n t /= d / 2;\n if (t === 2) {\n return b + c;\n }\n if (!p) {\n p = d * (0.3 * 1.5);\n }\n var opts = normalize(a, c, p, s);\n if (t < 1) {\n return -0.5 * elastic(opts, t, d) + b;\n }\n return opts.a * Math.pow(2, -10 * (t -= 1)) *\n Math.sin((t * d - opts.s) * (2 * Math.PI) / opts.p ) * 0.5 + opts.c + b;\n }\n\n /**\n * Backwards easing in\n * @memberOf fabric.util.ease\n */\n function easeInBack(t, b, c, d, s) {\n if (s === undefined) {\n s = 1.70158;\n }\n return c * (t /= d) * t * ((s + 1) * t - s) + b;\n }\n\n /**\n * Backwards easing out\n * @memberOf fabric.util.ease\n */\n function easeOutBack(t, b, c, d, s) {\n if (s === undefined) {\n s = 1.70158;\n }\n return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;\n }\n\n /**\n * Backwards easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutBack(t, b, c, d, s) {\n if (s === undefined) {\n s = 1.70158;\n }\n t /= d / 2;\n if (t < 1) {\n return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;\n }\n return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;\n }\n\n /**\n * Bouncing easing in\n * @memberOf fabric.util.ease\n */\n function easeInBounce(t, b, c, d) {\n return c - easeOutBounce (d - t, 0, c, d) + b;\n }\n\n /**\n * Bouncing easing out\n * @memberOf fabric.util.ease\n */\n function easeOutBounce(t, b, c, d) {\n if ((t /= d) < (1 / 2.75)) {\n return c * (7.5625 * t * t) + b;\n }\n else if (t < (2 / 2.75)) {\n return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;\n }\n else if (t < (2.5 / 2.75)) {\n return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;\n }\n else {\n return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;\n }\n }\n\n /**\n * Bouncing easing in and out\n * @memberOf fabric.util.ease\n */\n function easeInOutBounce(t, b, c, d) {\n if (t < d / 2) {\n return easeInBounce (t * 2, 0, c, d) * 0.5 + b;\n }\n return easeOutBounce(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;\n }\n\n /**\n * Easing functions\n * See Easing Equations by Robert Penner\n * @namespace fabric.util.ease\n */\n fabric.util.ease = {\n\n /**\n * Quadratic easing in\n * @memberOf fabric.util.ease\n */\n easeInQuad: function(t, b, c, d) {\n return c * (t /= d) * t + b;\n },\n\n /**\n * Quadratic easing out\n * @memberOf fabric.util.ease\n */\n easeOutQuad: function(t, b, c, d) {\n return -c * (t /= d) * (t - 2) + b;\n },\n\n /**\n * Quadratic easing in and out\n * @memberOf fabric.util.ease\n */\n easeInOutQuad: function(t, b, c, d) {\n t /= (d / 2);\n if (t < 1) {\n return c / 2 * t * t + b;\n }\n return -c / 2 * ((--t) * (t - 2) - 1) + b;\n },\n\n /**\n * Cubic easing in\n * @memberOf fabric.util.ease\n */\n easeInCubic: function(t, b, c, d) {\n return c * (t /= d) * t * t + b;\n },\n\n easeOutCubic: easeOutCubic,\n easeInOutCubic: easeInOutCubic,\n easeInQuart: easeInQuart,\n easeOutQuart: easeOutQuart,\n easeInOutQuart: easeInOutQuart,\n easeInQuint: easeInQuint,\n easeOutQuint: easeOutQuint,\n easeInOutQuint: easeInOutQuint,\n easeInSine: easeInSine,\n easeOutSine: easeOutSine,\n easeInOutSine: easeInOutSine,\n easeInExpo: easeInExpo,\n easeOutExpo: easeOutExpo,\n easeInOutExpo: easeInOutExpo,\n easeInCirc: easeInCirc,\n easeOutCirc: easeOutCirc,\n easeInOutCirc: easeInOutCirc,\n easeInElastic: easeInElastic,\n easeOutElastic: easeOutElastic,\n easeInOutElastic: easeInOutElastic,\n easeInBack: easeInBack,\n easeOutBack: easeOutBack,\n easeInOutBack: easeInOutBack,\n easeInBounce: easeInBounce,\n easeOutBounce: easeOutBounce,\n easeInOutBounce: easeInOutBounce\n };\n\n})();\n\n\n(function(global) {\n\n 'use strict';\n\n /**\n * @name fabric\n * @namespace\n */\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend,\n clone = fabric.util.object.clone,\n toFixed = fabric.util.toFixed,\n parseUnit = fabric.util.parseUnit,\n multiplyTransformMatrices = fabric.util.multiplyTransformMatrices,\n\n svgValidTagNames = ['path', 'circle', 'polygon', 'polyline', 'ellipse', 'rect', 'line',\n 'image', 'text'],\n svgViewBoxElements = ['symbol', 'image', 'marker', 'pattern', 'view', 'svg'],\n svgInvalidAncestors = ['pattern', 'defs', 'symbol', 'metadata', 'clipPath', 'mask', 'desc'],\n svgValidParents = ['symbol', 'g', 'a', 'svg', 'clipPath', 'defs'],\n\n attributesMap = {\n cx: 'left',\n x: 'left',\n r: 'radius',\n cy: 'top',\n y: 'top',\n display: 'visible',\n visibility: 'visible',\n transform: 'transformMatrix',\n 'fill-opacity': 'fillOpacity',\n 'fill-rule': 'fillRule',\n 'font-family': 'fontFamily',\n 'font-size': 'fontSize',\n 'font-style': 'fontStyle',\n 'font-weight': 'fontWeight',\n 'letter-spacing': 'charSpacing',\n 'paint-order': 'paintFirst',\n 'stroke-dasharray': 'strokeDashArray',\n 'stroke-dashoffset': 'strokeDashOffset',\n 'stroke-linecap': 'strokeLineCap',\n 'stroke-linejoin': 'strokeLineJoin',\n 'stroke-miterlimit': 'strokeMiterLimit',\n 'stroke-opacity': 'strokeOpacity',\n 'stroke-width': 'strokeWidth',\n 'text-decoration': 'textDecoration',\n 'text-anchor': 'textAnchor',\n opacity: 'opacity',\n 'clip-path': 'clipPath',\n 'clip-rule': 'clipRule',\n 'vector-effect': 'strokeUniform',\n 'image-rendering': 'imageSmoothing',\n },\n\n colorAttributes = {\n stroke: 'strokeOpacity',\n fill: 'fillOpacity'\n },\n\n fSize = 'font-size', cPath = 'clip-path';\n\n fabric.svgValidTagNamesRegEx = getSvgRegex(svgValidTagNames);\n fabric.svgViewBoxElementsRegEx = getSvgRegex(svgViewBoxElements);\n fabric.svgInvalidAncestorsRegEx = getSvgRegex(svgInvalidAncestors);\n fabric.svgValidParentsRegEx = getSvgRegex(svgValidParents);\n\n fabric.cssRules = { };\n fabric.gradientDefs = { };\n fabric.clipPaths = { };\n\n function normalizeAttr(attr) {\n // transform attribute names\n if (attr in attributesMap) {\n return attributesMap[attr];\n }\n return attr;\n }\n\n function normalizeValue(attr, value, parentAttributes, fontSize) {\n var isArray = Array.isArray(value), parsed;\n\n if ((attr === 'fill' || attr === 'stroke') && value === 'none') {\n value = '';\n }\n else if (attr === 'strokeUniform') {\n return (value === 'non-scaling-stroke');\n }\n else if (attr === 'strokeDashArray') {\n if (value === 'none') {\n value = null;\n }\n else {\n value = value.replace(/,/g, ' ').split(/\\s+/).map(parseFloat);\n }\n }\n else if (attr === 'transformMatrix') {\n if (parentAttributes && parentAttributes.transformMatrix) {\n value = multiplyTransformMatrices(\n parentAttributes.transformMatrix, fabric.parseTransformAttribute(value));\n }\n else {\n value = fabric.parseTransformAttribute(value);\n }\n }\n else if (attr === 'visible') {\n value = value !== 'none' && value !== 'hidden';\n // display=none on parent element always takes precedence over child element\n if (parentAttributes && parentAttributes.visible === false) {\n value = false;\n }\n }\n else if (attr === 'opacity') {\n value = parseFloat(value);\n if (parentAttributes && typeof parentAttributes.opacity !== 'undefined') {\n value *= parentAttributes.opacity;\n }\n }\n else if (attr === 'textAnchor' /* text-anchor */) {\n value = value === 'start' ? 'left' : value === 'end' ? 'right' : 'center';\n }\n else if (attr === 'charSpacing') {\n // parseUnit returns px and we convert it to em\n parsed = parseUnit(value, fontSize) / fontSize * 1000;\n }\n else if (attr === 'paintFirst') {\n var fillIndex = value.indexOf('fill');\n var strokeIndex = value.indexOf('stroke');\n var value = 'fill';\n if (fillIndex > -1 && strokeIndex > -1 && strokeIndex < fillIndex) {\n value = 'stroke';\n }\n else if (fillIndex === -1 && strokeIndex > -1) {\n value = 'stroke';\n }\n }\n else if (attr === 'href' || attr === 'xlink:href' || attr === 'font') {\n return value;\n }\n else if (attr === 'imageSmoothing') {\n return (value === 'optimizeQuality');\n }\n else {\n parsed = isArray ? value.map(parseUnit) : parseUnit(value, fontSize);\n }\n\n return (!isArray && isNaN(parsed) ? value : parsed);\n }\n\n /**\n * @private\n */\n function getSvgRegex(arr) {\n return new RegExp('^(' + arr.join('|') + ')\\\\b', 'i');\n }\n\n /**\n * @private\n * @param {Object} attributes Array of attributes to parse\n */\n function _setStrokeFillOpacity(attributes) {\n for (var attr in colorAttributes) {\n\n if (typeof attributes[colorAttributes[attr]] === 'undefined' || attributes[attr] === '') {\n continue;\n }\n\n if (typeof attributes[attr] === 'undefined') {\n if (!fabric.Object.prototype[attr]) {\n continue;\n }\n attributes[attr] = fabric.Object.prototype[attr];\n }\n\n if (attributes[attr].indexOf('url(') === 0) {\n continue;\n }\n\n var color = new fabric.Color(attributes[attr]);\n attributes[attr] = color.setAlpha(toFixed(color.getAlpha() * attributes[colorAttributes[attr]], 2)).toRgba();\n }\n return attributes;\n }\n\n /**\n * @private\n */\n function _getMultipleNodes(doc, nodeNames) {\n var nodeName, nodeArray = [], nodeList, i, len;\n for (i = 0, len = nodeNames.length; i < len; i++) {\n nodeName = nodeNames[i];\n nodeList = doc.getElementsByTagName(nodeName);\n nodeArray = nodeArray.concat(Array.prototype.slice.call(nodeList));\n }\n return nodeArray;\n }\n\n /**\n * Parses \"transform\" attribute, returning an array of values\n * @static\n * @function\n * @memberOf fabric\n * @param {String} attributeValue String containing attribute value\n * @return {Array} Array of 6 elements representing transformation matrix\n */\n fabric.parseTransformAttribute = (function() {\n function rotateMatrix(matrix, args) {\n var cos = fabric.util.cos(args[0]), sin = fabric.util.sin(args[0]),\n x = 0, y = 0;\n if (args.length === 3) {\n x = args[1];\n y = args[2];\n }\n\n matrix[0] = cos;\n matrix[1] = sin;\n matrix[2] = -sin;\n matrix[3] = cos;\n matrix[4] = x - (cos * x - sin * y);\n matrix[5] = y - (sin * x + cos * y);\n }\n\n function scaleMatrix(matrix, args) {\n var multiplierX = args[0],\n multiplierY = (args.length === 2) ? args[1] : args[0];\n\n matrix[0] = multiplierX;\n matrix[3] = multiplierY;\n }\n\n function skewMatrix(matrix, args, pos) {\n matrix[pos] = Math.tan(fabric.util.degreesToRadians(args[0]));\n }\n\n function translateMatrix(matrix, args) {\n matrix[4] = args[0];\n if (args.length === 2) {\n matrix[5] = args[1];\n }\n }\n\n // identity matrix\n var iMatrix = fabric.iMatrix,\n\n // == begin transform regexp\n number = fabric.reNum,\n\n commaWsp = fabric.commaWsp,\n\n skewX = '(?:(skewX)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n skewY = '(?:(skewY)\\\\s*\\\\(\\\\s*(' + number + ')\\\\s*\\\\))',\n\n rotate = '(?:(rotate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n commaWsp + '(' + number + ')' +\n commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n scale = '(?:(scale)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n translate = '(?:(translate)\\\\s*\\\\(\\\\s*(' + number + ')(?:' +\n commaWsp + '(' + number + '))?\\\\s*\\\\))',\n\n matrix = '(?:(matrix)\\\\s*\\\\(\\\\s*' +\n '(' + number + ')' + commaWsp +\n '(' + number + ')' + commaWsp +\n '(' + number + ')' + commaWsp +\n '(' + number + ')' + commaWsp +\n '(' + number + ')' + commaWsp +\n '(' + number + ')' +\n '\\\\s*\\\\))',\n\n transform = '(?:' +\n matrix + '|' +\n translate + '|' +\n scale + '|' +\n rotate + '|' +\n skewX + '|' +\n skewY +\n ')',\n\n transforms = '(?:' + transform + '(?:' + commaWsp + '*' + transform + ')*' + ')',\n\n transformList = '^\\\\s*(?:' + transforms + '?)\\\\s*$',\n\n // http://www.w3.org/TR/SVG/coords.html#TransformAttribute\n reTransformList = new RegExp(transformList),\n // == end transform regexp\n\n reTransform = new RegExp(transform, 'g');\n\n return function(attributeValue) {\n\n // start with identity matrix\n var matrix = iMatrix.concat(),\n matrices = [];\n\n // return if no argument was given or\n // an argument does not match transform attribute regexp\n if (!attributeValue || (attributeValue && !reTransformList.test(attributeValue))) {\n return matrix;\n }\n\n attributeValue.replace(reTransform, function(match) {\n\n var m = new RegExp(transform).exec(match).filter(function (match) {\n // match !== '' && match != null\n return (!!match);\n }),\n operation = m[1],\n args = m.slice(2).map(parseFloat);\n\n switch (operation) {\n case 'translate':\n translateMatrix(matrix, args);\n break;\n case 'rotate':\n args[0] = fabric.util.degreesToRadians(args[0]);\n rotateMatrix(matrix, args);\n break;\n case 'scale':\n scaleMatrix(matrix, args);\n break;\n case 'skewX':\n skewMatrix(matrix, args, 2);\n break;\n case 'skewY':\n skewMatrix(matrix, args, 1);\n break;\n case 'matrix':\n matrix = args;\n break;\n }\n\n // snapshot current matrix into matrices array\n matrices.push(matrix.concat());\n // reset\n matrix = iMatrix.concat();\n });\n\n var combinedMatrix = matrices[0];\n while (matrices.length > 1) {\n matrices.shift();\n combinedMatrix = fabric.util.multiplyTransformMatrices(combinedMatrix, matrices[0]);\n }\n return combinedMatrix;\n };\n })();\n\n /**\n * @private\n */\n function parseStyleString(style, oStyle) {\n var attr, value;\n style.replace(/;\\s*$/, '').split(';').forEach(function (chunk) {\n var pair = chunk.split(':');\n\n attr = pair[0].trim().toLowerCase();\n value = pair[1].trim();\n\n oStyle[attr] = value;\n });\n }\n\n /**\n * @private\n */\n function parseStyleObject(style, oStyle) {\n var attr, value;\n for (var prop in style) {\n if (typeof style[prop] === 'undefined') {\n continue;\n }\n\n attr = prop.toLowerCase();\n value = style[prop];\n\n oStyle[attr] = value;\n }\n }\n\n /**\n * @private\n */\n function getGlobalStylesForElement(element, svgUid) {\n var styles = { };\n for (var rule in fabric.cssRules[svgUid]) {\n if (elementMatchesRule(element, rule.split(' '))) {\n for (var property in fabric.cssRules[svgUid][rule]) {\n styles[property] = fabric.cssRules[svgUid][rule][property];\n }\n }\n }\n return styles;\n }\n\n /**\n * @private\n */\n function elementMatchesRule(element, selectors) {\n var firstMatching, parentMatching = true;\n //start from rightmost selector.\n firstMatching = selectorMatches(element, selectors.pop());\n if (firstMatching && selectors.length) {\n parentMatching = doesSomeParentMatch(element, selectors);\n }\n return firstMatching && parentMatching && (selectors.length === 0);\n }\n\n function doesSomeParentMatch(element, selectors) {\n var selector, parentMatching = true;\n while (element.parentNode && element.parentNode.nodeType === 1 && selectors.length) {\n if (parentMatching) {\n selector = selectors.pop();\n }\n element = element.parentNode;\n parentMatching = selectorMatches(element, selector);\n }\n return selectors.length === 0;\n }\n\n /**\n * @private\n */\n function selectorMatches(element, selector) {\n var nodeName = element.nodeName,\n classNames = element.getAttribute('class'),\n id = element.getAttribute('id'), matcher, i;\n // i check if a selector matches slicing away part from it.\n // if i get empty string i should match\n matcher = new RegExp('^' + nodeName, 'i');\n selector = selector.replace(matcher, '');\n if (id && selector.length) {\n matcher = new RegExp('#' + id + '(?![a-zA-Z\\\\-]+)', 'i');\n selector = selector.replace(matcher, '');\n }\n if (classNames && selector.length) {\n classNames = classNames.split(' ');\n for (i = classNames.length; i--;) {\n matcher = new RegExp('\\\\.' + classNames[i] + '(?![a-zA-Z\\\\-]+)', 'i');\n selector = selector.replace(matcher, '');\n }\n }\n return selector.length === 0;\n }\n\n /**\n * @private\n * to support IE8 missing getElementById on SVGdocument and on node xmlDOM\n */\n function elementById(doc, id) {\n var el;\n doc.getElementById && (el = doc.getElementById(id));\n if (el) {\n return el;\n }\n var node, i, len, nodelist = doc.getElementsByTagName('*');\n for (i = 0, len = nodelist.length; i < len; i++) {\n node = nodelist[i];\n if (id === node.getAttribute('id')) {\n return node;\n }\n }\n }\n\n /**\n * @private\n */\n function parseUseDirectives(doc) {\n var nodelist = _getMultipleNodes(doc, ['use', 'svg:use']), i = 0;\n while (nodelist.length && i < nodelist.length) {\n var el = nodelist[i],\n xlinkAttribute = el.getAttribute('xlink:href') || el.getAttribute('href');\n\n if (xlinkAttribute === null) {\n return;\n }\n\n var xlink = xlinkAttribute.slice(1),\n x = el.getAttribute('x') || 0,\n y = el.getAttribute('y') || 0,\n el2 = elementById(doc, xlink).cloneNode(true),\n currentTrans = (el2.getAttribute('transform') || '') + ' translate(' + x + ', ' + y + ')',\n parentNode,\n oldLength = nodelist.length, attr,\n j,\n attrs,\n len,\n namespace = fabric.svgNS;\n\n applyViewboxTransform(el2);\n if (/^svg$/i.test(el2.nodeName)) {\n var el3 = el2.ownerDocument.createElementNS(namespace, 'g');\n for (j = 0, attrs = el2.attributes, len = attrs.length; j < len; j++) {\n attr = attrs.item(j);\n el3.setAttributeNS(namespace, attr.nodeName, attr.nodeValue);\n }\n // el2.firstChild != null\n while (el2.firstChild) {\n el3.appendChild(el2.firstChild);\n }\n el2 = el3;\n }\n\n for (j = 0, attrs = el.attributes, len = attrs.length; j < len; j++) {\n attr = attrs.item(j);\n if (attr.nodeName === 'x' || attr.nodeName === 'y' ||\n attr.nodeName === 'xlink:href' || attr.nodeName === 'href') {\n continue;\n }\n\n if (attr.nodeName === 'transform') {\n currentTrans = attr.nodeValue + ' ' + currentTrans;\n }\n else {\n el2.setAttribute(attr.nodeName, attr.nodeValue);\n }\n }\n\n el2.setAttribute('transform', currentTrans);\n el2.setAttribute('instantiated_by_use', '1');\n el2.removeAttribute('id');\n parentNode = el.parentNode;\n parentNode.replaceChild(el2, el);\n // some browsers do not shorten nodelist after replaceChild (IE8)\n if (nodelist.length === oldLength) {\n i++;\n }\n }\n }\n\n // http://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute\n // matches, e.g.: +14.56e-12, etc.\n var reViewBoxAttrValue = new RegExp(\n '^' +\n '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n '\\\\s*(' + fabric.reNum + '+)\\\\s*,?' +\n '\\\\s*(' + fabric.reNum + '+)\\\\s*' +\n '$'\n );\n\n /**\n * Add a element that envelop all child elements and makes the viewbox transformMatrix descend on all elements\n */\n function applyViewboxTransform(element) {\n if (!fabric.svgViewBoxElementsRegEx.test(element.nodeName)) {\n return {};\n }\n var viewBoxAttr = element.getAttribute('viewBox'),\n scaleX = 1,\n scaleY = 1,\n minX = 0,\n minY = 0,\n viewBoxWidth, viewBoxHeight, matrix, el,\n widthAttr = element.getAttribute('width'),\n heightAttr = element.getAttribute('height'),\n x = element.getAttribute('x') || 0,\n y = element.getAttribute('y') || 0,\n preserveAspectRatio = element.getAttribute('preserveAspectRatio') || '',\n missingViewBox = (!viewBoxAttr || !(viewBoxAttr = viewBoxAttr.match(reViewBoxAttrValue))),\n missingDimAttr = (!widthAttr || !heightAttr || widthAttr === '100%' || heightAttr === '100%'),\n toBeParsed = missingViewBox && missingDimAttr,\n parsedDim = { }, translateMatrix = '', widthDiff = 0, heightDiff = 0;\n\n parsedDim.width = 0;\n parsedDim.height = 0;\n parsedDim.toBeParsed = toBeParsed;\n\n if (missingViewBox) {\n if (((x || y) && element.parentNode && element.parentNode.nodeName !== '#document')) {\n translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') ';\n matrix = (element.getAttribute('transform') || '') + translateMatrix;\n element.setAttribute('transform', matrix);\n element.removeAttribute('x');\n element.removeAttribute('y');\n }\n }\n\n if (toBeParsed) {\n return parsedDim;\n }\n\n if (missingViewBox) {\n parsedDim.width = parseUnit(widthAttr);\n parsedDim.height = parseUnit(heightAttr);\n // set a transform for elements that have x y and are inner(only) SVGs\n return parsedDim;\n }\n minX = -parseFloat(viewBoxAttr[1]);\n minY = -parseFloat(viewBoxAttr[2]);\n viewBoxWidth = parseFloat(viewBoxAttr[3]);\n viewBoxHeight = parseFloat(viewBoxAttr[4]);\n parsedDim.minX = minX;\n parsedDim.minY = minY;\n parsedDim.viewBoxWidth = viewBoxWidth;\n parsedDim.viewBoxHeight = viewBoxHeight;\n if (!missingDimAttr) {\n parsedDim.width = parseUnit(widthAttr);\n parsedDim.height = parseUnit(heightAttr);\n scaleX = parsedDim.width / viewBoxWidth;\n scaleY = parsedDim.height / viewBoxHeight;\n }\n else {\n parsedDim.width = viewBoxWidth;\n parsedDim.height = viewBoxHeight;\n }\n\n // default is to preserve aspect ratio\n preserveAspectRatio = fabric.util.parsePreserveAspectRatioAttribute(preserveAspectRatio);\n if (preserveAspectRatio.alignX !== 'none') {\n //translate all container for the effect of Mid, Min, Max\n if (preserveAspectRatio.meetOrSlice === 'meet') {\n scaleY = scaleX = (scaleX > scaleY ? scaleY : scaleX);\n // calculate additional translation to move the viewbox\n }\n if (preserveAspectRatio.meetOrSlice === 'slice') {\n scaleY = scaleX = (scaleX > scaleY ? scaleX : scaleY);\n // calculate additional translation to move the viewbox\n }\n widthDiff = parsedDim.width - viewBoxWidth * scaleX;\n heightDiff = parsedDim.height - viewBoxHeight * scaleX;\n if (preserveAspectRatio.alignX === 'Mid') {\n widthDiff /= 2;\n }\n if (preserveAspectRatio.alignY === 'Mid') {\n heightDiff /= 2;\n }\n if (preserveAspectRatio.alignX === 'Min') {\n widthDiff = 0;\n }\n if (preserveAspectRatio.alignY === 'Min') {\n heightDiff = 0;\n }\n }\n\n if (scaleX === 1 && scaleY === 1 && minX === 0 && minY === 0 && x === 0 && y === 0) {\n return parsedDim;\n }\n if ((x || y) && element.parentNode.nodeName !== '#document') {\n translateMatrix = ' translate(' + parseUnit(x) + ' ' + parseUnit(y) + ') ';\n }\n\n matrix = translateMatrix + ' matrix(' + scaleX +\n ' 0' +\n ' 0 ' +\n scaleY + ' ' +\n (minX * scaleX + widthDiff) + ' ' +\n (minY * scaleY + heightDiff) + ') ';\n // seems unused.\n // parsedDim.viewboxTransform = fabric.parseTransformAttribute(matrix);\n if (element.nodeName === 'svg') {\n el = element.ownerDocument.createElementNS(fabric.svgNS, 'g');\n // element.firstChild != null\n while (element.firstChild) {\n el.appendChild(element.firstChild);\n }\n element.appendChild(el);\n }\n else {\n el = element;\n el.removeAttribute('x');\n el.removeAttribute('y');\n matrix = el.getAttribute('transform') + matrix;\n }\n el.setAttribute('transform', matrix);\n return parsedDim;\n }\n\n function hasAncestorWithNodeName(element, nodeName) {\n while (element && (element = element.parentNode)) {\n if (element.nodeName && nodeName.test(element.nodeName.replace('svg:', ''))\n && !element.getAttribute('instantiated_by_use')) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Parses an SVG document, converts it to an array of corresponding fabric.* instances and passes them to a callback\n * @static\n * @function\n * @memberOf fabric\n * @param {SVGDocument} doc SVG document to parse\n * @param {Function} callback Callback to call when parsing is finished;\n * It's being passed an array of elements (parsed from a document).\n * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n * @param {Object} [parsingOptions] options for parsing document\n * @param {String} [parsingOptions.crossOrigin] crossOrigin settings\n */\n fabric.parseSVGDocument = function(doc, callback, reviver, parsingOptions) {\n if (!doc) {\n return;\n }\n\n parseUseDirectives(doc);\n\n var svgUid = fabric.Object.__uid++, i, len,\n options = applyViewboxTransform(doc),\n descendants = fabric.util.toArray(doc.getElementsByTagName('*'));\n options.crossOrigin = parsingOptions && parsingOptions.crossOrigin;\n options.svgUid = svgUid;\n\n if (descendants.length === 0 && fabric.isLikelyNode) {\n // we're likely in node, where \"o3-xml\" library fails to gEBTN(\"*\")\n // https://github.com/ajaxorg/node-o3-xml/issues/21\n descendants = doc.selectNodes('//*[name(.)!=\"svg\"]');\n var arr = [];\n for (i = 0, len = descendants.length; i < len; i++) {\n arr[i] = descendants[i];\n }\n descendants = arr;\n }\n\n var elements = descendants.filter(function(el) {\n applyViewboxTransform(el);\n return fabric.svgValidTagNamesRegEx.test(el.nodeName.replace('svg:', '')) &&\n !hasAncestorWithNodeName(el, fabric.svgInvalidAncestorsRegEx); // http://www.w3.org/TR/SVG/struct.html#DefsElement\n });\n if (!elements || (elements && !elements.length)) {\n callback && callback([], {});\n return;\n }\n var clipPaths = { };\n descendants.filter(function(el) {\n return el.nodeName.replace('svg:', '') === 'clipPath';\n }).forEach(function(el) {\n var id = el.getAttribute('id');\n clipPaths[id] = fabric.util.toArray(el.getElementsByTagName('*')).filter(function(el) {\n return fabric.svgValidTagNamesRegEx.test(el.nodeName.replace('svg:', ''));\n });\n });\n fabric.gradientDefs[svgUid] = fabric.getGradientDefs(doc);\n fabric.cssRules[svgUid] = fabric.getCSSRules(doc);\n fabric.clipPaths[svgUid] = clipPaths;\n // Precedence of rules: style > class > attribute\n fabric.parseElements(elements, function(instances, elements) {\n if (callback) {\n callback(instances, options, elements, descendants);\n delete fabric.gradientDefs[svgUid];\n delete fabric.cssRules[svgUid];\n delete fabric.clipPaths[svgUid];\n }\n }, clone(options), reviver, parsingOptions);\n };\n\n function recursivelyParseGradientsXlink(doc, gradient) {\n var gradientsAttrs = ['gradientTransform', 'x1', 'x2', 'y1', 'y2', 'gradientUnits', 'cx', 'cy', 'r', 'fx', 'fy'],\n xlinkAttr = 'xlink:href',\n xLink = gradient.getAttribute(xlinkAttr).slice(1),\n referencedGradient = elementById(doc, xLink);\n if (referencedGradient && referencedGradient.getAttribute(xlinkAttr)) {\n recursivelyParseGradientsXlink(doc, referencedGradient);\n }\n gradientsAttrs.forEach(function(attr) {\n if (referencedGradient && !gradient.hasAttribute(attr) && referencedGradient.hasAttribute(attr)) {\n gradient.setAttribute(attr, referencedGradient.getAttribute(attr));\n }\n });\n if (!gradient.children.length) {\n var referenceClone = referencedGradient.cloneNode(true);\n while (referenceClone.firstChild) {\n gradient.appendChild(referenceClone.firstChild);\n }\n }\n gradient.removeAttribute(xlinkAttr);\n }\n\n var reFontDeclaration = new RegExp(\n '(normal|italic)?\\\\s*(normal|small-caps)?\\\\s*' +\n '(normal|bold|bolder|lighter|100|200|300|400|500|600|700|800|900)?\\\\s*(' +\n fabric.reNum +\n '(?:px|cm|mm|em|pt|pc|in)*)(?:\\\\/(normal|' + fabric.reNum + '))?\\\\s+(.*)');\n\n extend(fabric, {\n /**\n * Parses a short font declaration, building adding its properties to a style object\n * @static\n * @function\n * @memberOf fabric\n * @param {String} value font declaration\n * @param {Object} oStyle definition\n */\n parseFontDeclaration: function(value, oStyle) {\n var match = value.match(reFontDeclaration);\n\n if (!match) {\n return;\n }\n var fontStyle = match[1],\n // font variant is not used\n // fontVariant = match[2],\n fontWeight = match[3],\n fontSize = match[4],\n lineHeight = match[5],\n fontFamily = match[6];\n\n if (fontStyle) {\n oStyle.fontStyle = fontStyle;\n }\n if (fontWeight) {\n oStyle.fontWeight = isNaN(parseFloat(fontWeight)) ? fontWeight : parseFloat(fontWeight);\n }\n if (fontSize) {\n oStyle.fontSize = parseUnit(fontSize);\n }\n if (fontFamily) {\n oStyle.fontFamily = fontFamily;\n }\n if (lineHeight) {\n oStyle.lineHeight = lineHeight === 'normal' ? 1 : lineHeight;\n }\n },\n\n /**\n * Parses an SVG document, returning all of the gradient declarations found in it\n * @static\n * @function\n * @memberOf fabric\n * @param {SVGDocument} doc SVG document to parse\n * @return {Object} Gradient definitions; key corresponds to element id, value -- to gradient definition element\n */\n getGradientDefs: function(doc) {\n var tagArray = [\n 'linearGradient',\n 'radialGradient',\n 'svg:linearGradient',\n 'svg:radialGradient'],\n elList = _getMultipleNodes(doc, tagArray),\n el, j = 0, gradientDefs = { };\n j = elList.length;\n while (j--) {\n el = elList[j];\n if (el.getAttribute('xlink:href')) {\n recursivelyParseGradientsXlink(doc, el);\n }\n gradientDefs[el.getAttribute('id')] = el;\n }\n return gradientDefs;\n },\n\n /**\n * Returns an object of attributes' name/value, given element and an array of attribute names;\n * Parses parent \"g\" nodes recursively upwards.\n * @static\n * @memberOf fabric\n * @param {DOMElement} element Element to parse\n * @param {Array} attributes Array of attributes to parse\n * @return {Object} object containing parsed attributes' names/values\n */\n parseAttributes: function(element, attributes, svgUid) {\n\n if (!element) {\n return;\n }\n\n var value,\n parentAttributes = { },\n fontSize, parentFontSize;\n\n if (typeof svgUid === 'undefined') {\n svgUid = element.getAttribute('svgUid');\n }\n // if there's a parent container (`g` or `a` or `symbol` node), parse its attributes recursively upwards\n if (element.parentNode && fabric.svgValidParentsRegEx.test(element.parentNode.nodeName)) {\n parentAttributes = fabric.parseAttributes(element.parentNode, attributes, svgUid);\n }\n\n var ownAttributes = attributes.reduce(function(memo, attr) {\n value = element.getAttribute(attr);\n if (value) { // eslint-disable-line\n memo[attr] = value;\n }\n return memo;\n }, { });\n // add values parsed from style, which take precedence over attributes\n // (see: http://www.w3.org/TR/SVG/styling.html#UsingPresentationAttributes)\n var cssAttrs = extend(\n getGlobalStylesForElement(element, svgUid),\n fabric.parseStyleAttribute(element)\n );\n ownAttributes = extend(\n ownAttributes,\n cssAttrs\n );\n if (cssAttrs[cPath]) {\n element.setAttribute(cPath, cssAttrs[cPath]);\n }\n fontSize = parentFontSize = parentAttributes.fontSize || fabric.Text.DEFAULT_SVG_FONT_SIZE;\n if (ownAttributes[fSize]) {\n // looks like the minimum should be 9px when dealing with ems. this is what looks like in browsers.\n ownAttributes[fSize] = fontSize = parseUnit(ownAttributes[fSize], parentFontSize);\n }\n\n var normalizedAttr, normalizedValue, normalizedStyle = {};\n for (var attr in ownAttributes) {\n normalizedAttr = normalizeAttr(attr);\n normalizedValue = normalizeValue(normalizedAttr, ownAttributes[attr], parentAttributes, fontSize);\n normalizedStyle[normalizedAttr] = normalizedValue;\n }\n if (normalizedStyle && normalizedStyle.font) {\n fabric.parseFontDeclaration(normalizedStyle.font, normalizedStyle);\n }\n var mergedAttrs = extend(parentAttributes, normalizedStyle);\n return fabric.svgValidParentsRegEx.test(element.nodeName) ? mergedAttrs : _setStrokeFillOpacity(mergedAttrs);\n },\n\n /**\n * Transforms an array of svg elements to corresponding fabric.* instances\n * @static\n * @memberOf fabric\n * @param {Array} elements Array of elements to parse\n * @param {Function} callback Being passed an array of fabric instances (transformed from SVG elements)\n * @param {Object} [options] Options object\n * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n */\n parseElements: function(elements, callback, options, reviver, parsingOptions) {\n new fabric.ElementsParser(elements, callback, options, reviver, parsingOptions).parse();\n },\n\n /**\n * Parses \"style\" attribute, retuning an object with values\n * @static\n * @memberOf fabric\n * @param {SVGElement} element Element to parse\n * @return {Object} Objects with values parsed from style attribute of an element\n */\n parseStyleAttribute: function(element) {\n var oStyle = { },\n style = element.getAttribute('style');\n\n if (!style) {\n return oStyle;\n }\n\n if (typeof style === 'string') {\n parseStyleString(style, oStyle);\n }\n else {\n parseStyleObject(style, oStyle);\n }\n\n return oStyle;\n },\n\n /**\n * Parses \"points\" attribute, returning an array of values\n * @static\n * @memberOf fabric\n * @param {String} points points attribute string\n * @return {Array} array of points\n */\n parsePointsAttribute: function(points) {\n\n // points attribute is required and must not be empty\n if (!points) {\n return null;\n }\n\n // replace commas with whitespace and remove bookending whitespace\n points = points.replace(/,/g, ' ').trim();\n\n points = points.split(/\\s+/);\n var parsedPoints = [], i, len;\n\n for (i = 0, len = points.length; i < len; i += 2) {\n parsedPoints.push({\n x: parseFloat(points[i]),\n y: parseFloat(points[i + 1])\n });\n }\n\n // odd number of points is an error\n // if (parsedPoints.length % 2 !== 0) {\n // return null;\n // }\n\n return parsedPoints;\n },\n\n /**\n * Returns CSS rules for a given SVG document\n * @static\n * @function\n * @memberOf fabric\n * @param {SVGDocument} doc SVG document to parse\n * @return {Object} CSS rules of this document\n */\n getCSSRules: function(doc) {\n var styles = doc.getElementsByTagName('style'), i, len,\n allRules = { }, rules;\n\n // very crude parsing of style contents\n for (i = 0, len = styles.length; i < len; i++) {\n var styleContents = styles[i].textContent;\n\n // remove comments\n styleContents = styleContents.replace(/\\/\\*[\\s\\S]*?\\*\\//g, '');\n if (styleContents.trim() === '') {\n continue;\n }\n // recovers all the rule in this form `body { style code... }`\n // rules = styleContents.match(/[^{]*\\{[\\s\\S]*?\\}/g);\n rules = styleContents.split('}');\n // remove empty rules.\n rules = rules.filter(function(rule) { return rule.trim(); });\n // at this point we have hopefully an array of rules `body { style code... `\n // eslint-disable-next-line no-loop-func\n rules.forEach(function(rule) {\n\n var match = rule.split('{'),\n ruleObj = { }, declaration = match[1].trim(),\n propertyValuePairs = declaration.split(';').filter(function(pair) { return pair.trim(); });\n\n for (i = 0, len = propertyValuePairs.length; i < len; i++) {\n var pair = propertyValuePairs[i].split(':'),\n property = pair[0].trim(),\n value = pair[1].trim();\n ruleObj[property] = value;\n }\n rule = match[0].trim();\n rule.split(',').forEach(function(_rule) {\n _rule = _rule.replace(/^svg/i, '').trim();\n if (_rule === '') {\n return;\n }\n if (allRules[_rule]) {\n fabric.util.object.extend(allRules[_rule], ruleObj);\n }\n else {\n allRules[_rule] = fabric.util.object.clone(ruleObj);\n }\n });\n });\n }\n return allRules;\n },\n\n /**\n * Takes url corresponding to an SVG document, and parses it into a set of fabric objects.\n * Note that SVG is fetched via XMLHttpRequest, so it needs to conform to SOP (Same Origin Policy)\n * @memberOf fabric\n * @param {String} url\n * @param {Function} callback\n * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n * @param {Object} [options] Object containing options for parsing\n * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources\n */\n loadSVGFromURL: function(url, callback, reviver, options) {\n\n url = url.replace(/^\\n\\s*/, '').trim();\n new fabric.util.request(url, {\n method: 'get',\n onComplete: onComplete\n });\n\n function onComplete(r) {\n\n var xml = r.responseXML;\n if (!xml || !xml.documentElement) {\n callback && callback(null);\n return false;\n }\n\n fabric.parseSVGDocument(xml.documentElement, function (results, _options, elements, allElements) {\n callback && callback(results, _options, elements, allElements);\n }, reviver, options);\n }\n },\n\n /**\n * Takes string corresponding to an SVG document, and parses it into a set of fabric objects\n * @memberOf fabric\n * @param {String} string\n * @param {Function} callback\n * @param {Function} [reviver] Method for further parsing of SVG elements, called after each fabric object created.\n * @param {Object} [options] Object containing options for parsing\n * @param {String} [options.crossOrigin] crossOrigin crossOrigin setting to use for external resources\n */\n loadSVGFromString: function(string, callback, reviver, options) {\n var parser = new fabric.window.DOMParser(),\n doc = parser.parseFromString(string.trim(), 'text/xml');\n fabric.parseSVGDocument(doc.documentElement, function (results, _options, elements, allElements) {\n callback(results, _options, elements, allElements);\n }, reviver, options);\n }\n });\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.ElementsParser = function(elements, callback, options, reviver, parsingOptions, doc) {\n this.elements = elements;\n this.callback = callback;\n this.options = options;\n this.reviver = reviver;\n this.svgUid = (options && options.svgUid) || 0;\n this.parsingOptions = parsingOptions;\n this.regexUrl = /^url\\(['\"]?#([^'\"]+)['\"]?\\)/g;\n this.doc = doc;\n};\n\n(function(proto) {\n proto.parse = function() {\n this.instances = new Array(this.elements.length);\n this.numElements = this.elements.length;\n this.createObjects();\n };\n\n proto.createObjects = function() {\n var _this = this;\n this.elements.forEach(function(element, i) {\n element.setAttribute('svgUid', _this.svgUid);\n _this.createObject(element, i);\n });\n };\n\n proto.findTag = function(el) {\n return fabric[fabric.util.string.capitalize(el.tagName.replace('svg:', ''))];\n };\n\n proto.createObject = function(el, index) {\n var klass = this.findTag(el);\n if (klass && klass.fromElement) {\n try {\n klass.fromElement(el, this.createCallback(index, el), this.options);\n }\n catch (err) {\n fabric.log(err);\n }\n }\n else {\n this.checkIfDone();\n }\n };\n\n proto.createCallback = function(index, el) {\n var _this = this;\n return function(obj) {\n var _options;\n _this.resolveGradient(obj, el, 'fill');\n _this.resolveGradient(obj, el, 'stroke');\n if (obj instanceof fabric.Image && obj._originalElement) {\n _options = obj.parsePreserveAspectRatioAttribute(el);\n }\n obj._removeTransformMatrix(_options);\n _this.resolveClipPath(obj, el);\n _this.reviver && _this.reviver(el, obj);\n _this.instances[index] = obj;\n _this.checkIfDone();\n };\n };\n\n proto.extractPropertyDefinition = function(obj, property, storage) {\n var value = obj[property], regex = this.regexUrl;\n if (!regex.test(value)) {\n return;\n }\n regex.lastIndex = 0;\n var id = regex.exec(value)[1];\n regex.lastIndex = 0;\n return fabric[storage][this.svgUid][id];\n };\n\n proto.resolveGradient = function(obj, el, property) {\n var gradientDef = this.extractPropertyDefinition(obj, property, 'gradientDefs');\n if (gradientDef) {\n var opacityAttr = el.getAttribute(property + '-opacity');\n var gradient = fabric.Gradient.fromElement(gradientDef, obj, opacityAttr, this.options);\n obj.set(property, gradient);\n }\n };\n\n proto.createClipPathCallback = function(obj, container) {\n return function(_newObj) {\n _newObj._removeTransformMatrix();\n _newObj.fillRule = _newObj.clipRule;\n container.push(_newObj);\n };\n };\n\n proto.resolveClipPath = function(obj, usingElement) {\n var clipPath = this.extractPropertyDefinition(obj, 'clipPath', 'clipPaths'),\n element, klass, objTransformInv, container, gTransform, options;\n if (clipPath) {\n container = [];\n objTransformInv = fabric.util.invertTransform(obj.calcTransformMatrix());\n // move the clipPath tag as sibling to the real element that is using it\n var clipPathTag = clipPath[0].parentNode;\n var clipPathOwner = usingElement;\n while (clipPathOwner.parentNode && clipPathOwner.getAttribute('clip-path') !== obj.clipPath) {\n clipPathOwner = clipPathOwner.parentNode;\n }\n clipPathOwner.parentNode.appendChild(clipPathTag);\n for (var i = 0; i < clipPath.length; i++) {\n element = clipPath[i];\n klass = this.findTag(element);\n klass.fromElement(\n element,\n this.createClipPathCallback(obj, container),\n this.options\n );\n }\n if (container.length === 1) {\n clipPath = container[0];\n }\n else {\n clipPath = new fabric.Group(container);\n }\n gTransform = fabric.util.multiplyTransformMatrices(\n objTransformInv,\n clipPath.calcTransformMatrix()\n );\n if (clipPath.clipPath) {\n this.resolveClipPath(clipPath, clipPathOwner);\n }\n var options = fabric.util.qrDecompose(gTransform);\n clipPath.flipX = false;\n clipPath.flipY = false;\n clipPath.set('scaleX', options.scaleX);\n clipPath.set('scaleY', options.scaleY);\n clipPath.angle = options.angle;\n clipPath.skewX = options.skewX;\n clipPath.skewY = 0;\n clipPath.setPositionByOrigin({ x: options.translateX, y: options.translateY }, 'center', 'center');\n obj.clipPath = clipPath;\n }\n else {\n // if clip-path does not resolve to any element, delete the property.\n delete obj.clipPath;\n }\n };\n\n proto.checkIfDone = function() {\n if (--this.numElements === 0) {\n this.instances = this.instances.filter(function(el) {\n // eslint-disable-next-line no-eq-null, eqeqeq\n return el != null;\n });\n this.callback(this.instances, this.elements);\n }\n };\n})(fabric.ElementsParser.prototype);\n\n\n(function(global) {\n\n 'use strict';\n\n /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n\n var fabric = global.fabric || (global.fabric = { });\n\n if (fabric.Point) {\n fabric.warn('fabric.Point is already defined');\n return;\n }\n\n fabric.Point = Point;\n\n /**\n * Point class\n * @class fabric.Point\n * @memberOf fabric\n * @constructor\n * @param {Number} x\n * @param {Number} y\n * @return {fabric.Point} thisArg\n */\n function Point(x, y) {\n this.x = x;\n this.y = y;\n }\n\n Point.prototype = /** @lends fabric.Point.prototype */ {\n\n type: 'point',\n\n constructor: Point,\n\n /**\n * Adds another point to this one and returns another one\n * @param {fabric.Point} that\n * @return {fabric.Point} new Point instance with added values\n */\n add: function (that) {\n return new Point(this.x + that.x, this.y + that.y);\n },\n\n /**\n * Adds another point to this one\n * @param {fabric.Point} that\n * @return {fabric.Point} thisArg\n * @chainable\n */\n addEquals: function (that) {\n this.x += that.x;\n this.y += that.y;\n return this;\n },\n\n /**\n * Adds value to this point and returns a new one\n * @param {Number} scalar\n * @return {fabric.Point} new Point with added value\n */\n scalarAdd: function (scalar) {\n return new Point(this.x + scalar, this.y + scalar);\n },\n\n /**\n * Adds value to this point\n * @param {Number} scalar\n * @return {fabric.Point} thisArg\n * @chainable\n */\n scalarAddEquals: function (scalar) {\n this.x += scalar;\n this.y += scalar;\n return this;\n },\n\n /**\n * Subtracts another point from this point and returns a new one\n * @param {fabric.Point} that\n * @return {fabric.Point} new Point object with subtracted values\n */\n subtract: function (that) {\n return new Point(this.x - that.x, this.y - that.y);\n },\n\n /**\n * Subtracts another point from this point\n * @param {fabric.Point} that\n * @return {fabric.Point} thisArg\n * @chainable\n */\n subtractEquals: function (that) {\n this.x -= that.x;\n this.y -= that.y;\n return this;\n },\n\n /**\n * Subtracts value from this point and returns a new one\n * @param {Number} scalar\n * @return {fabric.Point}\n */\n scalarSubtract: function (scalar) {\n return new Point(this.x - scalar, this.y - scalar);\n },\n\n /**\n * Subtracts value from this point\n * @param {Number} scalar\n * @return {fabric.Point} thisArg\n * @chainable\n */\n scalarSubtractEquals: function (scalar) {\n this.x -= scalar;\n this.y -= scalar;\n return this;\n },\n\n /**\n * Multiplies this point by a value and returns a new one\n * TODO: rename in scalarMultiply in 2.0\n * @param {Number} scalar\n * @return {fabric.Point}\n */\n multiply: function (scalar) {\n return new Point(this.x * scalar, this.y * scalar);\n },\n\n /**\n * Multiplies this point by a value\n * TODO: rename in scalarMultiplyEquals in 2.0\n * @param {Number} scalar\n * @return {fabric.Point} thisArg\n * @chainable\n */\n multiplyEquals: function (scalar) {\n this.x *= scalar;\n this.y *= scalar;\n return this;\n },\n\n /**\n * Divides this point by a value and returns a new one\n * TODO: rename in scalarDivide in 2.0\n * @param {Number} scalar\n * @return {fabric.Point}\n */\n divide: function (scalar) {\n return new Point(this.x / scalar, this.y / scalar);\n },\n\n /**\n * Divides this point by a value\n * TODO: rename in scalarDivideEquals in 2.0\n * @param {Number} scalar\n * @return {fabric.Point} thisArg\n * @chainable\n */\n divideEquals: function (scalar) {\n this.x /= scalar;\n this.y /= scalar;\n return this;\n },\n\n /**\n * Returns true if this point is equal to another one\n * @param {fabric.Point} that\n * @return {Boolean}\n */\n eq: function (that) {\n return (this.x === that.x && this.y === that.y);\n },\n\n /**\n * Returns true if this point is less than another one\n * @param {fabric.Point} that\n * @return {Boolean}\n */\n lt: function (that) {\n return (this.x < that.x && this.y < that.y);\n },\n\n /**\n * Returns true if this point is less than or equal to another one\n * @param {fabric.Point} that\n * @return {Boolean}\n */\n lte: function (that) {\n return (this.x <= that.x && this.y <= that.y);\n },\n\n /**\n\n * Returns true if this point is greater another one\n * @param {fabric.Point} that\n * @return {Boolean}\n */\n gt: function (that) {\n return (this.x > that.x && this.y > that.y);\n },\n\n /**\n * Returns true if this point is greater than or equal to another one\n * @param {fabric.Point} that\n * @return {Boolean}\n */\n gte: function (that) {\n return (this.x >= that.x && this.y >= that.y);\n },\n\n /**\n * Returns new point which is the result of linear interpolation with this one and another one\n * @param {fabric.Point} that\n * @param {Number} t , position of interpolation, between 0 and 1 default 0.5\n * @return {fabric.Point}\n */\n lerp: function (that, t) {\n if (typeof t === 'undefined') {\n t = 0.5;\n }\n t = Math.max(Math.min(1, t), 0);\n return new Point(this.x + (that.x - this.x) * t, this.y + (that.y - this.y) * t);\n },\n\n /**\n * Returns distance from this point and another one\n * @param {fabric.Point} that\n * @return {Number}\n */\n distanceFrom: function (that) {\n var dx = this.x - that.x,\n dy = this.y - that.y;\n return Math.sqrt(dx * dx + dy * dy);\n },\n\n /**\n * Returns the point between this point and another one\n * @param {fabric.Point} that\n * @return {fabric.Point}\n */\n midPointFrom: function (that) {\n return this.lerp(that);\n },\n\n /**\n * Returns a new point which is the min of this and another one\n * @param {fabric.Point} that\n * @return {fabric.Point}\n */\n min: function (that) {\n return new Point(Math.min(this.x, that.x), Math.min(this.y, that.y));\n },\n\n /**\n * Returns a new point which is the max of this and another one\n * @param {fabric.Point} that\n * @return {fabric.Point}\n */\n max: function (that) {\n return new Point(Math.max(this.x, that.x), Math.max(this.y, that.y));\n },\n\n /**\n * Returns string representation of this point\n * @return {String}\n */\n toString: function () {\n return this.x + ',' + this.y;\n },\n\n /**\n * Sets x/y of this point\n * @param {Number} x\n * @param {Number} y\n * @chainable\n */\n setXY: function (x, y) {\n this.x = x;\n this.y = y;\n return this;\n },\n\n /**\n * Sets x of this point\n * @param {Number} x\n * @chainable\n */\n setX: function (x) {\n this.x = x;\n return this;\n },\n\n /**\n * Sets y of this point\n * @param {Number} y\n * @chainable\n */\n setY: function (y) {\n this.y = y;\n return this;\n },\n\n /**\n * Sets x/y of this point from another point\n * @param {fabric.Point} that\n * @chainable\n */\n setFromPoint: function (that) {\n this.x = that.x;\n this.y = that.y;\n return this;\n },\n\n /**\n * Swaps x/y of this point and another point\n * @param {fabric.Point} that\n */\n swap: function (that) {\n var x = this.x,\n y = this.y;\n this.x = that.x;\n this.y = that.y;\n that.x = x;\n that.y = y;\n },\n\n /**\n * return a cloned instance of the point\n * @return {fabric.Point}\n */\n clone: function () {\n return new Point(this.x, this.y);\n }\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n /* Adaptation of work of Kevin Lindsey (kevin@kevlindev.com) */\n var fabric = global.fabric || (global.fabric = { });\n\n if (fabric.Intersection) {\n fabric.warn('fabric.Intersection is already defined');\n return;\n }\n\n /**\n * Intersection class\n * @class fabric.Intersection\n * @memberOf fabric\n * @constructor\n */\n function Intersection(status) {\n this.status = status;\n this.points = [];\n }\n\n fabric.Intersection = Intersection;\n\n fabric.Intersection.prototype = /** @lends fabric.Intersection.prototype */ {\n\n constructor: Intersection,\n\n /**\n * Appends a point to intersection\n * @param {fabric.Point} point\n * @return {fabric.Intersection} thisArg\n * @chainable\n */\n appendPoint: function (point) {\n this.points.push(point);\n return this;\n },\n\n /**\n * Appends points to intersection\n * @param {Array} points\n * @return {fabric.Intersection} thisArg\n * @chainable\n */\n appendPoints: function (points) {\n this.points = this.points.concat(points);\n return this;\n }\n };\n\n /**\n * Checks if one line intersects another\n * TODO: rename in intersectSegmentSegment\n * @static\n * @param {fabric.Point} a1\n * @param {fabric.Point} a2\n * @param {fabric.Point} b1\n * @param {fabric.Point} b2\n * @return {fabric.Intersection}\n */\n fabric.Intersection.intersectLineLine = function (a1, a2, b1, b2) {\n var result,\n uaT = (b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x),\n ubT = (a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x),\n uB = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);\n if (uB !== 0) {\n var ua = uaT / uB,\n ub = ubT / uB;\n if (0 <= ua && ua <= 1 && 0 <= ub && ub <= 1) {\n result = new Intersection('Intersection');\n result.appendPoint(new fabric.Point(a1.x + ua * (a2.x - a1.x), a1.y + ua * (a2.y - a1.y)));\n }\n else {\n result = new Intersection();\n }\n }\n else {\n if (uaT === 0 || ubT === 0) {\n result = new Intersection('Coincident');\n }\n else {\n result = new Intersection('Parallel');\n }\n }\n return result;\n };\n\n /**\n * Checks if line intersects polygon\n * TODO: rename in intersectSegmentPolygon\n * fix detection of coincident\n * @static\n * @param {fabric.Point} a1\n * @param {fabric.Point} a2\n * @param {Array} points\n * @return {fabric.Intersection}\n */\n fabric.Intersection.intersectLinePolygon = function(a1, a2, points) {\n var result = new Intersection(),\n length = points.length,\n b1, b2, inter, i;\n\n for (i = 0; i < length; i++) {\n b1 = points[i];\n b2 = points[(i + 1) % length];\n inter = Intersection.intersectLineLine(a1, a2, b1, b2);\n\n result.appendPoints(inter.points);\n }\n if (result.points.length > 0) {\n result.status = 'Intersection';\n }\n return result;\n };\n\n /**\n * Checks if polygon intersects another polygon\n * @static\n * @param {Array} points1\n * @param {Array} points2\n * @return {fabric.Intersection}\n */\n fabric.Intersection.intersectPolygonPolygon = function (points1, points2) {\n var result = new Intersection(),\n length = points1.length, i;\n\n for (i = 0; i < length; i++) {\n var a1 = points1[i],\n a2 = points1[(i + 1) % length],\n inter = Intersection.intersectLinePolygon(a1, a2, points2);\n\n result.appendPoints(inter.points);\n }\n if (result.points.length > 0) {\n result.status = 'Intersection';\n }\n return result;\n };\n\n /**\n * Checks if polygon intersects rectangle\n * @static\n * @param {Array} points\n * @param {fabric.Point} r1\n * @param {fabric.Point} r2\n * @return {fabric.Intersection}\n */\n fabric.Intersection.intersectPolygonRectangle = function (points, r1, r2) {\n var min = r1.min(r2),\n max = r1.max(r2),\n topRight = new fabric.Point(max.x, min.y),\n bottomLeft = new fabric.Point(min.x, max.y),\n inter1 = Intersection.intersectLinePolygon(min, topRight, points),\n inter2 = Intersection.intersectLinePolygon(topRight, max, points),\n inter3 = Intersection.intersectLinePolygon(max, bottomLeft, points),\n inter4 = Intersection.intersectLinePolygon(bottomLeft, min, points),\n result = new Intersection();\n\n result.appendPoints(inter1.points);\n result.appendPoints(inter2.points);\n result.appendPoints(inter3.points);\n result.appendPoints(inter4.points);\n\n if (result.points.length > 0) {\n result.status = 'Intersection';\n }\n return result;\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { });\n\n if (fabric.Color) {\n fabric.warn('fabric.Color is already defined.');\n return;\n }\n\n /**\n * Color class\n * The purpose of {@link fabric.Color} is to abstract and encapsulate common color operations;\n * {@link fabric.Color} is a constructor and creates instances of {@link fabric.Color} objects.\n *\n * @class fabric.Color\n * @param {String} color optional in hex or rgb(a) or hsl format or from known color list\n * @return {fabric.Color} thisArg\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2/#colors}\n */\n function Color(color) {\n if (!color) {\n this.setSource([0, 0, 0, 1]);\n }\n else {\n this._tryParsingColor(color);\n }\n }\n\n fabric.Color = Color;\n\n fabric.Color.prototype = /** @lends fabric.Color.prototype */ {\n\n /**\n * @private\n * @param {String|Array} color Color value to parse\n */\n _tryParsingColor: function(color) {\n var source;\n\n if (color in Color.colorNameMap) {\n color = Color.colorNameMap[color];\n }\n\n if (color === 'transparent') {\n source = [255, 255, 255, 0];\n }\n\n if (!source) {\n source = Color.sourceFromHex(color);\n }\n if (!source) {\n source = Color.sourceFromRgb(color);\n }\n if (!source) {\n source = Color.sourceFromHsl(color);\n }\n if (!source) {\n //if color is not recognize let's make black as canvas does\n source = [0, 0, 0, 1];\n }\n if (source) {\n this.setSource(source);\n }\n },\n\n /**\n * Adapted from https://github.com/mjijackson\n * @private\n * @param {Number} r Red color value\n * @param {Number} g Green color value\n * @param {Number} b Blue color value\n * @return {Array} Hsl color\n */\n _rgbToHsl: function(r, g, b) {\n r /= 255; g /= 255; b /= 255;\n\n var h, s, l,\n max = fabric.util.array.max([r, g, b]),\n min = fabric.util.array.min([r, g, b]);\n\n l = (max + min) / 2;\n\n if (max === min) {\n h = s = 0; // achromatic\n }\n else {\n var d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r:\n h = (g - b) / d + (g < b ? 6 : 0);\n break;\n case g:\n h = (b - r) / d + 2;\n break;\n case b:\n h = (r - g) / d + 4;\n break;\n }\n h /= 6;\n }\n\n return [\n Math.round(h * 360),\n Math.round(s * 100),\n Math.round(l * 100)\n ];\n },\n\n /**\n * Returns source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n * @return {Array}\n */\n getSource: function() {\n return this._source;\n },\n\n /**\n * Sets source of this color (where source is an array representation; ex: [200, 200, 100, 1])\n * @param {Array} source\n */\n setSource: function(source) {\n this._source = source;\n },\n\n /**\n * Returns color representation in RGB format\n * @return {String} ex: rgb(0-255,0-255,0-255)\n */\n toRgb: function() {\n var source = this.getSource();\n return 'rgb(' + source[0] + ',' + source[1] + ',' + source[2] + ')';\n },\n\n /**\n * Returns color representation in RGBA format\n * @return {String} ex: rgba(0-255,0-255,0-255,0-1)\n */\n toRgba: function() {\n var source = this.getSource();\n return 'rgba(' + source[0] + ',' + source[1] + ',' + source[2] + ',' + source[3] + ')';\n },\n\n /**\n * Returns color representation in HSL format\n * @return {String} ex: hsl(0-360,0%-100%,0%-100%)\n */\n toHsl: function() {\n var source = this.getSource(),\n hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n return 'hsl(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%)';\n },\n\n /**\n * Returns color representation in HSLA format\n * @return {String} ex: hsla(0-360,0%-100%,0%-100%,0-1)\n */\n toHsla: function() {\n var source = this.getSource(),\n hsl = this._rgbToHsl(source[0], source[1], source[2]);\n\n return 'hsla(' + hsl[0] + ',' + hsl[1] + '%,' + hsl[2] + '%,' + source[3] + ')';\n },\n\n /**\n * Returns color representation in HEX format\n * @return {String} ex: FF5555\n */\n toHex: function() {\n var source = this.getSource(), r, g, b;\n\n r = source[0].toString(16);\n r = (r.length === 1) ? ('0' + r) : r;\n\n g = source[1].toString(16);\n g = (g.length === 1) ? ('0' + g) : g;\n\n b = source[2].toString(16);\n b = (b.length === 1) ? ('0' + b) : b;\n\n return r.toUpperCase() + g.toUpperCase() + b.toUpperCase();\n },\n\n /**\n * Returns color representation in HEXA format\n * @return {String} ex: FF5555CC\n */\n toHexa: function() {\n var source = this.getSource(), a;\n\n a = Math.round(source[3] * 255);\n a = a.toString(16);\n a = (a.length === 1) ? ('0' + a) : a;\n\n return this.toHex() + a.toUpperCase();\n },\n\n /**\n * Gets value of alpha channel for this color\n * @return {Number} 0-1\n */\n getAlpha: function() {\n return this.getSource()[3];\n },\n\n /**\n * Sets value of alpha channel for this color\n * @param {Number} alpha Alpha value 0-1\n * @return {fabric.Color} thisArg\n */\n setAlpha: function(alpha) {\n var source = this.getSource();\n source[3] = alpha;\n this.setSource(source);\n return this;\n },\n\n /**\n * Transforms color to its grayscale representation\n * @return {fabric.Color} thisArg\n */\n toGrayscale: function() {\n var source = this.getSource(),\n average = parseInt((source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0), 10),\n currentAlpha = source[3];\n this.setSource([average, average, average, currentAlpha]);\n return this;\n },\n\n /**\n * Transforms color to its black and white representation\n * @param {Number} threshold\n * @return {fabric.Color} thisArg\n */\n toBlackWhite: function(threshold) {\n var source = this.getSource(),\n average = (source[0] * 0.3 + source[1] * 0.59 + source[2] * 0.11).toFixed(0),\n currentAlpha = source[3];\n\n threshold = threshold || 127;\n\n average = (Number(average) < Number(threshold)) ? 0 : 255;\n this.setSource([average, average, average, currentAlpha]);\n return this;\n },\n\n /**\n * Overlays color with another color\n * @param {String|fabric.Color} otherColor\n * @return {fabric.Color} thisArg\n */\n overlayWith: function(otherColor) {\n if (!(otherColor instanceof Color)) {\n otherColor = new Color(otherColor);\n }\n\n var result = [],\n alpha = this.getAlpha(),\n otherAlpha = 0.5,\n source = this.getSource(),\n otherSource = otherColor.getSource(), i;\n\n for (i = 0; i < 3; i++) {\n result.push(Math.round((source[i] * (1 - otherAlpha)) + (otherSource[i] * otherAlpha)));\n }\n\n result[3] = alpha;\n this.setSource(result);\n return this;\n }\n };\n\n /**\n * Regex matching color in RGB or RGBA formats (ex: rgb(0, 0, 0), rgba(255, 100, 10, 0.5), rgba( 255 , 100 , 10 , 0.5 ), rgb(1,1,1), rgba(100%, 60%, 10%, 0.5))\n * @static\n * @field\n * @memberOf fabric.Color\n */\n // eslint-disable-next-line max-len\n fabric.Color.reRGBa = /^rgba?\\(\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*,\\s*(\\d{1,3}(?:\\.\\d+)?\\%?)\\s*(?:\\s*,\\s*((?:\\d*\\.?\\d+)?)\\s*)?\\)$/i;\n\n /**\n * Regex matching color in HSL or HSLA formats (ex: hsl(200, 80%, 10%), hsla(300, 50%, 80%, 0.5), hsla( 300 , 50% , 80% , 0.5 ))\n * @static\n * @field\n * @memberOf fabric.Color\n */\n fabric.Color.reHSLa = /^hsla?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3}\\%)\\s*,\\s*(\\d{1,3}\\%)\\s*(?:\\s*,\\s*(\\d+(?:\\.\\d+)?)\\s*)?\\)$/i;\n\n /**\n * Regex matching color in HEX format (ex: #FF5544CC, #FF5555, 010155, aff)\n * @static\n * @field\n * @memberOf fabric.Color\n */\n fabric.Color.reHex = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i;\n\n /**\n * Map of the 148 color names with HEX code\n * @static\n * @field\n * @memberOf fabric.Color\n * @see: https://www.w3.org/TR/css3-color/#svg-color\n */\n fabric.Color.colorNameMap = {\n aliceblue: '#F0F8FF',\n antiquewhite: '#FAEBD7',\n aqua: '#00FFFF',\n aquamarine: '#7FFFD4',\n azure: '#F0FFFF',\n beige: '#F5F5DC',\n bisque: '#FFE4C4',\n black: '#000000',\n blanchedalmond: '#FFEBCD',\n blue: '#0000FF',\n blueviolet: '#8A2BE2',\n brown: '#A52A2A',\n burlywood: '#DEB887',\n cadetblue: '#5F9EA0',\n chartreuse: '#7FFF00',\n chocolate: '#D2691E',\n coral: '#FF7F50',\n cornflowerblue: '#6495ED',\n cornsilk: '#FFF8DC',\n crimson: '#DC143C',\n cyan: '#00FFFF',\n darkblue: '#00008B',\n darkcyan: '#008B8B',\n darkgoldenrod: '#B8860B',\n darkgray: '#A9A9A9',\n darkgrey: '#A9A9A9',\n darkgreen: '#006400',\n darkkhaki: '#BDB76B',\n darkmagenta: '#8B008B',\n darkolivegreen: '#556B2F',\n darkorange: '#FF8C00',\n darkorchid: '#9932CC',\n darkred: '#8B0000',\n darksalmon: '#E9967A',\n darkseagreen: '#8FBC8F',\n darkslateblue: '#483D8B',\n darkslategray: '#2F4F4F',\n darkslategrey: '#2F4F4F',\n darkturquoise: '#00CED1',\n darkviolet: '#9400D3',\n deeppink: '#FF1493',\n deepskyblue: '#00BFFF',\n dimgray: '#696969',\n dimgrey: '#696969',\n dodgerblue: '#1E90FF',\n firebrick: '#B22222',\n floralwhite: '#FFFAF0',\n forestgreen: '#228B22',\n fuchsia: '#FF00FF',\n gainsboro: '#DCDCDC',\n ghostwhite: '#F8F8FF',\n gold: '#FFD700',\n goldenrod: '#DAA520',\n gray: '#808080',\n grey: '#808080',\n green: '#008000',\n greenyellow: '#ADFF2F',\n honeydew: '#F0FFF0',\n hotpink: '#FF69B4',\n indianred: '#CD5C5C',\n indigo: '#4B0082',\n ivory: '#FFFFF0',\n khaki: '#F0E68C',\n lavender: '#E6E6FA',\n lavenderblush: '#FFF0F5',\n lawngreen: '#7CFC00',\n lemonchiffon: '#FFFACD',\n lightblue: '#ADD8E6',\n lightcoral: '#F08080',\n lightcyan: '#E0FFFF',\n lightgoldenrodyellow: '#FAFAD2',\n lightgray: '#D3D3D3',\n lightgrey: '#D3D3D3',\n lightgreen: '#90EE90',\n lightpink: '#FFB6C1',\n lightsalmon: '#FFA07A',\n lightseagreen: '#20B2AA',\n lightskyblue: '#87CEFA',\n lightslategray: '#778899',\n lightslategrey: '#778899',\n lightsteelblue: '#B0C4DE',\n lightyellow: '#FFFFE0',\n lime: '#00FF00',\n limegreen: '#32CD32',\n linen: '#FAF0E6',\n magenta: '#FF00FF',\n maroon: '#800000',\n mediumaquamarine: '#66CDAA',\n mediumblue: '#0000CD',\n mediumorchid: '#BA55D3',\n mediumpurple: '#9370DB',\n mediumseagreen: '#3CB371',\n mediumslateblue: '#7B68EE',\n mediumspringgreen: '#00FA9A',\n mediumturquoise: '#48D1CC',\n mediumvioletred: '#C71585',\n midnightblue: '#191970',\n mintcream: '#F5FFFA',\n mistyrose: '#FFE4E1',\n moccasin: '#FFE4B5',\n navajowhite: '#FFDEAD',\n navy: '#000080',\n oldlace: '#FDF5E6',\n olive: '#808000',\n olivedrab: '#6B8E23',\n orange: '#FFA500',\n orangered: '#FF4500',\n orchid: '#DA70D6',\n palegoldenrod: '#EEE8AA',\n palegreen: '#98FB98',\n paleturquoise: '#AFEEEE',\n palevioletred: '#DB7093',\n papayawhip: '#FFEFD5',\n peachpuff: '#FFDAB9',\n peru: '#CD853F',\n pink: '#FFC0CB',\n plum: '#DDA0DD',\n powderblue: '#B0E0E6',\n purple: '#800080',\n rebeccapurple: '#663399',\n red: '#FF0000',\n rosybrown: '#BC8F8F',\n royalblue: '#4169E1',\n saddlebrown: '#8B4513',\n salmon: '#FA8072',\n sandybrown: '#F4A460',\n seagreen: '#2E8B57',\n seashell: '#FFF5EE',\n sienna: '#A0522D',\n silver: '#C0C0C0',\n skyblue: '#87CEEB',\n slateblue: '#6A5ACD',\n slategray: '#708090',\n slategrey: '#708090',\n snow: '#FFFAFA',\n springgreen: '#00FF7F',\n steelblue: '#4682B4',\n tan: '#D2B48C',\n teal: '#008080',\n thistle: '#D8BFD8',\n tomato: '#FF6347',\n turquoise: '#40E0D0',\n violet: '#EE82EE',\n wheat: '#F5DEB3',\n white: '#FFFFFF',\n whitesmoke: '#F5F5F5',\n yellow: '#FFFF00',\n yellowgreen: '#9ACD32'\n };\n\n /**\n * @private\n * @param {Number} p\n * @param {Number} q\n * @param {Number} t\n * @return {Number}\n */\n function hue2rgb(p, q, t) {\n if (t < 0) {\n t += 1;\n }\n if (t > 1) {\n t -= 1;\n }\n if (t < 1 / 6) {\n return p + (q - p) * 6 * t;\n }\n if (t < 1 / 2) {\n return q;\n }\n if (t < 2 / 3) {\n return p + (q - p) * (2 / 3 - t) * 6;\n }\n return p;\n }\n\n /**\n * Returns new color object, when given a color in RGB format\n * @memberOf fabric.Color\n * @param {String} color Color value ex: rgb(0-255,0-255,0-255)\n * @return {fabric.Color}\n */\n fabric.Color.fromRgb = function(color) {\n return Color.fromSource(Color.sourceFromRgb(color));\n };\n\n /**\n * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in RGB or RGBA format\n * @memberOf fabric.Color\n * @param {String} color Color value ex: rgb(0-255,0-255,0-255), rgb(0%-100%,0%-100%,0%-100%)\n * @return {Array} source\n */\n fabric.Color.sourceFromRgb = function(color) {\n var match = color.match(Color.reRGBa);\n if (match) {\n var r = parseInt(match[1], 10) / (/%$/.test(match[1]) ? 100 : 1) * (/%$/.test(match[1]) ? 255 : 1),\n g = parseInt(match[2], 10) / (/%$/.test(match[2]) ? 100 : 1) * (/%$/.test(match[2]) ? 255 : 1),\n b = parseInt(match[3], 10) / (/%$/.test(match[3]) ? 100 : 1) * (/%$/.test(match[3]) ? 255 : 1);\n\n return [\n parseInt(r, 10),\n parseInt(g, 10),\n parseInt(b, 10),\n match[4] ? parseFloat(match[4]) : 1\n ];\n }\n };\n\n /**\n * Returns new color object, when given a color in RGBA format\n * @static\n * @function\n * @memberOf fabric.Color\n * @param {String} color\n * @return {fabric.Color}\n */\n fabric.Color.fromRgba = Color.fromRgb;\n\n /**\n * Returns new color object, when given a color in HSL format\n * @param {String} color Color value ex: hsl(0-260,0%-100%,0%-100%)\n * @memberOf fabric.Color\n * @return {fabric.Color}\n */\n fabric.Color.fromHsl = function(color) {\n return Color.fromSource(Color.sourceFromHsl(color));\n };\n\n /**\n * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HSL or HSLA format.\n * Adapted from https://github.com/mjijackson\n * @memberOf fabric.Color\n * @param {String} color Color value ex: hsl(0-360,0%-100%,0%-100%) or hsla(0-360,0%-100%,0%-100%, 0-1)\n * @return {Array} source\n * @see http://http://www.w3.org/TR/css3-color/#hsl-color\n */\n fabric.Color.sourceFromHsl = function(color) {\n var match = color.match(Color.reHSLa);\n if (!match) {\n return;\n }\n\n var h = (((parseFloat(match[1]) % 360) + 360) % 360) / 360,\n s = parseFloat(match[2]) / (/%$/.test(match[2]) ? 100 : 1),\n l = parseFloat(match[3]) / (/%$/.test(match[3]) ? 100 : 1),\n r, g, b;\n\n if (s === 0) {\n r = g = b = l;\n }\n else {\n var q = l <= 0.5 ? l * (s + 1) : l + s - l * s,\n p = l * 2 - q;\n\n r = hue2rgb(p, q, h + 1 / 3);\n g = hue2rgb(p, q, h);\n b = hue2rgb(p, q, h - 1 / 3);\n }\n\n return [\n Math.round(r * 255),\n Math.round(g * 255),\n Math.round(b * 255),\n match[4] ? parseFloat(match[4]) : 1\n ];\n };\n\n /**\n * Returns new color object, when given a color in HSLA format\n * @static\n * @function\n * @memberOf fabric.Color\n * @param {String} color\n * @return {fabric.Color}\n */\n fabric.Color.fromHsla = Color.fromHsl;\n\n /**\n * Returns new color object, when given a color in HEX format\n * @static\n * @memberOf fabric.Color\n * @param {String} color Color value ex: FF5555\n * @return {fabric.Color}\n */\n fabric.Color.fromHex = function(color) {\n return Color.fromSource(Color.sourceFromHex(color));\n };\n\n /**\n * Returns array representation (ex: [100, 100, 200, 1]) of a color that's in HEX format\n * @static\n * @memberOf fabric.Color\n * @param {String} color ex: FF5555 or FF5544CC (RGBa)\n * @return {Array} source\n */\n fabric.Color.sourceFromHex = function(color) {\n if (color.match(Color.reHex)) {\n var value = color.slice(color.indexOf('#') + 1),\n isShortNotation = (value.length === 3 || value.length === 4),\n isRGBa = (value.length === 8 || value.length === 4),\n r = isShortNotation ? (value.charAt(0) + value.charAt(0)) : value.substring(0, 2),\n g = isShortNotation ? (value.charAt(1) + value.charAt(1)) : value.substring(2, 4),\n b = isShortNotation ? (value.charAt(2) + value.charAt(2)) : value.substring(4, 6),\n a = isRGBa ? (isShortNotation ? (value.charAt(3) + value.charAt(3)) : value.substring(6, 8)) : 'FF';\n\n return [\n parseInt(r, 16),\n parseInt(g, 16),\n parseInt(b, 16),\n parseFloat((parseInt(a, 16) / 255).toFixed(2))\n ];\n }\n };\n\n /**\n * Returns new color object, when given color in array representation (ex: [200, 100, 100, 0.5])\n * @static\n * @memberOf fabric.Color\n * @param {Array} source\n * @return {fabric.Color}\n */\n fabric.Color.fromSource = function(source) {\n var oColor = new Color();\n oColor.setSource(source);\n return oColor;\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n scaleMap = ['e', 'se', 's', 'sw', 'w', 'nw', 'n', 'ne', 'e'],\n skewMap = ['ns', 'nesw', 'ew', 'nwse'],\n controls = {},\n LEFT = 'left', TOP = 'top', RIGHT = 'right', BOTTOM = 'bottom', CENTER = 'center',\n opposite = {\n top: BOTTOM,\n bottom: TOP,\n left: RIGHT,\n right: LEFT,\n center: CENTER,\n }, radiansToDegrees = fabric.util.radiansToDegrees,\n sign = (Math.sign || function(x) { return ((x > 0) - (x < 0)) || +x; });\n\n /**\n * Combine control position and object angle to find the control direction compared\n * to the object center.\n * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls\n * @param {fabric.Control} control the control class\n * @return {Number} 0 - 7 a quadrant number\n */\n function findCornerQuadrant(fabricObject, control) {\n var cornerAngle = fabricObject.angle + radiansToDegrees(Math.atan2(control.y, control.x)) + 360;\n return Math.round((cornerAngle % 360) / 45);\n }\n\n function fireEvent(eventName, options) {\n var target = options.transform.target,\n canvas = target.canvas,\n canvasOptions = fabric.util.object.clone(options);\n canvasOptions.target = target;\n canvas && canvas.fire('object:' + eventName, canvasOptions);\n target.fire(eventName, options);\n }\n\n /**\n * Inspect event and fabricObject properties to understand if the scaling action\n * @param {Event} eventData from the user action\n * @param {fabric.Object} fabricObject the fabric object about to scale\n * @return {Boolean} true if scale is proportional\n */\n function scaleIsProportional(eventData, fabricObject) {\n var canvas = fabricObject.canvas, uniScaleKey = canvas.uniScaleKey,\n uniformIsToggled = eventData[uniScaleKey];\n return (canvas.uniformScaling && !uniformIsToggled) ||\n (!canvas.uniformScaling && uniformIsToggled);\n }\n\n /**\n * Checks if transform is centered\n * @param {Object} transform transform data\n * @return {Boolean} true if transform is centered\n */\n function isTransformCentered(transform) {\n return transform.originX === CENTER && transform.originY === CENTER;\n }\n\n /**\n * Inspect fabricObject to understand if the current scaling action is allowed\n * @param {fabric.Object} fabricObject the fabric object about to scale\n * @param {String} by 'x' or 'y' or ''\n * @param {Boolean} scaleProportionally true if we are trying to scale proportionally\n * @return {Boolean} true if scaling is not allowed at current conditions\n */\n function scalingIsForbidden(fabricObject, by, scaleProportionally) {\n var lockX = fabricObject.lockScalingX, lockY = fabricObject.lockScalingY;\n if (lockX && lockY) {\n return true;\n }\n if (!by && (lockX || lockY) && scaleProportionally) {\n return true;\n }\n if (lockX && by === 'x') {\n return true;\n }\n if (lockY && by === 'y') {\n return true;\n }\n return false;\n }\n\n /**\n * return the correct cursor style for the scale action\n * @param {Event} eventData the javascript event that is causing the scale\n * @param {fabric.Control} control the control that is interested in the action\n * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n * @return {String} a valid css string for the cursor\n */\n function scaleCursorStyleHandler(eventData, control, fabricObject) {\n var notAllowed = 'not-allowed',\n scaleProportionally = scaleIsProportional(eventData, fabricObject),\n by = '';\n if (control.x !== 0 && control.y === 0) {\n by = 'x';\n }\n else if (control.x === 0 && control.y !== 0) {\n by = 'y';\n }\n if (scalingIsForbidden(fabricObject, by, scaleProportionally)) {\n return notAllowed;\n }\n var n = findCornerQuadrant(fabricObject, control);\n return scaleMap[n] + '-resize';\n }\n\n /**\n * return the correct cursor style for the skew action\n * @param {Event} eventData the javascript event that is causing the scale\n * @param {fabric.Control} control the control that is interested in the action\n * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n * @return {String} a valid css string for the cursor\n */\n function skewCursorStyleHandler(eventData, control, fabricObject) {\n var notAllowed = 'not-allowed';\n if (control.x !== 0 && fabricObject.lockSkewingY) {\n return notAllowed;\n }\n if (control.y !== 0 && fabricObject.lockSkewingX) {\n return notAllowed;\n }\n var n = findCornerQuadrant(fabricObject, control) % 4;\n return skewMap[n] + '-resize';\n }\n\n /**\n * Combine skew and scale style handlers to cover fabric standard use case\n * @param {Event} eventData the javascript event that is causing the scale\n * @param {fabric.Control} control the control that is interested in the action\n * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n * @return {String} a valid css string for the cursor\n */\n function scaleSkewCursorStyleHandler(eventData, control, fabricObject) {\n if (eventData[fabricObject.canvas.altActionKey]) {\n return controls.skewCursorStyleHandler(eventData, control, fabricObject);\n }\n return controls.scaleCursorStyleHandler(eventData, control, fabricObject);\n }\n\n /**\n * Inspect event, control and fabricObject to return the correct action name\n * @param {Event} eventData the javascript event that is causing the scale\n * @param {fabric.Control} control the control that is interested in the action\n * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n * @return {String} an action name\n */\n function scaleOrSkewActionName(eventData, control, fabricObject) {\n var isAlternative = eventData[fabricObject.canvas.altActionKey];\n if (control.x === 0) {\n // then is scaleY or skewX\n return isAlternative ? 'skewX' : 'scaleY';\n }\n if (control.y === 0) {\n // then is scaleY or skewX\n return isAlternative ? 'skewY' : 'scaleX';\n }\n }\n\n /**\n * Find the correct style for the control that is used for rotation.\n * this function is very simple and it just take care of not-allowed or standard cursor\n * @param {Event} eventData the javascript event that is causing the scale\n * @param {fabric.Control} control the control that is interested in the action\n * @param {fabric.Object} fabricObject the fabric object that is interested in the action\n * @return {String} a valid css string for the cursor\n */\n function rotationStyleHandler(eventData, control, fabricObject) {\n if (fabricObject.lockRotation) {\n return 'not-allowed';\n }\n return control.cursorStyle;\n }\n\n function commonEventInfo(eventData, transform, x, y) {\n return {\n e: eventData,\n transform: transform,\n pointer: {\n x: x,\n y: y,\n }\n };\n }\n\n /**\n * Wrap an action handler with saving/restoring object position on the transform.\n * this is the code that permits to objects to keep their position while transforming.\n * @param {Function} actionHandler the function to wrap\n * @return {Function} a function with an action handler signature\n */\n function wrapWithFixedAnchor(actionHandler) {\n return function(eventData, transform, x, y) {\n var target = transform.target, centerPoint = target.getCenterPoint(),\n constraint = target.translateToOriginPoint(centerPoint, transform.originX, transform.originY),\n actionPerformed = actionHandler(eventData, transform, x, y);\n target.setPositionByOrigin(constraint, transform.originX, transform.originY);\n return actionPerformed;\n };\n }\n\n /**\n * Wrap an action handler with firing an event if the action is performed\n * @param {Function} actionHandler the function to wrap\n * @return {Function} a function with an action handler signature\n */\n function wrapWithFireEvent(eventName, actionHandler) {\n return function(eventData, transform, x, y) {\n var actionPerformed = actionHandler(eventData, transform, x, y);\n if (actionPerformed) {\n fireEvent(eventName, commonEventInfo(eventData, transform, x, y));\n }\n return actionPerformed;\n };\n }\n\n /**\n * Transforms a point described by x and y in a distance from the top left corner of the object\n * bounding box.\n * @param {Object} transform\n * @param {String} originX\n * @param {String} originY\n * @param {number} x\n * @param {number} y\n * @return {Fabric.Point} the normalized point\n */\n function getLocalPoint(transform, originX, originY, x, y) {\n var target = transform.target,\n control = target.controls[transform.corner],\n zoom = target.canvas.getZoom(),\n padding = target.padding / zoom,\n localPoint = target.toLocalPoint(new fabric.Point(x, y), originX, originY);\n if (localPoint.x >= padding) {\n localPoint.x -= padding;\n }\n if (localPoint.x <= -padding) {\n localPoint.x += padding;\n }\n if (localPoint.y >= padding) {\n localPoint.y -= padding;\n }\n if (localPoint.y <= padding) {\n localPoint.y += padding;\n }\n localPoint.x -= control.offsetX;\n localPoint.y -= control.offsetY;\n return localPoint;\n }\n\n /**\n * Detect if the fabric object is flipped on one side.\n * @param {fabric.Object} target\n * @return {Boolean} true if one flip, but not two.\n */\n function targetHasOneFlip(target) {\n return target.flipX !== target.flipY;\n }\n\n /**\n * Utility function to compensate the scale factor when skew is applied on both axes\n * @private\n */\n function compensateScaleForSkew(target, oppositeSkew, scaleToCompensate, axis, reference) {\n if (target[oppositeSkew] !== 0) {\n var newDim = target._getTransformedDimensions()[axis];\n var newValue = reference / newDim * target[scaleToCompensate];\n target.set(scaleToCompensate, newValue);\n }\n }\n\n /**\n * Action handler for skewing on the X axis\n * @private\n */\n function skewObjectX(eventData, transform, x, y) {\n var target = transform.target,\n // find how big the object would be, if there was no skewX. takes in account scaling\n dimNoSkew = target._getTransformedDimensions(0, target.skewY),\n localPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y),\n // the mouse is in the center of the object, and we want it to stay there.\n // so the object will grow twice as much as the mouse.\n // this makes the skew growth to localPoint * 2 - dimNoSkew.\n totalSkewSize = Math.abs(localPoint.x * 2) - dimNoSkew.x,\n currentSkew = target.skewX, newSkew;\n if (totalSkewSize < 2) {\n // let's make it easy to go back to position 0.\n newSkew = 0;\n }\n else {\n newSkew = radiansToDegrees(\n Math.atan2((totalSkewSize / target.scaleX), (dimNoSkew.y / target.scaleY))\n );\n // now we have to find the sign of the skew.\n // it mostly depend on the origin of transformation.\n if (transform.originX === LEFT && transform.originY === BOTTOM) {\n newSkew = -newSkew;\n }\n if (transform.originX === RIGHT && transform.originY === TOP) {\n newSkew = -newSkew;\n }\n if (targetHasOneFlip(target)) {\n newSkew = -newSkew;\n }\n }\n var hasSkewed = currentSkew !== newSkew;\n if (hasSkewed) {\n var dimBeforeSkewing = target._getTransformedDimensions().y;\n target.set('skewX', newSkew);\n compensateScaleForSkew(target, 'skewY', 'scaleY', 'y', dimBeforeSkewing);\n }\n return hasSkewed;\n }\n\n /**\n * Action handler for skewing on the Y axis\n * @private\n */\n function skewObjectY(eventData, transform, x, y) {\n var target = transform.target,\n // find how big the object would be, if there was no skewX. takes in account scaling\n dimNoSkew = target._getTransformedDimensions(target.skewX, 0),\n localPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y),\n // the mouse is in the center of the object, and we want it to stay there.\n // so the object will grow twice as much as the mouse.\n // this makes the skew growth to localPoint * 2 - dimNoSkew.\n totalSkewSize = Math.abs(localPoint.y * 2) - dimNoSkew.y,\n currentSkew = target.skewY, newSkew;\n if (totalSkewSize < 2) {\n // let's make it easy to go back to position 0.\n newSkew = 0;\n }\n else {\n newSkew = radiansToDegrees(\n Math.atan2((totalSkewSize / target.scaleY), (dimNoSkew.x / target.scaleX))\n );\n // now we have to find the sign of the skew.\n // it mostly depend on the origin of transformation.\n if (transform.originX === LEFT && transform.originY === BOTTOM) {\n newSkew = -newSkew;\n }\n if (transform.originX === RIGHT && transform.originY === TOP) {\n newSkew = -newSkew;\n }\n if (targetHasOneFlip(target)) {\n newSkew = -newSkew;\n }\n }\n var hasSkewed = currentSkew !== newSkew;\n if (hasSkewed) {\n var dimBeforeSkewing = target._getTransformedDimensions().x;\n target.set('skewY', newSkew);\n compensateScaleForSkew(target, 'skewX', 'scaleX', 'x', dimBeforeSkewing);\n }\n return hasSkewed;\n }\n\n /**\n * Wrapped Action handler for skewing on the Y axis, takes care of the\n * skew direction and determine the correct transform origin for the anchor point\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function skewHandlerX(eventData, transform, x, y) {\n // step1 figure out and change transform origin.\n // if skewX > 0 and originY bottom we anchor on right\n // if skewX > 0 and originY top we anchor on left\n // if skewX < 0 and originY bottom we anchor on left\n // if skewX < 0 and originY top we anchor on right\n // if skewX is 0, we look for mouse position to understand where are we going.\n var target = transform.target, currentSkew = target.skewX, originX, originY = transform.originY;\n if (target.lockSkewingX) {\n return false;\n }\n if (currentSkew === 0) {\n var localPointFromCenter = getLocalPoint(transform, CENTER, CENTER, x, y);\n if (localPointFromCenter.x > 0) {\n // we are pulling right, anchor left;\n originX = LEFT;\n }\n else {\n // we are pulling right, anchor right\n originX = RIGHT;\n }\n }\n else {\n if (currentSkew > 0) {\n originX = originY === TOP ? LEFT : RIGHT;\n }\n if (currentSkew < 0) {\n originX = originY === TOP ? RIGHT : LEFT;\n }\n // is the object flipped on one side only? swap the origin.\n if (targetHasOneFlip(target)) {\n originX = originX === LEFT ? RIGHT : LEFT;\n }\n }\n\n // once we have the origin, we find the anchor point\n transform.originX = originX;\n var finalHandler = wrapWithFireEvent('skewing', wrapWithFixedAnchor(skewObjectX));\n return finalHandler(eventData, transform, x, y);\n }\n\n /**\n * Wrapped Action handler for skewing on the Y axis, takes care of the\n * skew direction and determine the correct transform origin for the anchor point\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function skewHandlerY(eventData, transform, x, y) {\n // step1 figure out and change transform origin.\n // if skewY > 0 and originX left we anchor on top\n // if skewY > 0 and originX right we anchor on bottom\n // if skewY < 0 and originX left we anchor on bottom\n // if skewY < 0 and originX right we anchor on top\n // if skewY is 0, we look for mouse position to understand where are we going.\n var target = transform.target, currentSkew = target.skewY, originY, originX = transform.originX;\n if (target.lockSkewingY) {\n return false;\n }\n if (currentSkew === 0) {\n var localPointFromCenter = getLocalPoint(transform, CENTER, CENTER, x, y);\n if (localPointFromCenter.y > 0) {\n // we are pulling down, anchor up;\n originY = TOP;\n }\n else {\n // we are pulling up, anchor down\n originY = BOTTOM;\n }\n }\n else {\n if (currentSkew > 0) {\n originY = originX === LEFT ? TOP : BOTTOM;\n }\n if (currentSkew < 0) {\n originY = originX === LEFT ? BOTTOM : TOP;\n }\n // is the object flipped on one side only? swap the origin.\n if (targetHasOneFlip(target)) {\n originY = originY === TOP ? BOTTOM : TOP;\n }\n }\n\n // once we have the origin, we find the anchor point\n transform.originY = originY;\n var finalHandler = wrapWithFireEvent('skewing', wrapWithFixedAnchor(skewObjectY));\n return finalHandler(eventData, transform, x, y);\n }\n\n /**\n * Action handler for rotation and snapping, without anchor point.\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n * @private\n */\n function rotationWithSnapping(eventData, transform, x, y) {\n var t = transform,\n target = t.target,\n pivotPoint = target.translateToOriginPoint(target.getCenterPoint(), t.originX, t.originY);\n\n if (target.lockRotation) {\n return false;\n }\n\n var lastAngle = Math.atan2(t.ey - pivotPoint.y, t.ex - pivotPoint.x),\n curAngle = Math.atan2(y - pivotPoint.y, x - pivotPoint.x),\n angle = radiansToDegrees(curAngle - lastAngle + t.theta),\n hasRotated = true;\n\n if (target.snapAngle > 0) {\n var snapAngle = target.snapAngle,\n snapThreshold = target.snapThreshold || snapAngle,\n rightAngleLocked = Math.ceil(angle / snapAngle) * snapAngle,\n leftAngleLocked = Math.floor(angle / snapAngle) * snapAngle;\n\n if (Math.abs(angle - leftAngleLocked) < snapThreshold) {\n angle = leftAngleLocked;\n }\n else if (Math.abs(angle - rightAngleLocked) < snapThreshold) {\n angle = rightAngleLocked;\n }\n }\n\n // normalize angle to positive value\n if (angle < 0) {\n angle = 360 + angle;\n }\n angle %= 360;\n\n hasRotated = target.angle !== angle;\n target.angle = angle;\n return hasRotated;\n }\n\n /**\n * Basic scaling logic, reused with different constrain for scaling X,Y, freely or equally.\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @param {Object} options additional information for scaling\n * @param {String} options.by 'x', 'y', 'equally' or '' to indicate type of scaling\n * @return {Boolean} true if some change happened\n * @private\n */\n function scaleObject(eventData, transform, x, y, options) {\n options = options || {};\n var target = transform.target,\n lockScalingX = target.lockScalingX, lockScalingY = target.lockScalingY,\n by = options.by, newPoint, scaleX, scaleY, dim,\n scaleProportionally = scaleIsProportional(eventData, target),\n forbidScaling = scalingIsForbidden(target, by, scaleProportionally),\n signX, signY, gestureScale = transform.gestureScale;\n\n if (forbidScaling) {\n return false;\n }\n if (gestureScale) {\n scaleX = transform.scaleX * gestureScale;\n scaleY = transform.scaleY * gestureScale;\n }\n else {\n newPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y);\n // use of sign: We use sign to detect change of direction of an action. sign usually change when\n // we cross the origin point with the mouse. So a scale flip for example. There is an issue when scaling\n // by center and scaling using one middle control ( default: mr, mt, ml, mb), the mouse movement can easily\n // cross many time the origin point and flip the object. so we need a way to filter out the noise.\n // This ternary here should be ok to filter out X scaling when we want Y only and vice versa.\n signX = by !== 'y' ? sign(newPoint.x) : 1;\n signY = by !== 'x' ? sign(newPoint.y) : 1;\n if (!transform.signX) {\n transform.signX = signX;\n }\n if (!transform.signY) {\n transform.signY = signY;\n }\n\n if (target.lockScalingFlip &&\n (transform.signX !== signX || transform.signY !== signY)\n ) {\n return false;\n }\n\n dim = target._getTransformedDimensions();\n // missing detection of flip and logic to switch the origin\n if (scaleProportionally && !by) {\n // uniform scaling\n var distance = Math.abs(newPoint.x) + Math.abs(newPoint.y),\n original = transform.original,\n originalDistance = Math.abs(dim.x * original.scaleX / target.scaleX) +\n Math.abs(dim.y * original.scaleY / target.scaleY),\n scale = distance / originalDistance;\n scaleX = original.scaleX * scale;\n scaleY = original.scaleY * scale;\n }\n else {\n scaleX = Math.abs(newPoint.x * target.scaleX / dim.x);\n scaleY = Math.abs(newPoint.y * target.scaleY / dim.y);\n }\n // if we are scaling by center, we need to double the scale\n if (isTransformCentered(transform)) {\n scaleX *= 2;\n scaleY *= 2;\n }\n if (transform.signX !== signX && by !== 'y') {\n transform.originX = opposite[transform.originX];\n scaleX *= -1;\n transform.signX = signX;\n }\n if (transform.signY !== signY && by !== 'x') {\n transform.originY = opposite[transform.originY];\n scaleY *= -1;\n transform.signY = signY;\n }\n }\n // minScale is taken are in the setter.\n var oldScaleX = target.scaleX, oldScaleY = target.scaleY;\n if (!by) {\n !lockScalingX && target.set('scaleX', scaleX);\n !lockScalingY && target.set('scaleY', scaleY);\n }\n else {\n // forbidden cases already handled on top here.\n by === 'x' && target.set('scaleX', scaleX);\n by === 'y' && target.set('scaleY', scaleY);\n }\n return oldScaleX !== target.scaleX || oldScaleY !== target.scaleY;\n }\n\n /**\n * Generic scaling logic, to scale from corners either equally or freely.\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function scaleObjectFromCorner(eventData, transform, x, y) {\n return scaleObject(eventData, transform, x, y);\n }\n\n /**\n * Scaling logic for the X axis.\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function scaleObjectX(eventData, transform, x, y) {\n return scaleObject(eventData, transform, x, y , { by: 'x' });\n }\n\n /**\n * Scaling logic for the Y axis.\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function scaleObjectY(eventData, transform, x, y) {\n return scaleObject(eventData, transform, x, y , { by: 'y' });\n }\n\n /**\n * Composed action handler to either scale Y or skew X\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function scalingYOrSkewingX(eventData, transform, x, y) {\n // ok some safety needed here.\n if (eventData[transform.target.canvas.altActionKey]) {\n return controls.skewHandlerX(eventData, transform, x, y);\n }\n return controls.scalingY(eventData, transform, x, y);\n }\n\n /**\n * Composed action handler to either scale X or skew Y\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function scalingXOrSkewingY(eventData, transform, x, y) {\n // ok some safety needed here.\n if (eventData[transform.target.canvas.altActionKey]) {\n return controls.skewHandlerY(eventData, transform, x, y);\n }\n return controls.scalingX(eventData, transform, x, y);\n }\n\n /**\n * Action handler to change textbox width\n * Needs to be wrapped with `wrapWithFixedAnchor` to be effective\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if some change happened\n */\n function changeWidth(eventData, transform, x, y) {\n var target = transform.target, localPoint = getLocalPoint(transform, transform.originX, transform.originY, x, y),\n strokePadding = target.strokeWidth / (target.strokeUniform ? target.scaleX : 1),\n multiplier = isTransformCentered(transform) ? 2 : 1,\n oldWidth = target.width,\n newWidth = Math.abs(localPoint.x * multiplier / target.scaleX) - strokePadding;\n target.set('width', Math.max(newWidth, 0));\n return oldWidth !== newWidth;\n }\n\n /**\n * Action handler\n * @private\n * @param {Event} eventData javascript event that is doing the transform\n * @param {Object} transform javascript object containing a series of information around the current transform\n * @param {number} x current mouse x position, canvas normalized\n * @param {number} y current mouse y position, canvas normalized\n * @return {Boolean} true if the translation occurred\n */\n function dragHandler(eventData, transform, x, y) {\n var target = transform.target,\n newLeft = x - transform.offsetX,\n newTop = y - transform.offsetY,\n moveX = !target.get('lockMovementX') && target.left !== newLeft,\n moveY = !target.get('lockMovementY') && target.top !== newTop;\n moveX && target.set('left', newLeft);\n moveY && target.set('top', newTop);\n if (moveX || moveY) {\n fireEvent('moving', commonEventInfo(eventData, transform, x, y));\n }\n return moveX || moveY;\n }\n\n controls.scaleCursorStyleHandler = scaleCursorStyleHandler;\n controls.skewCursorStyleHandler = skewCursorStyleHandler;\n controls.scaleSkewCursorStyleHandler = scaleSkewCursorStyleHandler;\n controls.rotationWithSnapping = wrapWithFireEvent('rotating', wrapWithFixedAnchor(rotationWithSnapping));\n controls.scalingEqually = wrapWithFireEvent('scaling', wrapWithFixedAnchor( scaleObjectFromCorner));\n controls.scalingX = wrapWithFireEvent('scaling', wrapWithFixedAnchor(scaleObjectX));\n controls.scalingY = wrapWithFireEvent('scaling', wrapWithFixedAnchor(scaleObjectY));\n controls.scalingYOrSkewingX = scalingYOrSkewingX;\n controls.scalingXOrSkewingY = scalingXOrSkewingY;\n controls.changeWidth = wrapWithFireEvent('resizing', wrapWithFixedAnchor(changeWidth));\n controls.skewHandlerX = skewHandlerX;\n controls.skewHandlerY = skewHandlerY;\n controls.dragHandler = dragHandler;\n controls.scaleOrSkewActionName = scaleOrSkewActionName;\n controls.rotationStyleHandler = rotationStyleHandler;\n controls.fireEvent = fireEvent;\n controls.wrapWithFixedAnchor = wrapWithFixedAnchor;\n controls.wrapWithFireEvent = wrapWithFireEvent;\n controls.getLocalPoint = getLocalPoint;\n fabric.controlsUtils = controls;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n degreesToRadians = fabric.util.degreesToRadians,\n controls = fabric.controlsUtils;\n\n /**\n * Render a round control, as per fabric features.\n * This function is written to respect object properties like transparentCorners, cornerSize\n * cornerColor, cornerStrokeColor\n * plus the addition of offsetY and offsetX.\n * @param {CanvasRenderingContext2D} ctx context to render on\n * @param {Number} left x coordinate where the control center should be\n * @param {Number} top y coordinate where the control center should be\n * @param {Object} styleOverride override for fabric.Object controls style\n * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls\n */\n function renderCircleControl (ctx, left, top, styleOverride, fabricObject) {\n styleOverride = styleOverride || {};\n var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\n transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ?\n styleOverride.transparentCorners : fabricObject.transparentCorners,\n methodName = transparentCorners ? 'stroke' : 'fill',\n stroke = !transparentCorners && (styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor),\n myLeft = left,\n myTop = top, size;\n ctx.save();\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor;\n ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor;\n // as soon as fabric react v5, remove ie11, use proper ellipse code.\n if (xSize > ySize) {\n size = xSize;\n ctx.scale(1.0, ySize / xSize);\n myTop = top * xSize / ySize;\n }\n else if (ySize > xSize) {\n size = ySize;\n ctx.scale(xSize / ySize, 1.0);\n myLeft = left * ySize / xSize;\n }\n else {\n size = xSize;\n }\n // this is still wrong\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.arc(myLeft, myTop, size / 2, 0, 2 * Math.PI, false);\n ctx[methodName]();\n if (stroke) {\n ctx.stroke();\n }\n ctx.restore();\n }\n\n /**\n * Render a square control, as per fabric features.\n * This function is written to respect object properties like transparentCorners, cornerSize\n * cornerColor, cornerStrokeColor\n * plus the addition of offsetY and offsetX.\n * @param {CanvasRenderingContext2D} ctx context to render on\n * @param {Number} left x coordinate where the control center should be\n * @param {Number} top y coordinate where the control center should be\n * @param {Object} styleOverride override for fabric.Object controls style\n * @param {fabric.Object} fabricObject the fabric object for which we are rendering controls\n */\n function renderSquareControl(ctx, left, top, styleOverride, fabricObject) {\n styleOverride = styleOverride || {};\n var xSize = this.sizeX || styleOverride.cornerSize || fabricObject.cornerSize,\n ySize = this.sizeY || styleOverride.cornerSize || fabricObject.cornerSize,\n transparentCorners = typeof styleOverride.transparentCorners !== 'undefined' ?\n styleOverride.transparentCorners : fabricObject.transparentCorners,\n methodName = transparentCorners ? 'stroke' : 'fill',\n stroke = !transparentCorners && (\n styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor\n ), xSizeBy2 = xSize / 2, ySizeBy2 = ySize / 2;\n ctx.save();\n ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor;\n ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor;\n // this is still wrong\n ctx.lineWidth = 1;\n ctx.translate(left, top);\n ctx.rotate(degreesToRadians(fabricObject.angle));\n // this does not work, and fixed with ( && ) does not make sense.\n // to have real transparent corners we need the controls on upperCanvas\n // transparentCorners || ctx.clearRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\n ctx[methodName + 'Rect'](-xSizeBy2, -ySizeBy2, xSize, ySize);\n if (stroke) {\n ctx.strokeRect(-xSizeBy2, -ySizeBy2, xSize, ySize);\n }\n ctx.restore();\n }\n\n controls.renderCircleControl = renderCircleControl;\n controls.renderSquareControl = renderSquareControl;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { });\n\n function Control(options) {\n for (var i in options) {\n this[i] = options[i];\n }\n }\n\n fabric.Control = Control;\n\n fabric.Control.prototype = /** @lends fabric.Control.prototype */ {\n\n /**\n * keep track of control visibility.\n * mainly for backward compatibility.\n * if you do not want to see a control, you can remove it\n * from the controlset.\n * @type {Boolean}\n * @default true\n */\n visible: true,\n\n /**\n * Name of the action that the control will likely execute.\n * This is optional. FabricJS uses to identify what the user is doing for some\n * extra optimizations. If you are writing a custom control and you want to know\n * somewhere else in the code what is going on, you can use this string here.\n * you can also provide a custom getActionName if your control run multiple actions\n * depending on some external state.\n * default to scale since is the most common, used on 4 corners by default\n * @type {String}\n * @default 'scale'\n */\n actionName: 'scale',\n\n /**\n * Drawing angle of the control.\n * NOT used for now, but name marked as needed for internal logic\n * example: to reuse the same drawing function for different rotated controls\n * @type {Number}\n * @default 0\n */\n angle: 0,\n\n /**\n * Relative position of the control. X\n * 0,0 is the center of the Object, while -0.5 (left) or 0.5 (right) are the extremities\n * of the bounding box.\n * @type {Number}\n * @default 0\n */\n x: 0,\n\n /**\n * Relative position of the control. Y\n * 0,0 is the center of the Object, while -0.5 (top) or 0.5 (bottom) are the extremities\n * of the bounding box.\n * @type {Number}\n * @default 0\n */\n y: 0,\n\n /**\n * Horizontal offset of the control from the defined position. In pixels\n * Positive offset moves the control to the right, negative to the left.\n * It used when you want to have position of control that does not scale with\n * the bounding box. Example: rotation control is placed at x:0, y: 0.5 on\n * the boundindbox, with an offset of 30 pixels vertically. Those 30 pixels will\n * stay 30 pixels no matter how the object is big. Another example is having 2\n * controls in the corner, that stay in the same position when the object scale.\n * of the bounding box.\n * @type {Number}\n * @default 0\n */\n offsetX: 0,\n\n /**\n * Vertical offset of the control from the defined position. In pixels\n * Positive offset moves the control to the bottom, negative to the top.\n * @type {Number}\n * @default 0\n */\n offsetY: 0,\n\n /**\n * Sets the length of the control. If null, defaults to object's cornerSize.\n * Expects both sizeX and sizeY to be set when set.\n * @type {?Number}\n * @default null\n */\n sizeX: null,\n\n /**\n * Sets the height of the control. If null, defaults to object's cornerSize.\n * Expects both sizeX and sizeY to be set when set.\n * @type {?Number}\n * @default null\n */\n sizeY: null,\n\n /**\n * Sets the length of the touch area of the control. If null, defaults to object's touchCornerSize.\n * Expects both touchSizeX and touchSizeY to be set when set.\n * @type {?Number}\n * @default null\n */\n touchSizeX: null,\n\n /**\n * Sets the height of the touch area of the control. If null, defaults to object's touchCornerSize.\n * Expects both touchSizeX and touchSizeY to be set when set.\n * @type {?Number}\n * @default null\n */\n touchSizeY: null,\n\n /**\n * Css cursor style to display when the control is hovered.\n * if the method `cursorStyleHandler` is provided, this property is ignored.\n * @type {String}\n * @default 'crosshair'\n */\n cursorStyle: 'crosshair',\n\n /**\n * If controls has an offsetY or offsetX, draw a line that connects\n * the control to the bounding box\n * @type {Boolean}\n * @default false\n */\n withConnection: false,\n\n /**\n * The control actionHandler, provide one to handle action ( control being moved )\n * @param {Event} eventData the native mouse event\n * @param {Object} transformData properties of the current transform\n * @param {Number} x x position of the cursor\n * @param {Number} y y position of the cursor\n * @return {Boolean} true if the action/event modified the object\n */\n actionHandler: function(/* eventData, transformData, x, y */) { },\n\n /**\n * The control handler for mouse down, provide one to handle mouse down on control\n * @param {Event} eventData the native mouse event\n * @param {Object} transformData properties of the current transform\n * @param {Number} x x position of the cursor\n * @param {Number} y y position of the cursor\n * @return {Boolean} true if the action/event modified the object\n */\n mouseDownHandler: function(/* eventData, transformData, x, y */) { },\n\n /**\n * The control mouseUpHandler, provide one to handle an effect on mouse up.\n * @param {Event} eventData the native mouse event\n * @param {Object} transformData properties of the current transform\n * @param {Number} x x position of the cursor\n * @param {Number} y y position of the cursor\n * @return {Boolean} true if the action/event modified the object\n */\n mouseUpHandler: function(/* eventData, transformData, x, y */) { },\n\n /**\n * Returns control actionHandler\n * @param {Event} eventData the native mouse event\n * @param {fabric.Object} fabricObject on which the control is displayed\n * @param {fabric.Control} control control for which the action handler is being asked\n * @return {Function} the action handler\n */\n getActionHandler: function(/* eventData, fabricObject, control */) {\n return this.actionHandler;\n },\n\n /**\n * Returns control mouseDown handler\n * @param {Event} eventData the native mouse event\n * @param {fabric.Object} fabricObject on which the control is displayed\n * @param {fabric.Control} control control for which the action handler is being asked\n * @return {Function} the action handler\n */\n getMouseDownHandler: function(/* eventData, fabricObject, control */) {\n return this.mouseDownHandler;\n },\n\n /**\n * Returns control mouseUp handler\n * @param {Event} eventData the native mouse event\n * @param {fabric.Object} fabricObject on which the control is displayed\n * @param {fabric.Control} control control for which the action handler is being asked\n * @return {Function} the action handler\n */\n getMouseUpHandler: function(/* eventData, fabricObject, control */) {\n return this.mouseUpHandler;\n },\n\n /**\n * Returns control cursorStyle for css using cursorStyle. If you need a more elaborate\n * function you can pass one in the constructor\n * the cursorStyle property\n * @param {Event} eventData the native mouse event\n * @param {fabric.Control} control the current control ( likely this)\n * @param {fabric.Object} object on which the control is displayed\n * @return {String}\n */\n cursorStyleHandler: function(eventData, control /* fabricObject */) {\n return control.cursorStyle;\n },\n\n /**\n * Returns the action name. The basic implementation just return the actionName property.\n * @param {Event} eventData the native mouse event\n * @param {fabric.Control} control the current control ( likely this)\n * @param {fabric.Object} object on which the control is displayed\n * @return {String}\n */\n getActionName: function(eventData, control /* fabricObject */) {\n return control.actionName;\n },\n\n /**\n * Returns controls visibility\n * @param {fabric.Object} object on which the control is displayed\n * @param {String} controlKey key where the control is memorized on the\n * @return {Boolean}\n */\n getVisibility: function(fabricObject, controlKey) {\n var objectVisibility = fabricObject._controlsVisibility;\n if (objectVisibility && typeof objectVisibility[controlKey] !== 'undefined') {\n return objectVisibility[controlKey];\n }\n return this.visible;\n },\n\n /**\n * Sets controls visibility\n * @param {Boolean} visibility for the object\n * @return {Void}\n */\n setVisibility: function(visibility /* name, fabricObject */) {\n this.visible = visibility;\n },\n\n\n positionHandler: function(dim, finalMatrix /*, fabricObject, currentControl */) {\n var point = fabric.util.transformPoint({\n x: this.x * dim.x + this.offsetX,\n y: this.y * dim.y + this.offsetY }, finalMatrix);\n return point;\n },\n\n /**\n * Returns the coords for this control based on object values.\n * @param {Number} objectAngle angle from the fabric object holding the control\n * @param {Number} objectCornerSize cornerSize from the fabric object holding the control (or touchCornerSize if\n * isTouch is true)\n * @param {Number} centerX x coordinate where the control center should be\n * @param {Number} centerY y coordinate where the control center should be\n * @param {boolean} isTouch true if touch corner, false if normal corner\n */\n calcCornerCoords: function(objectAngle, objectCornerSize, centerX, centerY, isTouch) {\n var cosHalfOffset,\n sinHalfOffset,\n cosHalfOffsetComp,\n sinHalfOffsetComp,\n xSize = (isTouch) ? this.touchSizeX : this.sizeX,\n ySize = (isTouch) ? this.touchSizeY : this.sizeY;\n if (xSize && ySize && xSize !== ySize) {\n // handle rectangular corners\n var controlTriangleAngle = Math.atan2(ySize, xSize);\n var cornerHypotenuse = Math.sqrt(xSize * xSize + ySize * ySize) / 2;\n var newTheta = controlTriangleAngle - fabric.util.degreesToRadians(objectAngle);\n var newThetaComp = Math.PI / 2 - controlTriangleAngle - fabric.util.degreesToRadians(objectAngle);\n cosHalfOffset = cornerHypotenuse * fabric.util.cos(newTheta);\n sinHalfOffset = cornerHypotenuse * fabric.util.sin(newTheta);\n // use complementary angle for two corners\n cosHalfOffsetComp = cornerHypotenuse * fabric.util.cos(newThetaComp);\n sinHalfOffsetComp = cornerHypotenuse * fabric.util.sin(newThetaComp);\n }\n else {\n // handle square corners\n // use default object corner size unless size is defined\n var cornerSize = (xSize && ySize) ? xSize : objectCornerSize;\n /* 0.7071067812 stands for sqrt(2)/2 */\n cornerHypotenuse = cornerSize * 0.7071067812;\n // complementary angles are equal since they're both 45 degrees\n var newTheta = fabric.util.degreesToRadians(45 - objectAngle);\n cosHalfOffset = cosHalfOffsetComp = cornerHypotenuse * fabric.util.cos(newTheta);\n sinHalfOffset = sinHalfOffsetComp = cornerHypotenuse * fabric.util.sin(newTheta);\n }\n\n return {\n tl: {\n x: centerX - sinHalfOffsetComp,\n y: centerY - cosHalfOffsetComp,\n },\n tr: {\n x: centerX + cosHalfOffset,\n y: centerY - sinHalfOffset,\n },\n bl: {\n x: centerX - cosHalfOffset,\n y: centerY + sinHalfOffset,\n },\n br: {\n x: centerX + sinHalfOffsetComp,\n y: centerY + cosHalfOffsetComp,\n },\n };\n },\n\n /**\n * Render function for the control.\n * When this function runs the context is unscaled. unrotate. Just retina scaled.\n * all the functions will have to translate to the point left,top before starting Drawing\n * if they want to draw a control where the position is detected.\n * left and top are the result of the positionHandler function\n * @param {RenderingContext2D} ctx the context where the control will be drawn\n * @param {Number} left position of the canvas where we are about to render the control.\n * @param {Number} top position of the canvas where we are about to render the control.\n * @param {Object} styleOverride\n * @param {fabric.Object} fabricObject the object where the control is about to be rendered\n */\n render: function(ctx, left, top, styleOverride, fabricObject) {\n styleOverride = styleOverride || {};\n switch (styleOverride.cornerStyle || fabricObject.cornerStyle) {\n case 'circle':\n fabric.controlsUtils.renderCircleControl.call(this, ctx, left, top, styleOverride, fabricObject);\n break;\n default:\n fabric.controlsUtils.renderSquareControl.call(this, ctx, left, top, styleOverride, fabricObject);\n }\n },\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n /* _FROM_SVG_START_ */\n function getColorStop(el, multiplier) {\n var style = el.getAttribute('style'),\n offset = el.getAttribute('offset') || 0,\n color, colorAlpha, opacity, i;\n\n // convert percents to absolute values\n offset = parseFloat(offset) / (/%$/.test(offset) ? 100 : 1);\n offset = offset < 0 ? 0 : offset > 1 ? 1 : offset;\n if (style) {\n var keyValuePairs = style.split(/\\s*;\\s*/);\n\n if (keyValuePairs[keyValuePairs.length - 1] === '') {\n keyValuePairs.pop();\n }\n\n for (i = keyValuePairs.length; i--; ) {\n\n var split = keyValuePairs[i].split(/\\s*:\\s*/),\n key = split[0].trim(),\n value = split[1].trim();\n\n if (key === 'stop-color') {\n color = value;\n }\n else if (key === 'stop-opacity') {\n opacity = value;\n }\n }\n }\n\n if (!color) {\n color = el.getAttribute('stop-color') || 'rgb(0,0,0)';\n }\n if (!opacity) {\n opacity = el.getAttribute('stop-opacity');\n }\n\n color = new fabric.Color(color);\n colorAlpha = color.getAlpha();\n opacity = isNaN(parseFloat(opacity)) ? 1 : parseFloat(opacity);\n opacity *= colorAlpha * multiplier;\n\n return {\n offset: offset,\n color: color.toRgb(),\n opacity: opacity\n };\n }\n\n function getLinearCoords(el) {\n return {\n x1: el.getAttribute('x1') || 0,\n y1: el.getAttribute('y1') || 0,\n x2: el.getAttribute('x2') || '100%',\n y2: el.getAttribute('y2') || 0\n };\n }\n\n function getRadialCoords(el) {\n return {\n x1: el.getAttribute('fx') || el.getAttribute('cx') || '50%',\n y1: el.getAttribute('fy') || el.getAttribute('cy') || '50%',\n r1: 0,\n x2: el.getAttribute('cx') || '50%',\n y2: el.getAttribute('cy') || '50%',\n r2: el.getAttribute('r') || '50%'\n };\n }\n /* _FROM_SVG_END_ */\n\n var clone = fabric.util.object.clone;\n\n /**\n * Gradient class\n * @class fabric.Gradient\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#gradients}\n * @see {@link fabric.Gradient#initialize} for constructor definition\n */\n fabric.Gradient = fabric.util.createClass(/** @lends fabric.Gradient.prototype */ {\n\n /**\n * Horizontal offset for aligning gradients coming from SVG when outside pathgroups\n * @type Number\n * @default 0\n */\n offsetX: 0,\n\n /**\n * Vertical offset for aligning gradients coming from SVG when outside pathgroups\n * @type Number\n * @default 0\n */\n offsetY: 0,\n\n /**\n * A transform matrix to apply to the gradient before painting.\n * Imported from svg gradients, is not applied with the current transform in the center.\n * Before this transform is applied, the origin point is at the top left corner of the object\n * plus the addition of offsetY and offsetX.\n * @type Number[]\n * @default null\n */\n gradientTransform: null,\n\n /**\n * coordinates units for coords.\n * If `pixels`, the number of coords are in the same unit of width / height.\n * If set as `percentage` the coords are still a number, but 1 means 100% of width\n * for the X and 100% of the height for the y. It can be bigger than 1 and negative.\n * allowed values pixels or percentage.\n * @type String\n * @default 'pixels'\n */\n gradientUnits: 'pixels',\n\n /**\n * Gradient type linear or radial\n * @type String\n * @default 'pixels'\n */\n type: 'linear',\n\n /**\n * Constructor\n * @param {Object} options Options object with type, coords, gradientUnits and colorStops\n * @param {Object} [options.type] gradient type linear or radial\n * @param {Object} [options.gradientUnits] gradient units\n * @param {Object} [options.offsetX] SVG import compatibility\n * @param {Object} [options.offsetY] SVG import compatibility\n * @param {Object[]} options.colorStops contains the colorstops.\n * @param {Object} options.coords contains the coords of the gradient\n * @param {Number} [options.coords.x1] X coordiante of the first point for linear or of the focal point for radial\n * @param {Number} [options.coords.y1] Y coordiante of the first point for linear or of the focal point for radial\n * @param {Number} [options.coords.x2] X coordiante of the second point for linear or of the center point for radial\n * @param {Number} [options.coords.y2] Y coordiante of the second point for linear or of the center point for radial\n * @param {Number} [options.coords.r1] only for radial gradient, radius of the inner circle\n * @param {Number} [options.coords.r2] only for radial gradient, radius of the external circle\n * @return {fabric.Gradient} thisArg\n */\n initialize: function(options) {\n options || (options = { });\n options.coords || (options.coords = { });\n\n var coords, _this = this;\n\n // sets everything, then coords and colorstops get sets again\n Object.keys(options).forEach(function(option) {\n _this[option] = options[option];\n });\n\n if (this.id) {\n this.id += '_' + fabric.Object.__uid++;\n }\n else {\n this.id = fabric.Object.__uid++;\n }\n\n coords = {\n x1: options.coords.x1 || 0,\n y1: options.coords.y1 || 0,\n x2: options.coords.x2 || 0,\n y2: options.coords.y2 || 0\n };\n\n if (this.type === 'radial') {\n coords.r1 = options.coords.r1 || 0;\n coords.r2 = options.coords.r2 || 0;\n }\n\n this.coords = coords;\n this.colorStops = options.colorStops.slice();\n },\n\n /**\n * Adds another colorStop\n * @param {Object} colorStop Object with offset and color\n * @return {fabric.Gradient} thisArg\n */\n addColorStop: function(colorStops) {\n for (var position in colorStops) {\n var color = new fabric.Color(colorStops[position]);\n this.colorStops.push({\n offset: parseFloat(position),\n color: color.toRgb(),\n opacity: color.getAlpha()\n });\n }\n return this;\n },\n\n /**\n * Returns object representation of a gradient\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object}\n */\n toObject: function(propertiesToInclude) {\n var object = {\n type: this.type,\n coords: this.coords,\n colorStops: this.colorStops,\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n gradientUnits: this.gradientUnits,\n gradientTransform: this.gradientTransform ? this.gradientTransform.concat() : this.gradientTransform\n };\n fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n return object;\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns SVG representation of an gradient\n * @param {Object} object Object to create a gradient for\n * @return {String} SVG representation of an gradient (linear/radial)\n */\n toSVG: function(object, options) {\n var coords = clone(this.coords, true), i, len, options = options || {},\n markup, commonAttributes, colorStops = clone(this.colorStops, true),\n needsSwap = coords.r1 > coords.r2,\n transform = this.gradientTransform ? this.gradientTransform.concat() : fabric.iMatrix.concat(),\n offsetX = -this.offsetX, offsetY = -this.offsetY,\n withViewport = !!options.additionalTransform,\n gradientUnits = this.gradientUnits === 'pixels' ? 'userSpaceOnUse' : 'objectBoundingBox';\n // colorStops must be sorted ascending\n colorStops.sort(function(a, b) {\n return a.offset - b.offset;\n });\n\n if (gradientUnits === 'objectBoundingBox') {\n offsetX /= object.width;\n offsetY /= object.height;\n }\n else {\n offsetX += object.width / 2;\n offsetY += object.height / 2;\n }\n if (object.type === 'path' && this.gradientUnits !== 'percentage') {\n offsetX -= object.pathOffset.x;\n offsetY -= object.pathOffset.y;\n }\n\n\n transform[4] -= offsetX;\n transform[5] -= offsetY;\n\n commonAttributes = 'id=\"SVGID_' + this.id +\n '\" gradientUnits=\"' + gradientUnits + '\"';\n commonAttributes += ' gradientTransform=\"' + (withViewport ?\n options.additionalTransform + ' ' : '') + fabric.util.matrixToSVG(transform) + '\" ';\n\n if (this.type === 'linear') {\n markup = [\n '\\n'\n ];\n }\n else if (this.type === 'radial') {\n // svg radial gradient has just 1 radius. the biggest.\n markup = [\n '\\n'\n ];\n }\n\n if (this.type === 'radial') {\n if (needsSwap) {\n // svg goes from internal to external radius. if radius are inverted, swap color stops.\n colorStops = colorStops.concat();\n colorStops.reverse();\n for (i = 0, len = colorStops.length; i < len; i++) {\n colorStops[i].offset = 1 - colorStops[i].offset;\n }\n }\n var minRadius = Math.min(coords.r1, coords.r2);\n if (minRadius > 0) {\n // i have to shift all colorStops and add new one in 0.\n var maxRadius = Math.max(coords.r1, coords.r2),\n percentageShift = minRadius / maxRadius;\n for (i = 0, len = colorStops.length; i < len; i++) {\n colorStops[i].offset += percentageShift * (1 - colorStops[i].offset);\n }\n }\n }\n\n for (i = 0, len = colorStops.length; i < len; i++) {\n var colorStop = colorStops[i];\n markup.push(\n '\\n'\n );\n }\n\n markup.push((this.type === 'linear' ? '\\n' : '\\n'));\n\n return markup.join('');\n },\n /* _TO_SVG_END_ */\n\n /**\n * Returns an instance of CanvasGradient\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @return {CanvasGradient}\n */\n toLive: function(ctx) {\n var gradient, coords = fabric.util.object.clone(this.coords), i, len;\n\n if (!this.type) {\n return;\n }\n\n if (this.type === 'linear') {\n gradient = ctx.createLinearGradient(\n coords.x1, coords.y1, coords.x2, coords.y2);\n }\n else if (this.type === 'radial') {\n gradient = ctx.createRadialGradient(\n coords.x1, coords.y1, coords.r1, coords.x2, coords.y2, coords.r2);\n }\n\n for (i = 0, len = this.colorStops.length; i < len; i++) {\n var color = this.colorStops[i].color,\n opacity = this.colorStops[i].opacity,\n offset = this.colorStops[i].offset;\n\n if (typeof opacity !== 'undefined') {\n color = new fabric.Color(color).setAlpha(opacity).toRgba();\n }\n gradient.addColorStop(offset, color);\n }\n\n return gradient;\n }\n });\n\n fabric.util.object.extend(fabric.Gradient, {\n\n /* _FROM_SVG_START_ */\n /**\n * Returns {@link fabric.Gradient} instance from an SVG element\n * @static\n * @memberOf fabric.Gradient\n * @param {SVGGradientElement} el SVG gradient element\n * @param {fabric.Object} instance\n * @param {String} opacityAttr A fill-opacity or stroke-opacity attribute to multiply to each stop's opacity.\n * @param {Object} svgOptions an object containing the size of the SVG in order to parse correctly gradients\n * that uses gradientUnits as 'userSpaceOnUse' and percentages.\n * @param {Object.number} viewBoxWidth width part of the viewBox attribute on svg\n * @param {Object.number} viewBoxHeight height part of the viewBox attribute on svg\n * @param {Object.number} width width part of the svg tag if viewBox is not specified\n * @param {Object.number} height height part of the svg tag if viewBox is not specified\n * @return {fabric.Gradient} Gradient instance\n * @see http://www.w3.org/TR/SVG/pservers.html#LinearGradientElement\n * @see http://www.w3.org/TR/SVG/pservers.html#RadialGradientElement\n */\n fromElement: function(el, instance, opacityAttr, svgOptions) {\n /**\n * @example:\n *\n * \n * \n * \n * \n *\n * OR\n *\n * \n * \n * \n * \n *\n * OR\n *\n * \n * \n * \n * \n * \n *\n * OR\n *\n * \n * \n * \n * \n * \n *\n */\n\n var multiplier = parseFloat(opacityAttr) / (/%$/.test(opacityAttr) ? 100 : 1);\n multiplier = multiplier < 0 ? 0 : multiplier > 1 ? 1 : multiplier;\n if (isNaN(multiplier)) {\n multiplier = 1;\n }\n\n var colorStopEls = el.getElementsByTagName('stop'),\n type,\n gradientUnits = el.getAttribute('gradientUnits') === 'userSpaceOnUse' ?\n 'pixels' : 'percentage',\n gradientTransform = el.getAttribute('gradientTransform') || '',\n colorStops = [],\n coords, i, offsetX = 0, offsetY = 0,\n transformMatrix;\n if (el.nodeName === 'linearGradient' || el.nodeName === 'LINEARGRADIENT') {\n type = 'linear';\n coords = getLinearCoords(el);\n }\n else {\n type = 'radial';\n coords = getRadialCoords(el);\n }\n\n for (i = colorStopEls.length; i--; ) {\n colorStops.push(getColorStop(colorStopEls[i], multiplier));\n }\n\n transformMatrix = fabric.parseTransformAttribute(gradientTransform);\n\n __convertPercentUnitsToValues(instance, coords, svgOptions, gradientUnits);\n\n if (gradientUnits === 'pixels') {\n offsetX = -instance.left;\n offsetY = -instance.top;\n }\n\n var gradient = new fabric.Gradient({\n id: el.getAttribute('id'),\n type: type,\n coords: coords,\n colorStops: colorStops,\n gradientUnits: gradientUnits,\n gradientTransform: transformMatrix,\n offsetX: offsetX,\n offsetY: offsetY,\n });\n\n return gradient;\n }\n /* _FROM_SVG_END_ */\n });\n\n /**\n * @private\n */\n function __convertPercentUnitsToValues(instance, options, svgOptions, gradientUnits) {\n var propValue, finalValue;\n Object.keys(options).forEach(function(prop) {\n propValue = options[prop];\n if (propValue === 'Infinity') {\n finalValue = 1;\n }\n else if (propValue === '-Infinity') {\n finalValue = 0;\n }\n else {\n finalValue = parseFloat(options[prop], 10);\n if (typeof propValue === 'string' && /^(\\d+\\.\\d+)%|(\\d+)%$/.test(propValue)) {\n finalValue *= 0.01;\n if (gradientUnits === 'pixels') {\n // then we need to fix those percentages here in svg parsing\n if (prop === 'x1' || prop === 'x2' || prop === 'r2') {\n finalValue *= svgOptions.viewBoxWidth || svgOptions.width;\n }\n if (prop === 'y1' || prop === 'y2') {\n finalValue *= svgOptions.viewBoxHeight || svgOptions.height;\n }\n }\n }\n }\n options[prop] = finalValue;\n });\n }\n})();\n\n\n(function() {\n\n 'use strict';\n\n var toFixed = fabric.util.toFixed;\n\n /**\n * Pattern class\n * @class fabric.Pattern\n * @see {@link http://fabricjs.com/patterns|Pattern demo}\n * @see {@link http://fabricjs.com/dynamic-patterns|DynamicPattern demo}\n * @see {@link fabric.Pattern#initialize} for constructor definition\n */\n\n\n fabric.Pattern = fabric.util.createClass(/** @lends fabric.Pattern.prototype */ {\n\n /**\n * Repeat property of a pattern (one of repeat, repeat-x, repeat-y or no-repeat)\n * @type String\n * @default\n */\n repeat: 'repeat',\n\n /**\n * Pattern horizontal offset from object's left/top corner\n * @type Number\n * @default\n */\n offsetX: 0,\n\n /**\n * Pattern vertical offset from object's left/top corner\n * @type Number\n * @default\n */\n offsetY: 0,\n\n /**\n * crossOrigin value (one of \"\", \"anonymous\", \"use-credentials\")\n * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes\n * @type String\n * @default\n */\n crossOrigin: '',\n\n /**\n * transform matrix to change the pattern, imported from svgs.\n * @type Array\n * @default\n */\n patternTransform: null,\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n * @param {Function} [callback] function to invoke after callback init.\n * @return {fabric.Pattern} thisArg\n */\n initialize: function(options, callback) {\n options || (options = { });\n\n this.id = fabric.Object.__uid++;\n this.setOptions(options);\n if (!options.source || (options.source && typeof options.source !== 'string')) {\n callback && callback(this);\n return;\n }\n else {\n // img src string\n var _this = this;\n this.source = fabric.util.createImage();\n fabric.util.loadImage(options.source, function(img, isError) {\n _this.source = img;\n callback && callback(_this, isError);\n }, null, this.crossOrigin);\n }\n },\n\n /**\n * Returns object representation of a pattern\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} Object representation of a pattern instance\n */\n toObject: function(propertiesToInclude) {\n var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n source, object;\n\n // element\n if (typeof this.source.src === 'string') {\n source = this.source.src;\n }\n // element\n else if (typeof this.source === 'object' && this.source.toDataURL) {\n source = this.source.toDataURL();\n }\n\n object = {\n type: 'pattern',\n source: source,\n repeat: this.repeat,\n crossOrigin: this.crossOrigin,\n offsetX: toFixed(this.offsetX, NUM_FRACTION_DIGITS),\n offsetY: toFixed(this.offsetY, NUM_FRACTION_DIGITS),\n patternTransform: this.patternTransform ? this.patternTransform.concat() : null\n };\n fabric.util.populateWithProperties(this, object, propertiesToInclude);\n\n return object;\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns SVG representation of a pattern\n * @param {fabric.Object} object\n * @return {String} SVG representation of a pattern\n */\n toSVG: function(object) {\n var patternSource = typeof this.source === 'function' ? this.source() : this.source,\n patternWidth = patternSource.width / object.width,\n patternHeight = patternSource.height / object.height,\n patternOffsetX = this.offsetX / object.width,\n patternOffsetY = this.offsetY / object.height,\n patternImgSrc = '';\n if (this.repeat === 'repeat-x' || this.repeat === 'no-repeat') {\n patternHeight = 1;\n if (patternOffsetY) {\n patternHeight += Math.abs(patternOffsetY);\n }\n }\n if (this.repeat === 'repeat-y' || this.repeat === 'no-repeat') {\n patternWidth = 1;\n if (patternOffsetX) {\n patternWidth += Math.abs(patternOffsetX);\n }\n\n }\n if (patternSource.src) {\n patternImgSrc = patternSource.src;\n }\n else if (patternSource.toDataURL) {\n patternImgSrc = patternSource.toDataURL();\n }\n\n return '\\n' +\n '\\n' +\n '\\n';\n },\n /* _TO_SVG_END_ */\n\n setOptions: function(options) {\n for (var prop in options) {\n this[prop] = options[prop];\n }\n },\n\n /**\n * Returns an instance of CanvasPattern\n * @param {CanvasRenderingContext2D} ctx Context to create pattern\n * @return {CanvasPattern}\n */\n toLive: function(ctx) {\n var source = this.source;\n // if the image failed to load, return, and allow rest to continue loading\n if (!source) {\n return '';\n }\n\n // if an image\n if (typeof source.src !== 'undefined') {\n if (!source.complete) {\n return '';\n }\n if (source.naturalWidth === 0 || source.naturalHeight === 0) {\n return '';\n }\n }\n return ctx.createPattern(source, this.repeat);\n }\n });\n})();\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n toFixed = fabric.util.toFixed;\n\n if (fabric.Shadow) {\n fabric.warn('fabric.Shadow is already defined.');\n return;\n }\n\n /**\n * Shadow class\n * @class fabric.Shadow\n * @see {@link http://fabricjs.com/shadows|Shadow demo}\n * @see {@link fabric.Shadow#initialize} for constructor definition\n */\n fabric.Shadow = fabric.util.createClass(/** @lends fabric.Shadow.prototype */ {\n\n /**\n * Shadow color\n * @type String\n * @default\n */\n color: 'rgb(0,0,0)',\n\n /**\n * Shadow blur\n * @type Number\n */\n blur: 0,\n\n /**\n * Shadow horizontal offset\n * @type Number\n * @default\n */\n offsetX: 0,\n\n /**\n * Shadow vertical offset\n * @type Number\n * @default\n */\n offsetY: 0,\n\n /**\n * Whether the shadow should affect stroke operations\n * @type Boolean\n * @default\n */\n affectStroke: false,\n\n /**\n * Indicates whether toObject should include default values\n * @type Boolean\n * @default\n */\n includeDefaultValues: true,\n\n /**\n * When `false`, the shadow will scale with the object.\n * When `true`, the shadow's offsetX, offsetY, and blur will not be affected by the object's scale.\n * default to false\n * @type Boolean\n * @default\n */\n nonScaling: false,\n\n /**\n * Constructor\n * @param {Object|String} [options] Options object with any of color, blur, offsetX, offsetY properties or string (e.g. \"rgba(0,0,0,0.2) 2px 2px 10px\")\n * @return {fabric.Shadow} thisArg\n */\n initialize: function(options) {\n\n if (typeof options === 'string') {\n options = this._parseShadow(options);\n }\n\n for (var prop in options) {\n this[prop] = options[prop];\n }\n\n this.id = fabric.Object.__uid++;\n },\n\n /**\n * @private\n * @param {String} shadow Shadow value to parse\n * @return {Object} Shadow object with color, offsetX, offsetY and blur\n */\n _parseShadow: function(shadow) {\n var shadowStr = shadow.trim(),\n offsetsAndBlur = fabric.Shadow.reOffsetsAndBlur.exec(shadowStr) || [],\n color = shadowStr.replace(fabric.Shadow.reOffsetsAndBlur, '') || 'rgb(0,0,0)';\n\n return {\n color: color.trim(),\n offsetX: parseFloat(offsetsAndBlur[1], 10) || 0,\n offsetY: parseFloat(offsetsAndBlur[2], 10) || 0,\n blur: parseFloat(offsetsAndBlur[3], 10) || 0\n };\n },\n\n /**\n * Returns a string representation of an instance\n * @see http://www.w3.org/TR/css-text-decor-3/#text-shadow\n * @return {String} Returns CSS3 text-shadow declaration\n */\n toString: function() {\n return [this.offsetX, this.offsetY, this.blur, this.color].join('px ');\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns SVG representation of a shadow\n * @param {fabric.Object} object\n * @return {String} SVG representation of a shadow\n */\n toSVG: function(object) {\n var fBoxX = 40, fBoxY = 40, NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n offset = fabric.util.rotateVector(\n { x: this.offsetX, y: this.offsetY },\n fabric.util.degreesToRadians(-object.angle)),\n BLUR_BOX = 20, color = new fabric.Color(this.color);\n\n if (object.width && object.height) {\n //http://www.w3.org/TR/SVG/filters.html#FilterEffectsRegion\n // we add some extra space to filter box to contain the blur ( 20 )\n fBoxX = toFixed((Math.abs(offset.x) + this.blur) / object.width, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;\n fBoxY = toFixed((Math.abs(offset.y) + this.blur) / object.height, NUM_FRACTION_DIGITS) * 100 + BLUR_BOX;\n }\n if (object.flipX) {\n offset.x *= -1;\n }\n if (object.flipY) {\n offset.y *= -1;\n }\n\n return (\n '\\n' +\n '\\t\\n' +\n '\\t\\n' +\n '\\t\\n' +\n '\\t\\n' +\n '\\t\\n' +\n '\\t\\t\\n' +\n '\\t\\t\\n' +\n '\\t\\n' +\n '\\n');\n },\n /* _TO_SVG_END_ */\n\n /**\n * Returns object representation of a shadow\n * @return {Object} Object representation of a shadow instance\n */\n toObject: function() {\n if (this.includeDefaultValues) {\n return {\n color: this.color,\n blur: this.blur,\n offsetX: this.offsetX,\n offsetY: this.offsetY,\n affectStroke: this.affectStroke,\n nonScaling: this.nonScaling\n };\n }\n var obj = { }, proto = fabric.Shadow.prototype;\n\n ['color', 'blur', 'offsetX', 'offsetY', 'affectStroke', 'nonScaling'].forEach(function(prop) {\n if (this[prop] !== proto[prop]) {\n obj[prop] = this[prop];\n }\n }, this);\n\n return obj;\n }\n });\n\n /**\n * Regex matching shadow offsetX, offsetY and blur (ex: \"2px 2px 10px rgba(0,0,0,0.2)\", \"rgb(0,255,0) 2px 2px\")\n * @static\n * @field\n * @memberOf fabric.Shadow\n */\n // eslint-disable-next-line max-len\n fabric.Shadow.reOffsetsAndBlur = /(?:\\s|^)(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?(-?\\d+(?:\\.\\d*)?(?:px)?(?:\\s?|$))?(\\d+(?:\\.\\d*)?(?:px)?)?(?:\\s?|$)(?:$|\\s)/;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function () {\n\n 'use strict';\n\n if (fabric.StaticCanvas) {\n fabric.warn('fabric.StaticCanvas is already defined.');\n return;\n }\n\n // aliases for faster resolution\n var extend = fabric.util.object.extend,\n getElementOffset = fabric.util.getElementOffset,\n removeFromArray = fabric.util.removeFromArray,\n toFixed = fabric.util.toFixed,\n transformPoint = fabric.util.transformPoint,\n invertTransform = fabric.util.invertTransform,\n getNodeCanvas = fabric.util.getNodeCanvas,\n createCanvasElement = fabric.util.createCanvasElement,\n\n CANVAS_INIT_ERROR = new Error('Could not initialize `canvas` element');\n\n /**\n * Static canvas class\n * @class fabric.StaticCanvas\n * @mixes fabric.Collection\n * @mixes fabric.Observable\n * @see {@link http://fabricjs.com/static_canvas|StaticCanvas demo}\n * @see {@link fabric.StaticCanvas#initialize} for constructor definition\n * @fires before:render\n * @fires after:render\n * @fires canvas:cleared\n * @fires object:added\n * @fires object:removed\n */\n fabric.StaticCanvas = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.StaticCanvas.prototype */ {\n\n /**\n * Constructor\n * @param {HTMLElement | String} el <canvas> element to initialize instance on\n * @param {Object} [options] Options object\n * @return {Object} thisArg\n */\n initialize: function(el, options) {\n options || (options = { });\n this.renderAndResetBound = this.renderAndReset.bind(this);\n this.requestRenderAllBound = this.requestRenderAll.bind(this);\n this._initStatic(el, options);\n },\n\n /**\n * Background color of canvas instance.\n * Should be set via {@link fabric.StaticCanvas#setBackgroundColor}.\n * @type {(String|fabric.Pattern)}\n * @default\n */\n backgroundColor: '',\n\n /**\n * Background image of canvas instance.\n * since 2.4.0 image caching is active, please when putting an image as background, add to the\n * canvas property a reference to the canvas it is on. Otherwise the image cannot detect the zoom\n * vale. As an alternative you can disable image objectCaching\n * @type fabric.Image\n * @default\n */\n backgroundImage: null,\n\n /**\n * Overlay color of canvas instance.\n * Should be set via {@link fabric.StaticCanvas#setOverlayColor}\n * @since 1.3.9\n * @type {(String|fabric.Pattern)}\n * @default\n */\n overlayColor: '',\n\n /**\n * Overlay image of canvas instance.\n * since 2.4.0 image caching is active, please when putting an image as overlay, add to the\n * canvas property a reference to the canvas it is on. Otherwise the image cannot detect the zoom\n * vale. As an alternative you can disable image objectCaching\n * @type fabric.Image\n * @default\n */\n overlayImage: null,\n\n /**\n * Indicates whether toObject/toDatalessObject should include default values\n * if set to false, takes precedence over the object value.\n * @type Boolean\n * @default\n */\n includeDefaultValues: true,\n\n /**\n * Indicates whether objects' state should be saved\n * @type Boolean\n * @default\n */\n stateful: false,\n\n /**\n * Indicates whether {@link fabric.Collection.add}, {@link fabric.Collection.insertAt} and {@link fabric.Collection.remove},\n * {@link fabric.StaticCanvas.moveTo}, {@link fabric.StaticCanvas.clear} and many more, should also re-render canvas.\n * Disabling this option will not give a performance boost when adding/removing a lot of objects to/from canvas at once\n * since the renders are quequed and executed one per frame.\n * Disabling is suggested anyway and managing the renders of the app manually is not a big effort ( canvas.requestRenderAll() )\n * Left default to true to do not break documentation and old app, fiddles.\n * @type Boolean\n * @default\n */\n renderOnAddRemove: true,\n\n /**\n * Indicates whether object controls (borders/controls) are rendered above overlay image\n * @type Boolean\n * @default\n */\n controlsAboveOverlay: false,\n\n /**\n * Indicates whether the browser can be scrolled when using a touchscreen and dragging on the canvas\n * @type Boolean\n * @default\n */\n allowTouchScrolling: false,\n\n /**\n * Indicates whether this canvas will use image smoothing, this is on by default in browsers\n * @type Boolean\n * @default\n */\n imageSmoothingEnabled: true,\n\n /**\n * The transformation (a Canvas 2D API transform matrix) which focuses the viewport\n * @type Array\n * @example Default transform\n * canvas.viewportTransform = [1, 0, 0, 1, 0, 0];\n * @example Scale by 70% and translate toward bottom-right by 50, without skewing\n * canvas.viewportTransform = [0.7, 0, 0, 0.7, 50, 50];\n * @default\n */\n viewportTransform: fabric.iMatrix.concat(),\n\n /**\n * if set to false background image is not affected by viewport transform\n * @since 1.6.3\n * @type Boolean\n * @default\n */\n backgroundVpt: true,\n\n /**\n * if set to false overlya image is not affected by viewport transform\n * @since 1.6.3\n * @type Boolean\n * @default\n */\n overlayVpt: true,\n\n /**\n * When true, canvas is scaled by devicePixelRatio for better rendering on retina screens\n * @type Boolean\n * @default\n */\n enableRetinaScaling: true,\n\n /**\n * Describe canvas element extension over design\n * properties are tl,tr,bl,br.\n * if canvas is not zoomed/panned those points are the four corner of canvas\n * if canvas is viewportTransformed you those points indicate the extension\n * of canvas element in plain untrasformed coordinates\n * The coordinates get updated with @method calcViewportBoundaries.\n * @memberOf fabric.StaticCanvas.prototype\n */\n vptCoords: { },\n\n /**\n * Based on vptCoords and object.aCoords, skip rendering of objects that\n * are not included in current viewport.\n * May greatly help in applications with crowded canvas and use of zoom/pan\n * If One of the corner of the bounding box of the object is on the canvas\n * the objects get rendered.\n * @memberOf fabric.StaticCanvas.prototype\n * @type Boolean\n * @default\n */\n skipOffscreen: true,\n\n /**\n * a fabricObject that, without stroke define a clipping area with their shape. filled in black\n * the clipPath object gets used when the canvas has rendered, and the context is placed in the\n * top left corner of the canvas.\n * clipPath will clip away controls, if you do not want this to happen use controlsAboveOverlay = true\n * @type fabric.Object\n */\n clipPath: undefined,\n\n /**\n * @private\n * @param {HTMLElement | String} el <canvas> element to initialize instance on\n * @param {Object} [options] Options object\n */\n _initStatic: function(el, options) {\n var cb = this.requestRenderAllBound;\n this._objects = [];\n this._createLowerCanvas(el);\n this._initOptions(options);\n // only initialize retina scaling once\n if (!this.interactive) {\n this._initRetinaScaling();\n }\n\n if (options.overlayImage) {\n this.setOverlayImage(options.overlayImage, cb);\n }\n if (options.backgroundImage) {\n this.setBackgroundImage(options.backgroundImage, cb);\n }\n if (options.backgroundColor) {\n this.setBackgroundColor(options.backgroundColor, cb);\n }\n if (options.overlayColor) {\n this.setOverlayColor(options.overlayColor, cb);\n }\n this.calcOffset();\n },\n\n /**\n * @private\n */\n _isRetinaScaling: function() {\n return (fabric.devicePixelRatio > 1 && this.enableRetinaScaling);\n },\n\n /**\n * @private\n * @return {Number} retinaScaling if applied, otherwise 1;\n */\n getRetinaScaling: function() {\n return this._isRetinaScaling() ? Math.max(1, fabric.devicePixelRatio) : 1;\n },\n\n /**\n * @private\n */\n _initRetinaScaling: function() {\n if (!this._isRetinaScaling()) {\n return;\n }\n var scaleRatio = fabric.devicePixelRatio;\n this.__initRetinaScaling(scaleRatio, this.lowerCanvasEl, this.contextContainer);\n if (this.upperCanvasEl) {\n this.__initRetinaScaling(scaleRatio, this.upperCanvasEl, this.contextTop);\n }\n },\n\n __initRetinaScaling: function(scaleRatio, canvas, context) {\n canvas.setAttribute('width', this.width * scaleRatio);\n canvas.setAttribute('height', this.height * scaleRatio);\n context.scale(scaleRatio, scaleRatio);\n },\n\n\n /**\n * Calculates canvas element offset relative to the document\n * This method is also attached as \"resize\" event handler of window\n * @return {fabric.Canvas} instance\n * @chainable\n */\n calcOffset: function () {\n this._offset = getElementOffset(this.lowerCanvasEl);\n return this;\n },\n\n /**\n * Sets {@link fabric.StaticCanvas#overlayImage|overlay image} for this canvas\n * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set overlay to\n * @param {Function} callback callback to invoke when image is loaded and set as an overlay\n * @param {Object} [options] Optional options to set for the {@link fabric.Image|overlay image}.\n * @return {fabric.Canvas} thisArg\n * @chainable\n * @see {@link http://jsfiddle.net/fabricjs/MnzHT/|jsFiddle demo}\n * @example Normal overlayImage with left/top = 0\n * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n * // Needed to position overlayImage at 0/0\n * originX: 'left',\n * originY: 'top'\n * });\n * @example overlayImage with different properties\n * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n * opacity: 0.5,\n * angle: 45,\n * left: 400,\n * top: 400,\n * originX: 'left',\n * originY: 'top'\n * });\n * @example Stretched overlayImage #1 - width/height correspond to canvas width/height\n * fabric.Image.fromURL('http://fabricjs.com/assets/jail_cell_bars.png', function(img, isError) {\n * img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n * canvas.setOverlayImage(img, canvas.renderAll.bind(canvas));\n * });\n * @example Stretched overlayImage #2 - width/height correspond to canvas width/height\n * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n * width: canvas.width,\n * height: canvas.height,\n * // Needed to position overlayImage at 0/0\n * originX: 'left',\n * originY: 'top'\n * });\n * @example overlayImage loaded from cross-origin\n * canvas.setOverlayImage('http://fabricjs.com/assets/jail_cell_bars.png', canvas.renderAll.bind(canvas), {\n * opacity: 0.5,\n * angle: 45,\n * left: 400,\n * top: 400,\n * originX: 'left',\n * originY: 'top',\n * crossOrigin: 'anonymous'\n * });\n */\n setOverlayImage: function (image, callback, options) {\n return this.__setBgOverlayImage('overlayImage', image, callback, options);\n },\n\n /**\n * Sets {@link fabric.StaticCanvas#backgroundImage|background image} for this canvas\n * @param {(fabric.Image|String)} image fabric.Image instance or URL of an image to set background to\n * @param {Function} callback Callback to invoke when image is loaded and set as background\n * @param {Object} [options] Optional options to set for the {@link fabric.Image|background image}.\n * @return {fabric.Canvas} thisArg\n * @chainable\n * @see {@link http://jsfiddle.net/djnr8o7a/28/|jsFiddle demo}\n * @example Normal backgroundImage with left/top = 0\n * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n * // Needed to position backgroundImage at 0/0\n * originX: 'left',\n * originY: 'top'\n * });\n * @example backgroundImage with different properties\n * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n * opacity: 0.5,\n * angle: 45,\n * left: 400,\n * top: 400,\n * originX: 'left',\n * originY: 'top'\n * });\n * @example Stretched backgroundImage #1 - width/height correspond to canvas width/height\n * fabric.Image.fromURL('http://fabricjs.com/assets/honey_im_subtle.png', function(img, isError) {\n * img.set({width: canvas.width, height: canvas.height, originX: 'left', originY: 'top'});\n * canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas));\n * });\n * @example Stretched backgroundImage #2 - width/height correspond to canvas width/height\n * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n * width: canvas.width,\n * height: canvas.height,\n * // Needed to position backgroundImage at 0/0\n * originX: 'left',\n * originY: 'top'\n * });\n * @example backgroundImage loaded from cross-origin\n * canvas.setBackgroundImage('http://fabricjs.com/assets/honey_im_subtle.png', canvas.renderAll.bind(canvas), {\n * opacity: 0.5,\n * angle: 45,\n * left: 400,\n * top: 400,\n * originX: 'left',\n * originY: 'top',\n * crossOrigin: 'anonymous'\n * });\n */\n // TODO: fix stretched examples\n setBackgroundImage: function (image, callback, options) {\n return this.__setBgOverlayImage('backgroundImage', image, callback, options);\n },\n\n /**\n * Sets {@link fabric.StaticCanvas#overlayColor|foreground color} for this canvas\n * @param {(String|fabric.Pattern)} overlayColor Color or pattern to set foreground color to\n * @param {Function} callback Callback to invoke when foreground color is set\n * @return {fabric.Canvas} thisArg\n * @chainable\n * @see {@link http://jsfiddle.net/fabricjs/pB55h/|jsFiddle demo}\n * @example Normal overlayColor - color value\n * canvas.setOverlayColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n * @example fabric.Pattern used as overlayColor\n * canvas.setOverlayColor({\n * source: 'http://fabricjs.com/assets/escheresque_ste.png'\n * }, canvas.renderAll.bind(canvas));\n * @example fabric.Pattern used as overlayColor with repeat and offset\n * canvas.setOverlayColor({\n * source: 'http://fabricjs.com/assets/escheresque_ste.png',\n * repeat: 'repeat',\n * offsetX: 200,\n * offsetY: 100\n * }, canvas.renderAll.bind(canvas));\n */\n setOverlayColor: function(overlayColor, callback) {\n return this.__setBgOverlayColor('overlayColor', overlayColor, callback);\n },\n\n /**\n * Sets {@link fabric.StaticCanvas#backgroundColor|background color} for this canvas\n * @param {(String|fabric.Pattern)} backgroundColor Color or pattern to set background color to\n * @param {Function} callback Callback to invoke when background color is set\n * @return {fabric.Canvas} thisArg\n * @chainable\n * @see {@link http://jsfiddle.net/fabricjs/hXzvk/|jsFiddle demo}\n * @example Normal backgroundColor - color value\n * canvas.setBackgroundColor('rgba(255, 73, 64, 0.6)', canvas.renderAll.bind(canvas));\n * @example fabric.Pattern used as backgroundColor\n * canvas.setBackgroundColor({\n * source: 'http://fabricjs.com/assets/escheresque_ste.png'\n * }, canvas.renderAll.bind(canvas));\n * @example fabric.Pattern used as backgroundColor with repeat and offset\n * canvas.setBackgroundColor({\n * source: 'http://fabricjs.com/assets/escheresque_ste.png',\n * repeat: 'repeat',\n * offsetX: 200,\n * offsetY: 100\n * }, canvas.renderAll.bind(canvas));\n */\n setBackgroundColor: function(backgroundColor, callback) {\n return this.__setBgOverlayColor('backgroundColor', backgroundColor, callback);\n },\n\n /**\n * @private\n * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundImage|backgroundImage}\n * or {@link fabric.StaticCanvas#overlayImage|overlayImage})\n * @param {(fabric.Image|String|null)} image fabric.Image instance, URL of an image or null to set background or overlay to\n * @param {Function} callback Callback to invoke when image is loaded and set as background or overlay. The first argument is the created image, the second argument is a flag indicating whether an error occurred or not.\n * @param {Object} [options] Optional options to set for the {@link fabric.Image|image}.\n */\n __setBgOverlayImage: function(property, image, callback, options) {\n if (typeof image === 'string') {\n fabric.util.loadImage(image, function(img, isError) {\n if (img) {\n var instance = new fabric.Image(img, options);\n this[property] = instance;\n instance.canvas = this;\n }\n callback && callback(img, isError);\n }, this, options && options.crossOrigin);\n }\n else {\n options && image.setOptions(options);\n this[property] = image;\n image && (image.canvas = this);\n callback && callback(image, false);\n }\n\n return this;\n },\n\n /**\n * @private\n * @param {String} property Property to set ({@link fabric.StaticCanvas#backgroundColor|backgroundColor}\n * or {@link fabric.StaticCanvas#overlayColor|overlayColor})\n * @param {(Object|String|null)} color Object with pattern information, color value or null\n * @param {Function} [callback] Callback is invoked when color is set\n */\n __setBgOverlayColor: function(property, color, callback) {\n this[property] = color;\n this._initGradient(color, property);\n this._initPattern(color, property, callback);\n return this;\n },\n\n /**\n * @private\n */\n _createCanvasElement: function() {\n var element = createCanvasElement();\n if (!element) {\n throw CANVAS_INIT_ERROR;\n }\n if (!element.style) {\n element.style = { };\n }\n if (typeof element.getContext === 'undefined') {\n throw CANVAS_INIT_ERROR;\n }\n return element;\n },\n\n /**\n * @private\n * @param {Object} [options] Options object\n */\n _initOptions: function (options) {\n var lowerCanvasEl = this.lowerCanvasEl;\n this._setOptions(options);\n\n this.width = this.width || parseInt(lowerCanvasEl.width, 10) || 0;\n this.height = this.height || parseInt(lowerCanvasEl.height, 10) || 0;\n\n if (!this.lowerCanvasEl.style) {\n return;\n }\n\n lowerCanvasEl.width = this.width;\n lowerCanvasEl.height = this.height;\n\n lowerCanvasEl.style.width = this.width + 'px';\n lowerCanvasEl.style.height = this.height + 'px';\n\n this.viewportTransform = this.viewportTransform.slice();\n },\n\n /**\n * Creates a bottom canvas\n * @private\n * @param {HTMLElement} [canvasEl]\n */\n _createLowerCanvas: function (canvasEl) {\n // canvasEl === 'HTMLCanvasElement' does not work on jsdom/node\n if (canvasEl && canvasEl.getContext) {\n this.lowerCanvasEl = canvasEl;\n }\n else {\n this.lowerCanvasEl = fabric.util.getById(canvasEl) || this._createCanvasElement();\n }\n\n fabric.util.addClass(this.lowerCanvasEl, 'lower-canvas');\n this._originalCanvasStyle = this.lowerCanvasEl.style;\n if (this.interactive) {\n this._applyCanvasStyle(this.lowerCanvasEl);\n }\n\n this.contextContainer = this.lowerCanvasEl.getContext('2d');\n },\n\n /**\n * Returns canvas width (in px)\n * @return {Number}\n */\n getWidth: function () {\n return this.width;\n },\n\n /**\n * Returns canvas height (in px)\n * @return {Number}\n */\n getHeight: function () {\n return this.height;\n },\n\n /**\n * Sets width of this canvas instance\n * @param {Number|String} value Value to set width to\n * @param {Object} [options] Options object\n * @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n * @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n setWidth: function (value, options) {\n return this.setDimensions({ width: value }, options);\n },\n\n /**\n * Sets height of this canvas instance\n * @param {Number|String} value Value to set height to\n * @param {Object} [options] Options object\n * @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n * @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n setHeight: function (value, options) {\n return this.setDimensions({ height: value }, options);\n },\n\n /**\n * Sets dimensions (width, height) of this canvas instance. when options.cssOnly flag active you should also supply the unit of measure (px/%/em)\n * @param {Object} dimensions Object with width/height properties\n * @param {Number|String} [dimensions.width] Width of canvas element\n * @param {Number|String} [dimensions.height] Height of canvas element\n * @param {Object} [options] Options object\n * @param {Boolean} [options.backstoreOnly=false] Set the given dimensions only as canvas backstore dimensions\n * @param {Boolean} [options.cssOnly=false] Set the given dimensions only as css dimensions\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n setDimensions: function (dimensions, options) {\n var cssValue;\n\n options = options || {};\n\n for (var prop in dimensions) {\n cssValue = dimensions[prop];\n\n if (!options.cssOnly) {\n this._setBackstoreDimension(prop, dimensions[prop]);\n cssValue += 'px';\n this.hasLostContext = true;\n }\n\n if (!options.backstoreOnly) {\n this._setCssDimension(prop, cssValue);\n }\n }\n if (this._isCurrentlyDrawing) {\n this.freeDrawingBrush && this.freeDrawingBrush._setBrushStyles(this.contextTop);\n }\n this._initRetinaScaling();\n this.calcOffset();\n\n if (!options.cssOnly) {\n this.requestRenderAll();\n }\n\n return this;\n },\n\n /**\n * Helper for setting width/height\n * @private\n * @param {String} prop property (width|height)\n * @param {Number} value value to set property to\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n _setBackstoreDimension: function (prop, value) {\n this.lowerCanvasEl[prop] = value;\n\n if (this.upperCanvasEl) {\n this.upperCanvasEl[prop] = value;\n }\n\n if (this.cacheCanvasEl) {\n this.cacheCanvasEl[prop] = value;\n }\n\n this[prop] = value;\n\n return this;\n },\n\n /**\n * Helper for setting css width/height\n * @private\n * @param {String} prop property (width|height)\n * @param {String} value value to set property to\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n _setCssDimension: function (prop, value) {\n this.lowerCanvasEl.style[prop] = value;\n\n if (this.upperCanvasEl) {\n this.upperCanvasEl.style[prop] = value;\n }\n\n if (this.wrapperEl) {\n this.wrapperEl.style[prop] = value;\n }\n\n return this;\n },\n\n /**\n * Returns canvas zoom level\n * @return {Number}\n */\n getZoom: function () {\n return this.viewportTransform[0];\n },\n\n /**\n * Sets viewport transformation of this canvas instance\n * @param {Array} vpt a Canvas 2D API transform matrix\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n setViewportTransform: function (vpt) {\n var activeObject = this._activeObject,\n backgroundObject = this.backgroundImage,\n overlayObject = this.overlayImage,\n object, i, len;\n this.viewportTransform = vpt;\n for (i = 0, len = this._objects.length; i < len; i++) {\n object = this._objects[i];\n object.group || object.setCoords(true);\n }\n if (activeObject) {\n activeObject.setCoords();\n }\n if (backgroundObject) {\n backgroundObject.setCoords(true);\n }\n if (overlayObject) {\n overlayObject.setCoords(true);\n }\n this.calcViewportBoundaries();\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * Sets zoom level of this canvas instance, the zoom centered around point\n * meaning that following zoom to point with the same point will have the visual\n * effect of the zoom originating from that point. The point won't move.\n * It has nothing to do with canvas center or visual center of the viewport.\n * @param {fabric.Point} point to zoom with respect to\n * @param {Number} value to set zoom to, less than 1 zooms out\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n zoomToPoint: function (point, value) {\n // TODO: just change the scale, preserve other transformations\n var before = point, vpt = this.viewportTransform.slice(0);\n point = transformPoint(point, invertTransform(this.viewportTransform));\n vpt[0] = value;\n vpt[3] = value;\n var after = transformPoint(point, vpt);\n vpt[4] += before.x - after.x;\n vpt[5] += before.y - after.y;\n return this.setViewportTransform(vpt);\n },\n\n /**\n * Sets zoom level of this canvas instance\n * @param {Number} value to set zoom to, less than 1 zooms out\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n setZoom: function (value) {\n this.zoomToPoint(new fabric.Point(0, 0), value);\n return this;\n },\n\n /**\n * Pan viewport so as to place point at top left corner of canvas\n * @param {fabric.Point} point to move to\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n absolutePan: function (point) {\n var vpt = this.viewportTransform.slice(0);\n vpt[4] = -point.x;\n vpt[5] = -point.y;\n return this.setViewportTransform(vpt);\n },\n\n /**\n * Pans viewpoint relatively\n * @param {fabric.Point} point (position vector) to move by\n * @return {fabric.Canvas} instance\n * @chainable true\n */\n relativePan: function (point) {\n return this.absolutePan(new fabric.Point(\n -point.x - this.viewportTransform[4],\n -point.y - this.viewportTransform[5]\n ));\n },\n\n /**\n * Returns <canvas> element corresponding to this instance\n * @return {HTMLCanvasElement}\n */\n getElement: function () {\n return this.lowerCanvasEl;\n },\n\n /**\n * @private\n * @param {fabric.Object} obj Object that was added\n */\n _onObjectAdded: function(obj) {\n this.stateful && obj.setupState();\n obj._set('canvas', this);\n obj.setCoords();\n this.fire('object:added', { target: obj });\n obj.fire('added');\n },\n\n /**\n * @private\n * @param {fabric.Object} obj Object that was removed\n */\n _onObjectRemoved: function(obj) {\n this.fire('object:removed', { target: obj });\n obj.fire('removed');\n delete obj.canvas;\n },\n\n /**\n * Clears specified context of canvas element\n * @param {CanvasRenderingContext2D} ctx Context to clear\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n clearContext: function(ctx) {\n ctx.clearRect(0, 0, this.width, this.height);\n return this;\n },\n\n /**\n * Returns context of canvas where objects are drawn\n * @return {CanvasRenderingContext2D}\n */\n getContext: function () {\n return this.contextContainer;\n },\n\n /**\n * Clears all contexts (background, main, top) of an instance\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n clear: function () {\n this.remove.apply(this, this.getObjects());\n this.backgroundImage = null;\n this.overlayImage = null;\n this.backgroundColor = '';\n this.overlayColor = '';\n if (this._hasITextHandlers) {\n this.off('mouse:up', this._mouseUpITextHandler);\n this._iTextInstances = null;\n this._hasITextHandlers = false;\n }\n this.clearContext(this.contextContainer);\n this.fire('canvas:cleared');\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * Renders the canvas\n * @return {fabric.Canvas} instance\n * @chainable\n */\n renderAll: function () {\n var canvasToDrawOn = this.contextContainer;\n this.renderCanvas(canvasToDrawOn, this._objects);\n return this;\n },\n\n /**\n * Function created to be instance bound at initialization\n * used in requestAnimationFrame rendering\n * Let the fabricJS call it. If you call it manually you could have more\n * animationFrame stacking on to of each other\n * for an imperative rendering, use canvas.renderAll\n * @private\n * @return {fabric.Canvas} instance\n * @chainable\n */\n renderAndReset: function() {\n this.isRendering = 0;\n this.renderAll();\n },\n\n /**\n * Append a renderAll request to next animation frame.\n * unless one is already in progress, in that case nothing is done\n * a boolean flag will avoid appending more.\n * @return {fabric.Canvas} instance\n * @chainable\n */\n requestRenderAll: function () {\n if (!this.isRendering) {\n this.isRendering = fabric.util.requestAnimFrame(this.renderAndResetBound);\n }\n return this;\n },\n\n /**\n * Calculate the position of the 4 corner of canvas with current viewportTransform.\n * helps to determinate when an object is in the current rendering viewport using\n * object absolute coordinates ( aCoords )\n * @return {Object} points.tl\n * @chainable\n */\n calcViewportBoundaries: function() {\n var points = { }, width = this.width, height = this.height,\n iVpt = invertTransform(this.viewportTransform);\n points.tl = transformPoint({ x: 0, y: 0 }, iVpt);\n points.br = transformPoint({ x: width, y: height }, iVpt);\n points.tr = new fabric.Point(points.br.x, points.tl.y);\n points.bl = new fabric.Point(points.tl.x, points.br.y);\n this.vptCoords = points;\n return points;\n },\n\n cancelRequestedRender: function() {\n if (this.isRendering) {\n fabric.util.cancelAnimFrame(this.isRendering);\n this.isRendering = 0;\n }\n },\n\n /**\n * Renders background, objects, overlay and controls.\n * @param {CanvasRenderingContext2D} ctx\n * @param {Array} objects to render\n * @return {fabric.Canvas} instance\n * @chainable\n */\n renderCanvas: function(ctx, objects) {\n var v = this.viewportTransform, path = this.clipPath;\n this.cancelRequestedRender();\n this.calcViewportBoundaries();\n this.clearContext(ctx);\n fabric.util.setImageSmoothing(ctx, this.imageSmoothingEnabled);\n this.fire('before:render', { ctx: ctx, });\n this._renderBackground(ctx);\n\n ctx.save();\n //apply viewport transform once for all rendering process\n ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n this._renderObjects(ctx, objects);\n ctx.restore();\n if (!this.controlsAboveOverlay && this.interactive) {\n this.drawControls(ctx);\n }\n if (path) {\n path.canvas = this;\n // needed to setup a couple of variables\n path.shouldCache();\n path._transformDone = true;\n path.renderCache({ forClipping: true });\n this.drawClipPathOnCanvas(ctx);\n }\n this._renderOverlay(ctx);\n if (this.controlsAboveOverlay && this.interactive) {\n this.drawControls(ctx);\n }\n this.fire('after:render', { ctx: ctx, });\n },\n\n /**\n * Paint the cached clipPath on the lowerCanvasEl\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n drawClipPathOnCanvas: function(ctx) {\n var v = this.viewportTransform, path = this.clipPath;\n ctx.save();\n ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n // DEBUG: uncomment this line, comment the following\n // ctx.globalAlpha = 0.4;\n ctx.globalCompositeOperation = 'destination-in';\n path.transform(ctx);\n ctx.scale(1 / path.zoomX, 1 / path.zoomY);\n ctx.drawImage(path._cacheCanvas, -path.cacheTranslationX, -path.cacheTranslationY);\n ctx.restore();\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {Array} objects to render\n */\n _renderObjects: function(ctx, objects) {\n var i, len;\n for (i = 0, len = objects.length; i < len; ++i) {\n objects[i] && objects[i].render(ctx);\n }\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {string} property 'background' or 'overlay'\n */\n _renderBackgroundOrOverlay: function(ctx, property) {\n var fill = this[property + 'Color'], object = this[property + 'Image'],\n v = this.viewportTransform, needsVpt = this[property + 'Vpt'];\n if (!fill && !object) {\n return;\n }\n if (fill) {\n ctx.save();\n ctx.beginPath();\n ctx.moveTo(0, 0);\n ctx.lineTo(this.width, 0);\n ctx.lineTo(this.width, this.height);\n ctx.lineTo(0, this.height);\n ctx.closePath();\n ctx.fillStyle = fill.toLive\n ? fill.toLive(ctx, this)\n : fill;\n if (needsVpt) {\n ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n }\n ctx.transform(1, 0, 0, 1, fill.offsetX || 0, fill.offsetY || 0);\n var m = fill.gradientTransform || fill.patternTransform;\n m && ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n ctx.fill();\n ctx.restore();\n }\n if (object) {\n ctx.save();\n if (needsVpt) {\n ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n }\n object.render(ctx);\n ctx.restore();\n }\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderBackground: function(ctx) {\n this._renderBackgroundOrOverlay(ctx, 'background');\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderOverlay: function(ctx) {\n this._renderBackgroundOrOverlay(ctx, 'overlay');\n },\n\n /**\n * Returns coordinates of a center of canvas.\n * Returned value is an object with top and left properties\n * @return {Object} object with \"top\" and \"left\" number values\n * @deprecated migrate to `getCenterPoint`\n */\n getCenter: function () {\n return {\n top: this.height / 2,\n left: this.width / 2\n };\n },\n\n /**\n * Returns coordinates of a center of canvas.\n * @return {fabric.Point} \n */\n getCenterPoint: function () {\n return new fabric.Point(this.width / 2, this.height / 2);\n },\n\n /**\n * Centers object horizontally in the canvas\n * @param {fabric.Object} object Object to center horizontally\n * @return {fabric.Canvas} thisArg\n */\n centerObjectH: function (object) {\n return this._centerObject(object, new fabric.Point(this.getCenterPoint().x, object.getCenterPoint().y));\n },\n\n /**\n * Centers object vertically in the canvas\n * @param {fabric.Object} object Object to center vertically\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n centerObjectV: function (object) {\n return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, this.getCenterPoint().y));\n },\n\n /**\n * Centers object vertically and horizontally in the canvas\n * @param {fabric.Object} object Object to center vertically and horizontally\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n centerObject: function(object) {\n var center = this.getCenterPoint();\n return this._centerObject(object, center);\n },\n\n /**\n * Centers object vertically and horizontally in the viewport\n * @param {fabric.Object} object Object to center vertically and horizontally\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n viewportCenterObject: function(object) {\n var vpCenter = this.getVpCenter();\n return this._centerObject(object, vpCenter);\n },\n\n /**\n * Centers object horizontally in the viewport, object.top is unchanged\n * @param {fabric.Object} object Object to center vertically and horizontally\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n viewportCenterObjectH: function(object) {\n var vpCenter = this.getVpCenter();\n this._centerObject(object, new fabric.Point(vpCenter.x, object.getCenterPoint().y));\n return this;\n },\n\n /**\n * Centers object Vertically in the viewport, object.top is unchanged\n * @param {fabric.Object} object Object to center vertically and horizontally\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n viewportCenterObjectV: function(object) {\n var vpCenter = this.getVpCenter();\n\n return this._centerObject(object, new fabric.Point(object.getCenterPoint().x, vpCenter.y));\n },\n\n /**\n * Calculate the point in canvas that correspond to the center of actual viewport.\n * @return {fabric.Point} vpCenter, viewport center\n * @chainable\n */\n getVpCenter: function() {\n var center = this.getCenterPoint(),\n iVpt = invertTransform(this.viewportTransform);\n return transformPoint(center, iVpt);\n },\n\n /**\n * @private\n * @param {fabric.Object} object Object to center\n * @param {fabric.Point} center Center point\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n _centerObject: function(object, center) {\n object.setPositionByOrigin(center, 'center', 'center');\n object.setCoords();\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * Returns dataless JSON representation of canvas\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {String} json string\n */\n toDatalessJSON: function (propertiesToInclude) {\n return this.toDatalessObject(propertiesToInclude);\n },\n\n /**\n * Returns object representation of canvas\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function (propertiesToInclude) {\n return this._toObjectMethod('toObject', propertiesToInclude);\n },\n\n /**\n * Returns dataless object representation of canvas\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toDatalessObject: function (propertiesToInclude) {\n return this._toObjectMethod('toDatalessObject', propertiesToInclude);\n },\n\n /**\n * @private\n */\n _toObjectMethod: function (methodName, propertiesToInclude) {\n\n var clipPath = this.clipPath, data = {\n version: fabric.version,\n objects: this._toObjects(methodName, propertiesToInclude),\n };\n if (clipPath && !clipPath.excludeFromExport) {\n data.clipPath = this._toObject(this.clipPath, methodName, propertiesToInclude);\n }\n extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));\n\n fabric.util.populateWithProperties(this, data, propertiesToInclude);\n\n return data;\n },\n\n /**\n * @private\n */\n _toObjects: function(methodName, propertiesToInclude) {\n return this._objects.filter(function(object) {\n return !object.excludeFromExport;\n }).map(function(instance) {\n return this._toObject(instance, methodName, propertiesToInclude);\n }, this);\n },\n\n /**\n * @private\n */\n _toObject: function(instance, methodName, propertiesToInclude) {\n var originalValue;\n\n if (!this.includeDefaultValues) {\n originalValue = instance.includeDefaultValues;\n instance.includeDefaultValues = false;\n }\n\n var object = instance[methodName](propertiesToInclude);\n if (!this.includeDefaultValues) {\n instance.includeDefaultValues = originalValue;\n }\n return object;\n },\n\n /**\n * @private\n */\n __serializeBgOverlay: function(methodName, propertiesToInclude) {\n var data = {}, bgImage = this.backgroundImage, overlayImage = this.overlayImage,\n bgColor = this.backgroundColor, overlayColor = this.overlayColor;\n\n if (bgColor && bgColor.toObject) {\n if (!bgColor.excludeFromExport) {\n data.background = bgColor.toObject(propertiesToInclude);\n }\n }\n else if (bgColor) {\n data.background = bgColor;\n }\n\n if (overlayColor && overlayColor.toObject) {\n if (!overlayColor.excludeFromExport) {\n data.overlay = overlayColor.toObject(propertiesToInclude);\n }\n }\n else if (overlayColor) {\n data.overlay = overlayColor;\n }\n\n if (bgImage && !bgImage.excludeFromExport) {\n data.backgroundImage = this._toObject(bgImage, methodName, propertiesToInclude);\n }\n if (overlayImage && !overlayImage.excludeFromExport) {\n data.overlayImage = this._toObject(overlayImage, methodName, propertiesToInclude);\n }\n\n return data;\n },\n\n /* _TO_SVG_START_ */\n /**\n * When true, getSvgTransform() will apply the StaticCanvas.viewportTransform to the SVG transformation. When true,\n * a zoomed canvas will then produce zoomed SVG output.\n * @type Boolean\n * @default\n */\n svgViewportTransformation: true,\n\n /**\n * Returns SVG representation of canvas\n * @function\n * @param {Object} [options] Options object for SVG output\n * @param {Boolean} [options.suppressPreamble=false] If true xml tag is not included\n * @param {Object} [options.viewBox] SVG viewbox object\n * @param {Number} [options.viewBox.x] x-coordinate of viewbox\n * @param {Number} [options.viewBox.y] y-coordinate of viewbox\n * @param {Number} [options.viewBox.width] Width of viewbox\n * @param {Number} [options.viewBox.height] Height of viewbox\n * @param {String} [options.encoding=UTF-8] Encoding of SVG output\n * @param {String} [options.width] desired width of svg with or without units\n * @param {String} [options.height] desired height of svg with or without units\n * @param {Function} [reviver] Method for further parsing of svg elements, called after each fabric object converted into svg representation.\n * @return {String} SVG string\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}\n * @see {@link http://jsfiddle.net/fabricjs/jQ3ZZ/|jsFiddle demo}\n * @example Normal SVG output\n * var svg = canvas.toSVG();\n * @example SVG output without preamble (without <?xml ../>)\n * var svg = canvas.toSVG({suppressPreamble: true});\n * @example SVG output with viewBox attribute\n * var svg = canvas.toSVG({\n * viewBox: {\n * x: 100,\n * y: 100,\n * width: 200,\n * height: 300\n * }\n * });\n * @example SVG output with different encoding (default: UTF-8)\n * var svg = canvas.toSVG({encoding: 'ISO-8859-1'});\n * @example Modify SVG output with reviver function\n * var svg = canvas.toSVG(null, function(svg) {\n * return svg.replace('stroke-dasharray: ; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 10; ', '');\n * });\n */\n toSVG: function(options, reviver) {\n options || (options = { });\n options.reviver = reviver;\n var markup = [];\n\n this._setSVGPreamble(markup, options);\n this._setSVGHeader(markup, options);\n if (this.clipPath) {\n markup.push('\\n');\n }\n this._setSVGBgOverlayColor(markup, 'background');\n this._setSVGBgOverlayImage(markup, 'backgroundImage', reviver);\n this._setSVGObjects(markup, reviver);\n if (this.clipPath) {\n markup.push('\\n');\n }\n this._setSVGBgOverlayColor(markup, 'overlay');\n this._setSVGBgOverlayImage(markup, 'overlayImage', reviver);\n\n markup.push('');\n\n return markup.join('');\n },\n\n /**\n * @private\n */\n _setSVGPreamble: function(markup, options) {\n if (options.suppressPreamble) {\n return;\n }\n markup.push(\n '\\n',\n '\\n'\n );\n },\n\n /**\n * @private\n */\n _setSVGHeader: function(markup, options) {\n var width = options.width || this.width,\n height = options.height || this.height,\n vpt, viewBox = 'viewBox=\"0 0 ' + this.width + ' ' + this.height + '\" ',\n NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n\n if (options.viewBox) {\n viewBox = 'viewBox=\"' +\n options.viewBox.x + ' ' +\n options.viewBox.y + ' ' +\n options.viewBox.width + ' ' +\n options.viewBox.height + '\" ';\n }\n else {\n if (this.svgViewportTransformation) {\n vpt = this.viewportTransform;\n viewBox = 'viewBox=\"' +\n toFixed(-vpt[4] / vpt[0], NUM_FRACTION_DIGITS) + ' ' +\n toFixed(-vpt[5] / vpt[3], NUM_FRACTION_DIGITS) + ' ' +\n toFixed(this.width / vpt[0], NUM_FRACTION_DIGITS) + ' ' +\n toFixed(this.height / vpt[3], NUM_FRACTION_DIGITS) + '\" ';\n }\n }\n\n markup.push(\n '\\n',\n 'Created with Fabric.js ', fabric.version, '\\n',\n '\\n',\n this.createSVGFontFacesMarkup(),\n this.createSVGRefElementsMarkup(),\n this.createSVGClipPathMarkup(options),\n '\\n'\n );\n },\n\n createSVGClipPathMarkup: function(options) {\n var clipPath = this.clipPath;\n if (clipPath) {\n clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;\n return '\\n' +\n this.clipPath.toClipPathSVG(options.reviver) +\n '\\n';\n }\n return '';\n },\n\n /**\n * Creates markup containing SVG referenced elements like patterns, gradients etc.\n * @return {String}\n */\n createSVGRefElementsMarkup: function() {\n var _this = this,\n markup = ['background', 'overlay'].map(function(prop) {\n var fill = _this[prop + 'Color'];\n if (fill && fill.toLive) {\n var shouldTransform = _this[prop + 'Vpt'], vpt = _this.viewportTransform,\n object = {\n width: _this.width / (shouldTransform ? vpt[0] : 1),\n height: _this.height / (shouldTransform ? vpt[3] : 1)\n };\n return fill.toSVG(\n object,\n { additionalTransform: shouldTransform ? fabric.util.matrixToSVG(vpt) : '' }\n );\n }\n });\n return markup.join('');\n },\n\n /**\n * Creates markup containing SVG font faces,\n * font URLs for font faces must be collected by developers\n * and are not extracted from the DOM by fabricjs\n * @param {Array} objects Array of fabric objects\n * @return {String}\n */\n createSVGFontFacesMarkup: function() {\n var markup = '', fontList = { }, obj, fontFamily,\n style, row, rowIndex, _char, charIndex, i, len,\n fontPaths = fabric.fontPaths, objects = [];\n\n this._objects.forEach(function add(object) {\n objects.push(object);\n if (object._objects) {\n object._objects.forEach(add);\n }\n });\n\n for (i = 0, len = objects.length; i < len; i++) {\n obj = objects[i];\n fontFamily = obj.fontFamily;\n if (obj.type.indexOf('text') === -1 || fontList[fontFamily] || !fontPaths[fontFamily]) {\n continue;\n }\n fontList[fontFamily] = true;\n if (!obj.styles) {\n continue;\n }\n style = obj.styles;\n for (rowIndex in style) {\n row = style[rowIndex];\n for (charIndex in row) {\n _char = row[charIndex];\n fontFamily = _char.fontFamily;\n if (!fontList[fontFamily] && fontPaths[fontFamily]) {\n fontList[fontFamily] = true;\n }\n }\n }\n }\n\n for (var j in fontList) {\n markup += [\n '\\t\\t@font-face {\\n',\n '\\t\\t\\tfont-family: \\'', j, '\\';\\n',\n '\\t\\t\\tsrc: url(\\'', fontPaths[j], '\\');\\n',\n '\\t\\t}\\n'\n ].join('');\n }\n\n if (markup) {\n markup = [\n '\\t\\n'\n ].join('');\n }\n\n return markup;\n },\n\n /**\n * @private\n */\n _setSVGObjects: function(markup, reviver) {\n var instance, i, len, objects = this._objects;\n for (i = 0, len = objects.length; i < len; i++) {\n instance = objects[i];\n if (instance.excludeFromExport) {\n continue;\n }\n this._setSVGObject(markup, instance, reviver);\n }\n },\n\n /**\n * @private\n */\n _setSVGObject: function(markup, instance, reviver) {\n markup.push(instance.toSVG(reviver));\n },\n\n /**\n * @private\n */\n _setSVGBgOverlayImage: function(markup, property, reviver) {\n if (this[property] && !this[property].excludeFromExport && this[property].toSVG) {\n markup.push(this[property].toSVG(reviver));\n }\n },\n\n /**\n * @private\n */\n _setSVGBgOverlayColor: function(markup, property) {\n var filler = this[property + 'Color'], vpt = this.viewportTransform, finalWidth = this.width,\n finalHeight = this.height;\n if (!filler) {\n return;\n }\n if (filler.toLive) {\n var repeat = filler.repeat, iVpt = fabric.util.invertTransform(vpt), shouldInvert = this[property + 'Vpt'],\n additionalTransform = shouldInvert ? fabric.util.matrixToSVG(iVpt) : '';\n markup.push(\n '\\n'\n );\n }\n else {\n markup.push(\n '\\n'\n );\n }\n },\n /* _TO_SVG_END_ */\n\n /**\n * Moves an object or the objects of a multiple selection\n * to the bottom of the stack of drawn objects\n * @param {fabric.Object} object Object to send to back\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n sendToBack: function (object) {\n if (!object) {\n return this;\n }\n var activeSelection = this._activeObject,\n i, obj, objs;\n if (object === activeSelection && object.type === 'activeSelection') {\n objs = activeSelection._objects;\n for (i = objs.length; i--;) {\n obj = objs[i];\n removeFromArray(this._objects, obj);\n this._objects.unshift(obj);\n }\n }\n else {\n removeFromArray(this._objects, object);\n this._objects.unshift(object);\n }\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * Moves an object or the objects of a multiple selection\n * to the top of the stack of drawn objects\n * @param {fabric.Object} object Object to send\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n bringToFront: function (object) {\n if (!object) {\n return this;\n }\n var activeSelection = this._activeObject,\n i, obj, objs;\n if (object === activeSelection && object.type === 'activeSelection') {\n objs = activeSelection._objects;\n for (i = 0; i < objs.length; i++) {\n obj = objs[i];\n removeFromArray(this._objects, obj);\n this._objects.push(obj);\n }\n }\n else {\n removeFromArray(this._objects, object);\n this._objects.push(object);\n }\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * Moves an object or a selection down in stack of drawn objects\n * An optional parameter, intersecting allows to move the object in behind\n * the first intersecting object. Where intersection is calculated with\n * bounding box. If no intersection is found, there will not be change in the\n * stack.\n * @param {fabric.Object} object Object to send\n * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n sendBackwards: function (object, intersecting) {\n if (!object) {\n return this;\n }\n var activeSelection = this._activeObject,\n i, obj, idx, newIdx, objs, objsMoved = 0;\n\n if (object === activeSelection && object.type === 'activeSelection') {\n objs = activeSelection._objects;\n for (i = 0; i < objs.length; i++) {\n obj = objs[i];\n idx = this._objects.indexOf(obj);\n if (idx > 0 + objsMoved) {\n newIdx = idx - 1;\n removeFromArray(this._objects, obj);\n this._objects.splice(newIdx, 0, obj);\n }\n objsMoved++;\n }\n }\n else {\n idx = this._objects.indexOf(object);\n if (idx !== 0) {\n // if object is not on the bottom of stack\n newIdx = this._findNewLowerIndex(object, idx, intersecting);\n removeFromArray(this._objects, object);\n this._objects.splice(newIdx, 0, object);\n }\n }\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * @private\n */\n _findNewLowerIndex: function(object, idx, intersecting) {\n var newIdx, i;\n\n if (intersecting) {\n newIdx = idx;\n\n // traverse down the stack looking for the nearest intersecting object\n for (i = idx - 1; i >= 0; --i) {\n\n var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n object.isContainedWithinObject(this._objects[i]) ||\n this._objects[i].isContainedWithinObject(object);\n\n if (isIntersecting) {\n newIdx = i;\n break;\n }\n }\n }\n else {\n newIdx = idx - 1;\n }\n\n return newIdx;\n },\n\n /**\n * Moves an object or a selection up in stack of drawn objects\n * An optional parameter, intersecting allows to move the object in front\n * of the first intersecting object. Where intersection is calculated with\n * bounding box. If no intersection is found, there will not be change in the\n * stack.\n * @param {fabric.Object} object Object to send\n * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n bringForward: function (object, intersecting) {\n if (!object) {\n return this;\n }\n var activeSelection = this._activeObject,\n i, obj, idx, newIdx, objs, objsMoved = 0;\n\n if (object === activeSelection && object.type === 'activeSelection') {\n objs = activeSelection._objects;\n for (i = objs.length; i--;) {\n obj = objs[i];\n idx = this._objects.indexOf(obj);\n if (idx < this._objects.length - 1 - objsMoved) {\n newIdx = idx + 1;\n removeFromArray(this._objects, obj);\n this._objects.splice(newIdx, 0, obj);\n }\n objsMoved++;\n }\n }\n else {\n idx = this._objects.indexOf(object);\n if (idx !== this._objects.length - 1) {\n // if object is not on top of stack (last item in an array)\n newIdx = this._findNewUpperIndex(object, idx, intersecting);\n removeFromArray(this._objects, object);\n this._objects.splice(newIdx, 0, object);\n }\n }\n this.renderOnAddRemove && this.requestRenderAll();\n return this;\n },\n\n /**\n * @private\n */\n _findNewUpperIndex: function(object, idx, intersecting) {\n var newIdx, i, len;\n\n if (intersecting) {\n newIdx = idx;\n\n // traverse up the stack looking for the nearest intersecting object\n for (i = idx + 1, len = this._objects.length; i < len; ++i) {\n\n var isIntersecting = object.intersectsWithObject(this._objects[i]) ||\n object.isContainedWithinObject(this._objects[i]) ||\n this._objects[i].isContainedWithinObject(object);\n\n if (isIntersecting) {\n newIdx = i;\n break;\n }\n }\n }\n else {\n newIdx = idx + 1;\n }\n\n return newIdx;\n },\n\n /**\n * Moves an object to specified level in stack of drawn objects\n * @param {fabric.Object} object Object to send\n * @param {Number} index Position to move to\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n moveTo: function (object, index) {\n removeFromArray(this._objects, object);\n this._objects.splice(index, 0, object);\n return this.renderOnAddRemove && this.requestRenderAll();\n },\n\n /**\n * Clears a canvas element and dispose objects\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n dispose: function () {\n // cancel eventually ongoing renders\n if (this.isRendering) {\n fabric.util.cancelAnimFrame(this.isRendering);\n this.isRendering = 0;\n }\n this.forEachObject(function(object) {\n object.dispose && object.dispose();\n });\n this._objects = [];\n if (this.backgroundImage && this.backgroundImage.dispose) {\n this.backgroundImage.dispose();\n }\n this.backgroundImage = null;\n if (this.overlayImage && this.overlayImage.dispose) {\n this.overlayImage.dispose();\n }\n this.overlayImage = null;\n this._iTextInstances = null;\n this.contextContainer = null;\n // restore canvas style\n this.lowerCanvasEl.classList.remove('lower-canvas');\n fabric.util.setStyle(this.lowerCanvasEl, this._originalCanvasStyle);\n delete this._originalCanvasStyle;\n // restore canvas size to original size in case retina scaling was applied\n this.lowerCanvasEl.setAttribute('width', this.width);\n this.lowerCanvasEl.setAttribute('height', this.height);\n fabric.util.cleanUpJsdomNode(this.lowerCanvasEl);\n this.lowerCanvasEl = undefined;\n return this;\n },\n\n /**\n * Returns a string representation of an instance\n * @return {String} string representation of an instance\n */\n toString: function () {\n return '#';\n }\n });\n\n extend(fabric.StaticCanvas.prototype, fabric.Observable);\n extend(fabric.StaticCanvas.prototype, fabric.Collection);\n extend(fabric.StaticCanvas.prototype, fabric.DataURLExporter);\n\n extend(fabric.StaticCanvas, /** @lends fabric.StaticCanvas */ {\n\n /**\n * @static\n * @type String\n * @default\n */\n EMPTY_JSON: '{\"objects\": [], \"background\": \"white\"}',\n\n /**\n * Provides a way to check support of some of the canvas methods\n * (either those of HTMLCanvasElement itself, or rendering context)\n *\n * @param {String} methodName Method to check support for;\n * Could be one of \"setLineDash\"\n * @return {Boolean | null} `true` if method is supported (or at least exists),\n * `null` if canvas element or context can not be initialized\n */\n supports: function (methodName) {\n var el = createCanvasElement();\n\n if (!el || !el.getContext) {\n return null;\n }\n\n var ctx = el.getContext('2d');\n if (!ctx) {\n return null;\n }\n\n switch (methodName) {\n\n case 'setLineDash':\n return typeof ctx.setLineDash !== 'undefined';\n\n default:\n return null;\n }\n }\n });\n\n /**\n * Returns Object representation of canvas\n * this alias is provided because if you call JSON.stringify on an instance,\n * the toJSON object will be invoked if it exists.\n * Having a toJSON method means you can do JSON.stringify(myCanvas)\n * @function\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} JSON compatible object\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#serialization}\n * @see {@link http://jsfiddle.net/fabricjs/pec86/|jsFiddle demo}\n * @example JSON without additional properties\n * var json = canvas.toJSON();\n * @example JSON with additional properties included\n * var json = canvas.toJSON(['lockMovementX', 'lockMovementY', 'lockRotation', 'lockScalingX', 'lockScalingY']);\n * @example JSON without default values\n * canvas.includeDefaultValues = false;\n * var json = canvas.toJSON();\n */\n fabric.StaticCanvas.prototype.toJSON = fabric.StaticCanvas.prototype.toObject;\n\n if (fabric.isLikelyNode) {\n fabric.StaticCanvas.prototype.createPNGStream = function() {\n var impl = getNodeCanvas(this.lowerCanvasEl);\n return impl && impl.createPNGStream();\n };\n fabric.StaticCanvas.prototype.createJPEGStream = function(opts) {\n var impl = getNodeCanvas(this.lowerCanvasEl);\n return impl && impl.createJPEGStream(opts);\n };\n }\n})();\n\n\n/**\n * BaseBrush class\n * @class fabric.BaseBrush\n * @see {@link http://fabricjs.com/freedrawing|Freedrawing demo}\n */\nfabric.BaseBrush = fabric.util.createClass(/** @lends fabric.BaseBrush.prototype */ {\n\n /**\n * Color of a brush\n * @type String\n * @default\n */\n color: 'rgb(0, 0, 0)',\n\n /**\n * Width of a brush, has to be a Number, no string literals\n * @type Number\n * @default\n */\n width: 1,\n\n /**\n * Shadow object representing shadow of this shape.\n * Backwards incompatibility note: This property replaces \"shadowColor\" (String), \"shadowOffsetX\" (Number),\n * \"shadowOffsetY\" (Number) and \"shadowBlur\" (Number) since v1.2.12\n * @type fabric.Shadow\n * @default\n */\n shadow: null,\n\n /**\n * Line endings style of a brush (one of \"butt\", \"round\", \"square\")\n * @type String\n * @default\n */\n strokeLineCap: 'round',\n\n /**\n * Corner style of a brush (one of \"bevel\", \"round\", \"miter\")\n * @type String\n * @default\n */\n strokeLineJoin: 'round',\n\n /**\n * Maximum miter length (used for strokeLineJoin = \"miter\") of a brush's\n * @type Number\n * @default\n */\n strokeMiterLimit: 10,\n\n /**\n * Stroke Dash Array.\n * @type Array\n * @default\n */\n strokeDashArray: null,\n\n /**\n * When `true`, the free drawing is limited to the whiteboard size. Default to false.\n * @type Boolean\n * @default false\n */\n\n limitedToCanvasSize: false,\n\n\n /**\n * Sets brush styles\n * @private\n * @param {CanvasRenderingContext2D} ctx\n */\n _setBrushStyles: function (ctx) {\n ctx.strokeStyle = this.color;\n ctx.lineWidth = this.width;\n ctx.lineCap = this.strokeLineCap;\n ctx.miterLimit = this.strokeMiterLimit;\n ctx.lineJoin = this.strokeLineJoin;\n ctx.setLineDash(this.strokeDashArray || []);\n },\n\n /**\n * Sets the transformation on given context\n * @param {RenderingContext2d} ctx context to render on\n * @private\n */\n _saveAndTransform: function(ctx) {\n var v = this.canvas.viewportTransform;\n ctx.save();\n ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n },\n\n /**\n * Sets brush shadow styles\n * @private\n */\n _setShadow: function() {\n if (!this.shadow) {\n return;\n }\n\n var canvas = this.canvas,\n shadow = this.shadow,\n ctx = canvas.contextTop,\n zoom = canvas.getZoom();\n if (canvas && canvas._isRetinaScaling()) {\n zoom *= fabric.devicePixelRatio;\n }\n\n ctx.shadowColor = shadow.color;\n ctx.shadowBlur = shadow.blur * zoom;\n ctx.shadowOffsetX = shadow.offsetX * zoom;\n ctx.shadowOffsetY = shadow.offsetY * zoom;\n },\n\n needsFullRender: function() {\n var color = new fabric.Color(this.color);\n return color.getAlpha() < 1 || !!this.shadow;\n },\n\n /**\n * Removes brush shadow styles\n * @private\n */\n _resetShadow: function() {\n var ctx = this.canvas.contextTop;\n\n ctx.shadowColor = '';\n ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n },\n\n /**\n * Check is pointer is outside canvas boundaries\n * @param {Object} pointer\n * @private\n */\n _isOutSideCanvas: function(pointer) {\n return pointer.x < 0 || pointer.x > this.canvas.getWidth() || pointer.y < 0 || pointer.y > this.canvas.getHeight();\n }\n});\n\n\n(function() {\n /**\n * PencilBrush class\n * @class fabric.PencilBrush\n * @extends fabric.BaseBrush\n */\n fabric.PencilBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.PencilBrush.prototype */ {\n\n /**\n * Discard points that are less than `decimate` pixel distant from each other\n * @type Number\n * @default 0.4\n */\n decimate: 0.4,\n\n /**\n * Draws a straight line between last recorded point to current pointer\n * Used for `shift` functionality\n *\n * @type boolean\n * @default false\n */\n drawStraightLine: false,\n\n /**\n * The event modifier key that makes the brush draw a straight line.\n * If `null` or 'none' or any other string that is not a modifier key the feature is disabled.\n * @type {'altKey' | 'shiftKey' | 'ctrlKey' | 'none' | undefined | null}\n */\n straightLineKey: 'shiftKey',\n\n /**\n * Constructor\n * @param {fabric.Canvas} canvas\n * @return {fabric.PencilBrush} Instance of a pencil brush\n */\n initialize: function(canvas) {\n this.canvas = canvas;\n this._points = [];\n },\n\n needsFullRender: function () {\n return this.callSuper('needsFullRender') || this._hasStraightLine;\n },\n\n /**\n * Invoked inside on mouse down and mouse move\n * @param {Object} pointer\n */\n _drawSegment: function (ctx, p1, p2) {\n var midPoint = p1.midPointFrom(p2);\n ctx.quadraticCurveTo(p1.x, p1.y, midPoint.x, midPoint.y);\n return midPoint;\n },\n\n /**\n * Invoked on mouse down\n * @param {Object} pointer\n */\n onMouseDown: function(pointer, options) {\n if (!this.canvas._isMainEvent(options.e)) {\n return;\n }\n this.drawStraightLine = options.e[this.straightLineKey];\n this._prepareForDrawing(pointer);\n // capture coordinates immediately\n // this allows to draw dots (when movement never occurs)\n this._captureDrawingPath(pointer);\n this._render();\n },\n\n /**\n * Invoked on mouse move\n * @param {Object} pointer\n */\n onMouseMove: function(pointer, options) {\n if (!this.canvas._isMainEvent(options.e)) {\n return;\n }\n this.drawStraightLine = options.e[this.straightLineKey];\n if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {\n return;\n }\n if (this._captureDrawingPath(pointer) && this._points.length > 1) {\n if (this.needsFullRender()) {\n // redraw curve\n // clear top canvas\n this.canvas.clearContext(this.canvas.contextTop);\n this._render();\n }\n else {\n var points = this._points, length = points.length, ctx = this.canvas.contextTop;\n // draw the curve update\n this._saveAndTransform(ctx);\n if (this.oldEnd) {\n ctx.beginPath();\n ctx.moveTo(this.oldEnd.x, this.oldEnd.y);\n }\n this.oldEnd = this._drawSegment(ctx, points[length - 2], points[length - 1], true);\n ctx.stroke();\n ctx.restore();\n }\n }\n },\n\n /**\n * Invoked on mouse up\n */\n onMouseUp: function(options) {\n if (!this.canvas._isMainEvent(options.e)) {\n return true;\n }\n this.drawStraightLine = false;\n this.oldEnd = undefined;\n this._finalizeAndAddPath();\n return false;\n },\n\n /**\n * @private\n * @param {Object} pointer Actual mouse position related to the canvas.\n */\n _prepareForDrawing: function(pointer) {\n\n var p = new fabric.Point(pointer.x, pointer.y);\n\n this._reset();\n this._addPoint(p);\n this.canvas.contextTop.moveTo(p.x, p.y);\n },\n\n /**\n * @private\n * @param {fabric.Point} point Point to be added to points array\n */\n _addPoint: function(point) {\n if (this._points.length > 1 && point.eq(this._points[this._points.length - 1])) {\n return false;\n }\n if (this.drawStraightLine && this._points.length > 1) {\n this._hasStraightLine = true;\n this._points.pop();\n }\n this._points.push(point);\n return true;\n },\n\n /**\n * Clear points array and set contextTop canvas style.\n * @private\n */\n _reset: function() {\n this._points = [];\n this._setBrushStyles(this.canvas.contextTop);\n this._setShadow();\n this._hasStraightLine = false;\n },\n\n /**\n * @private\n * @param {Object} pointer Actual mouse position related to the canvas.\n */\n _captureDrawingPath: function(pointer) {\n var pointerPoint = new fabric.Point(pointer.x, pointer.y);\n return this._addPoint(pointerPoint);\n },\n\n /**\n * Draw a smooth path on the topCanvas using quadraticCurveTo\n * @private\n * @param {CanvasRenderingContext2D} [ctx]\n */\n _render: function(ctx) {\n var i, len,\n p1 = this._points[0],\n p2 = this._points[1];\n ctx = ctx || this.canvas.contextTop;\n this._saveAndTransform(ctx);\n ctx.beginPath();\n //if we only have 2 points in the path and they are the same\n //it means that the user only clicked the canvas without moving the mouse\n //then we should be drawing a dot. A path isn't drawn between two identical dots\n //that's why we set them apart a bit\n if (this._points.length === 2 && p1.x === p2.x && p1.y === p2.y) {\n var width = this.width / 1000;\n p1 = new fabric.Point(p1.x, p1.y);\n p2 = new fabric.Point(p2.x, p2.y);\n p1.x -= width;\n p2.x += width;\n }\n ctx.moveTo(p1.x, p1.y);\n\n for (i = 1, len = this._points.length; i < len; i++) {\n // we pick the point between pi + 1 & pi + 2 as the\n // end point and p1 as our control point.\n this._drawSegment(ctx, p1, p2);\n p1 = this._points[i];\n p2 = this._points[i + 1];\n }\n // Draw last line as a straight line while\n // we wait for the next point to be able to calculate\n // the bezier control point\n ctx.lineTo(p1.x, p1.y);\n ctx.stroke();\n ctx.restore();\n },\n\n /**\n * Converts points to SVG path\n * @param {Array} points Array of points\n * @return {(string|number)[][]} SVG path commands\n */\n convertPointsToSVGPath: function (points) {\n var correction = this.width / 1000;\n return fabric.util.getSmoothPathFromPoints(points, correction);\n },\n\n /**\n * @private\n * @param {(string|number)[][]} pathData SVG path commands\n * @returns {boolean}\n */\n _isEmptySVGPath: function (pathData) {\n var pathString = fabric.util.joinPath(pathData);\n return pathString === 'M 0 0 Q 0 0 0 0 L 0 0';\n },\n\n /**\n * Creates fabric.Path object to add on canvas\n * @param {(string|number)[][]} pathData Path data\n * @return {fabric.Path} Path to add on canvas\n */\n createPath: function(pathData) {\n var path = new fabric.Path(pathData, {\n fill: null,\n stroke: this.color,\n strokeWidth: this.width,\n strokeLineCap: this.strokeLineCap,\n strokeMiterLimit: this.strokeMiterLimit,\n strokeLineJoin: this.strokeLineJoin,\n strokeDashArray: this.strokeDashArray,\n });\n if (this.shadow) {\n this.shadow.affectStroke = true;\n path.shadow = new fabric.Shadow(this.shadow);\n }\n\n return path;\n },\n\n /**\n * Decimate points array with the decimate value\n */\n decimatePoints: function(points, distance) {\n if (points.length <= 2) {\n return points;\n }\n var zoom = this.canvas.getZoom(), adjustedDistance = Math.pow(distance / zoom, 2),\n i, l = points.length - 1, lastPoint = points[0], newPoints = [lastPoint],\n cDistance;\n for (i = 1; i < l - 1; i++) {\n cDistance = Math.pow(lastPoint.x - points[i].x, 2) + Math.pow(lastPoint.y - points[i].y, 2);\n if (cDistance >= adjustedDistance) {\n lastPoint = points[i];\n newPoints.push(lastPoint);\n }\n }\n /**\n * Add the last point from the original line to the end of the array.\n * This ensures decimate doesn't delete the last point on the line, and ensures the line is > 1 point.\n */\n newPoints.push(points[l]);\n return newPoints;\n },\n\n /**\n * On mouseup after drawing the path on contextTop canvas\n * we use the points captured to create an new fabric path object\n * and add it to the fabric canvas.\n */\n _finalizeAndAddPath: function() {\n var ctx = this.canvas.contextTop;\n ctx.closePath();\n if (this.decimate) {\n this._points = this.decimatePoints(this._points, this.decimate);\n }\n var pathData = this.convertPointsToSVGPath(this._points);\n if (this._isEmptySVGPath(pathData)) {\n // do not create 0 width/height paths, as they are\n // rendered inconsistently across browsers\n // Firefox 4, for example, renders a dot,\n // whereas Chrome 10 renders nothing\n this.canvas.requestRenderAll();\n return;\n }\n\n var path = this.createPath(pathData);\n this.canvas.clearContext(this.canvas.contextTop);\n this.canvas.fire('before:path:created', { path: path });\n this.canvas.add(path);\n this.canvas.requestRenderAll();\n path.setCoords();\n this._resetShadow();\n\n\n // fire event 'path' created\n this.canvas.fire('path:created', { path: path });\n }\n });\n})();\n\n\n/**\n * CircleBrush class\n * @class fabric.CircleBrush\n */\nfabric.CircleBrush = fabric.util.createClass(fabric.BaseBrush, /** @lends fabric.CircleBrush.prototype */ {\n\n /**\n * Width of a brush\n * @type Number\n * @default\n */\n width: 10,\n\n /**\n * Constructor\n * @param {fabric.Canvas} canvas\n * @return {fabric.CircleBrush} Instance of a circle brush\n */\n initialize: function(canvas) {\n this.canvas = canvas;\n this.points = [];\n },\n\n /**\n * Invoked inside on mouse down and mouse move\n * @param {Object} pointer\n */\n drawDot: function(pointer) {\n var point = this.addPoint(pointer),\n ctx = this.canvas.contextTop;\n this._saveAndTransform(ctx);\n this.dot(ctx, point);\n ctx.restore();\n },\n\n dot: function(ctx, point) {\n ctx.fillStyle = point.fill;\n ctx.beginPath();\n ctx.arc(point.x, point.y, point.radius, 0, Math.PI * 2, false);\n ctx.closePath();\n ctx.fill();\n },\n\n /**\n * Invoked on mouse down\n */\n onMouseDown: function(pointer) {\n this.points.length = 0;\n this.canvas.clearContext(this.canvas.contextTop);\n this._setShadow();\n this.drawDot(pointer);\n },\n\n /**\n * Render the full state of the brush\n * @private\n */\n _render: function() {\n var ctx = this.canvas.contextTop, i, len,\n points = this.points;\n this._saveAndTransform(ctx);\n for (i = 0, len = points.length; i < len; i++) {\n this.dot(ctx, points[i]);\n }\n ctx.restore();\n },\n\n /**\n * Invoked on mouse move\n * @param {Object} pointer\n */\n onMouseMove: function(pointer) {\n if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {\n return;\n }\n if (this.needsFullRender()) {\n this.canvas.clearContext(this.canvas.contextTop);\n this.addPoint(pointer);\n this._render();\n }\n else {\n this.drawDot(pointer);\n }\n },\n\n /**\n * Invoked on mouse up\n */\n onMouseUp: function() {\n var originalRenderOnAddRemove = this.canvas.renderOnAddRemove, i, len;\n this.canvas.renderOnAddRemove = false;\n\n var circles = [];\n\n for (i = 0, len = this.points.length; i < len; i++) {\n var point = this.points[i],\n circle = new fabric.Circle({\n radius: point.radius,\n left: point.x,\n top: point.y,\n originX: 'center',\n originY: 'center',\n fill: point.fill\n });\n\n this.shadow && (circle.shadow = new fabric.Shadow(this.shadow));\n\n circles.push(circle);\n }\n var group = new fabric.Group(circles);\n group.canvas = this.canvas;\n\n this.canvas.fire('before:path:created', { path: group });\n this.canvas.add(group);\n this.canvas.fire('path:created', { path: group });\n\n this.canvas.clearContext(this.canvas.contextTop);\n this._resetShadow();\n this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n this.canvas.requestRenderAll();\n },\n\n /**\n * @param {Object} pointer\n * @return {fabric.Point} Just added pointer point\n */\n addPoint: function(pointer) {\n var pointerPoint = new fabric.Point(pointer.x, pointer.y),\n\n circleRadius = fabric.util.getRandomInt(\n Math.max(0, this.width - 20), this.width + 20) / 2,\n\n circleColor = new fabric.Color(this.color)\n .setAlpha(fabric.util.getRandomInt(0, 100) / 100)\n .toRgba();\n\n pointerPoint.radius = circleRadius;\n pointerPoint.fill = circleColor;\n\n this.points.push(pointerPoint);\n\n return pointerPoint;\n }\n});\n\n\n/**\n * SprayBrush class\n * @class fabric.SprayBrush\n */\nfabric.SprayBrush = fabric.util.createClass( fabric.BaseBrush, /** @lends fabric.SprayBrush.prototype */ {\n\n /**\n * Width of a spray\n * @type Number\n * @default\n */\n width: 10,\n\n /**\n * Density of a spray (number of dots per chunk)\n * @type Number\n * @default\n */\n density: 20,\n\n /**\n * Width of spray dots\n * @type Number\n * @default\n */\n dotWidth: 1,\n\n /**\n * Width variance of spray dots\n * @type Number\n * @default\n */\n dotWidthVariance: 1,\n\n /**\n * Whether opacity of a dot should be random\n * @type Boolean\n * @default\n */\n randomOpacity: false,\n\n /**\n * Whether overlapping dots (rectangles) should be removed (for performance reasons)\n * @type Boolean\n * @default\n */\n optimizeOverlapping: true,\n\n /**\n * Constructor\n * @param {fabric.Canvas} canvas\n * @return {fabric.SprayBrush} Instance of a spray brush\n */\n initialize: function(canvas) {\n this.canvas = canvas;\n this.sprayChunks = [];\n },\n\n /**\n * Invoked on mouse down\n * @param {Object} pointer\n */\n onMouseDown: function(pointer) {\n this.sprayChunks.length = 0;\n this.canvas.clearContext(this.canvas.contextTop);\n this._setShadow();\n\n this.addSprayChunk(pointer);\n this.render(this.sprayChunkPoints);\n },\n\n /**\n * Invoked on mouse move\n * @param {Object} pointer\n */\n onMouseMove: function(pointer) {\n if (this.limitedToCanvasSize === true && this._isOutSideCanvas(pointer)) {\n return;\n }\n this.addSprayChunk(pointer);\n this.render(this.sprayChunkPoints);\n },\n\n /**\n * Invoked on mouse up\n */\n onMouseUp: function() {\n var originalRenderOnAddRemove = this.canvas.renderOnAddRemove;\n this.canvas.renderOnAddRemove = false;\n\n var rects = [];\n\n for (var i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {\n var sprayChunk = this.sprayChunks[i];\n\n for (var j = 0, jlen = sprayChunk.length; j < jlen; j++) {\n\n var rect = new fabric.Rect({\n width: sprayChunk[j].width,\n height: sprayChunk[j].width,\n left: sprayChunk[j].x + 1,\n top: sprayChunk[j].y + 1,\n originX: 'center',\n originY: 'center',\n fill: this.color\n });\n rects.push(rect);\n }\n }\n\n if (this.optimizeOverlapping) {\n rects = this._getOptimizedRects(rects);\n }\n\n var group = new fabric.Group(rects);\n this.shadow && group.set('shadow', new fabric.Shadow(this.shadow));\n this.canvas.fire('before:path:created', { path: group });\n this.canvas.add(group);\n this.canvas.fire('path:created', { path: group });\n\n this.canvas.clearContext(this.canvas.contextTop);\n this._resetShadow();\n this.canvas.renderOnAddRemove = originalRenderOnAddRemove;\n this.canvas.requestRenderAll();\n },\n\n /**\n * @private\n * @param {Array} rects\n */\n _getOptimizedRects: function(rects) {\n\n // avoid creating duplicate rects at the same coordinates\n var uniqueRects = { }, key, i, len;\n\n for (i = 0, len = rects.length; i < len; i++) {\n key = rects[i].left + '' + rects[i].top;\n if (!uniqueRects[key]) {\n uniqueRects[key] = rects[i];\n }\n }\n var uniqueRectsArray = [];\n for (key in uniqueRects) {\n uniqueRectsArray.push(uniqueRects[key]);\n }\n\n return uniqueRectsArray;\n },\n\n /**\n * Render new chunk of spray brush\n */\n render: function(sprayChunk) {\n var ctx = this.canvas.contextTop, i, len;\n ctx.fillStyle = this.color;\n\n this._saveAndTransform(ctx);\n\n for (i = 0, len = sprayChunk.length; i < len; i++) {\n var point = sprayChunk[i];\n if (typeof point.opacity !== 'undefined') {\n ctx.globalAlpha = point.opacity;\n }\n ctx.fillRect(point.x, point.y, point.width, point.width);\n }\n ctx.restore();\n },\n\n /**\n * Render all spray chunks\n */\n _render: function() {\n var ctx = this.canvas.contextTop, i, ilen;\n ctx.fillStyle = this.color;\n\n this._saveAndTransform(ctx);\n\n for (i = 0, ilen = this.sprayChunks.length; i < ilen; i++) {\n this.render(this.sprayChunks[i]);\n }\n ctx.restore();\n },\n\n /**\n * @param {Object} pointer\n */\n addSprayChunk: function(pointer) {\n this.sprayChunkPoints = [];\n\n var x, y, width, radius = this.width / 2, i;\n\n for (i = 0; i < this.density; i++) {\n\n x = fabric.util.getRandomInt(pointer.x - radius, pointer.x + radius);\n y = fabric.util.getRandomInt(pointer.y - radius, pointer.y + radius);\n\n if (this.dotWidthVariance) {\n width = fabric.util.getRandomInt(\n // bottom clamp width to 1\n Math.max(1, this.dotWidth - this.dotWidthVariance),\n this.dotWidth + this.dotWidthVariance);\n }\n else {\n width = this.dotWidth;\n }\n\n var point = new fabric.Point(x, y);\n point.width = width;\n\n if (this.randomOpacity) {\n point.opacity = fabric.util.getRandomInt(0, 100) / 100;\n }\n\n this.sprayChunkPoints.push(point);\n }\n\n this.sprayChunks.push(this.sprayChunkPoints);\n }\n});\n\n\n/**\n * PatternBrush class\n * @class fabric.PatternBrush\n * @extends fabric.BaseBrush\n */\nfabric.PatternBrush = fabric.util.createClass(fabric.PencilBrush, /** @lends fabric.PatternBrush.prototype */ {\n\n getPatternSrc: function() {\n\n var dotWidth = 20,\n dotDistance = 5,\n patternCanvas = fabric.util.createCanvasElement(),\n patternCtx = patternCanvas.getContext('2d');\n\n patternCanvas.width = patternCanvas.height = dotWidth + dotDistance;\n\n patternCtx.fillStyle = this.color;\n patternCtx.beginPath();\n patternCtx.arc(dotWidth / 2, dotWidth / 2, dotWidth / 2, 0, Math.PI * 2, false);\n patternCtx.closePath();\n patternCtx.fill();\n\n return patternCanvas;\n },\n\n getPatternSrcFunction: function() {\n return String(this.getPatternSrc).replace('this.color', '\"' + this.color + '\"');\n },\n\n /**\n * Creates \"pattern\" instance property\n * @param {CanvasRenderingContext2D} ctx\n */\n getPattern: function(ctx) {\n return ctx.createPattern(this.source || this.getPatternSrc(), 'repeat');\n },\n\n /**\n * Sets brush styles\n * @param {CanvasRenderingContext2D} ctx\n */\n _setBrushStyles: function(ctx) {\n this.callSuper('_setBrushStyles', ctx);\n ctx.strokeStyle = this.getPattern(ctx);\n },\n\n /**\n * Creates path\n */\n createPath: function(pathData) {\n var path = this.callSuper('createPath', pathData),\n topLeft = path._getLeftTopCoords().scalarAdd(path.strokeWidth / 2);\n\n path.stroke = new fabric.Pattern({\n source: this.source || this.getPatternSrcFunction(),\n offsetX: -topLeft.x,\n offsetY: -topLeft.y\n });\n return path;\n }\n});\n\n\n(function() {\n\n var getPointer = fabric.util.getPointer,\n degreesToRadians = fabric.util.degreesToRadians,\n isTouchEvent = fabric.util.isTouchEvent;\n\n /**\n * Canvas class\n * @class fabric.Canvas\n * @extends fabric.StaticCanvas\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#canvas}\n * @see {@link fabric.Canvas#initialize} for constructor definition\n *\n * @fires object:modified at the end of a transform or any change when statefull is true\n * @fires object:rotating while an object is being rotated from the control\n * @fires object:scaling while an object is being scaled by controls\n * @fires object:moving while an object is being dragged\n * @fires object:skewing while an object is being skewed from the controls\n *\n * @fires before:transform before a transform is is started\n * @fires before:selection:cleared\n * @fires selection:cleared\n * @fires selection:updated\n * @fires selection:created\n *\n * @fires path:created after a drawing operation ends and the path is added\n * @fires mouse:down\n * @fires mouse:move\n * @fires mouse:up\n * @fires mouse:down:before on mouse down, before the inner fabric logic runs\n * @fires mouse:move:before on mouse move, before the inner fabric logic runs\n * @fires mouse:up:before on mouse up, before the inner fabric logic runs\n * @fires mouse:over\n * @fires mouse:out\n * @fires mouse:dblclick whenever a native dbl click event fires on the canvas.\n *\n * @fires dragover\n * @fires dragenter\n * @fires dragleave\n * @fires drop:before before drop event. same native event. This is added to handle edge cases\n * @fires drop\n * @fires after:render at the end of the render process, receives the context in the callback\n * @fires before:render at start the render process, receives the context in the callback\n *\n */\n fabric.Canvas = fabric.util.createClass(fabric.StaticCanvas, /** @lends fabric.Canvas.prototype */ {\n\n /**\n * Constructor\n * @param {HTMLElement | String} el <canvas> element to initialize instance on\n * @param {Object} [options] Options object\n * @return {Object} thisArg\n */\n initialize: function(el, options) {\n options || (options = { });\n this.renderAndResetBound = this.renderAndReset.bind(this);\n this.requestRenderAllBound = this.requestRenderAll.bind(this);\n this._initStatic(el, options);\n this._initInteractive();\n this._createCacheCanvas();\n },\n\n /**\n * When true, objects can be transformed by one side (unproportionally)\n * when dragged on the corners that normally would not do that.\n * @type Boolean\n * @default\n * @since fabric 4.0 // changed name and default value\n */\n uniformScaling: true,\n\n /**\n * Indicates which key switches uniform scaling.\n * values: 'altKey', 'shiftKey', 'ctrlKey'.\n * If `null` or 'none' or any other string that is not a modifier key\n * feature is disabled.\n * totally wrong named. this sounds like `uniform scaling`\n * if Canvas.uniformScaling is true, pressing this will set it to false\n * and viceversa.\n * @since 1.6.2\n * @type String\n * @default\n */\n uniScaleKey: 'shiftKey',\n\n /**\n * When true, objects use center point as the origin of scale transformation.\n * Backwards incompatibility note: This property replaces \"centerTransform\" (Boolean).\n * @since 1.3.4\n * @type Boolean\n * @default\n */\n centeredScaling: false,\n\n /**\n * When true, objects use center point as the origin of rotate transformation.\n * Backwards incompatibility note: This property replaces \"centerTransform\" (Boolean).\n * @since 1.3.4\n * @type Boolean\n * @default\n */\n centeredRotation: false,\n\n /**\n * Indicates which key enable centered Transform\n * values: 'altKey', 'shiftKey', 'ctrlKey'.\n * If `null` or 'none' or any other string that is not a modifier key\n * feature is disabled feature disabled.\n * @since 1.6.2\n * @type String\n * @default\n */\n centeredKey: 'altKey',\n\n /**\n * Indicates which key enable alternate action on corner\n * values: 'altKey', 'shiftKey', 'ctrlKey'.\n * If `null` or 'none' or any other string that is not a modifier key\n * feature is disabled feature disabled.\n * @since 1.6.2\n * @type String\n * @default\n */\n altActionKey: 'shiftKey',\n\n /**\n * Indicates that canvas is interactive. This property should not be changed.\n * @type Boolean\n * @default\n */\n interactive: true,\n\n /**\n * Indicates whether group selection should be enabled\n * @type Boolean\n * @default\n */\n selection: true,\n\n /**\n * Indicates which key or keys enable multiple click selection\n * Pass value as a string or array of strings\n * values: 'altKey', 'shiftKey', 'ctrlKey'.\n * If `null` or empty or containing any other string that is not a modifier key\n * feature is disabled.\n * @since 1.6.2\n * @type String|Array\n * @default\n */\n selectionKey: 'shiftKey',\n\n /**\n * Indicates which key enable alternative selection\n * in case of target overlapping with active object\n * values: 'altKey', 'shiftKey', 'ctrlKey'.\n * For a series of reason that come from the general expectations on how\n * things should work, this feature works only for preserveObjectStacking true.\n * If `null` or 'none' or any other string that is not a modifier key\n * feature is disabled.\n * @since 1.6.5\n * @type null|String\n * @default\n */\n altSelectionKey: null,\n\n /**\n * Color of selection\n * @type String\n * @default\n */\n selectionColor: 'rgba(100, 100, 255, 0.3)', // blue\n\n /**\n * Default dash array pattern\n * If not empty the selection border is dashed\n * @type Array\n */\n selectionDashArray: [],\n\n /**\n * Color of the border of selection (usually slightly darker than color of selection itself)\n * @type String\n * @default\n */\n selectionBorderColor: 'rgba(255, 255, 255, 0.3)',\n\n /**\n * Width of a line used in object/group selection\n * @type Number\n * @default\n */\n selectionLineWidth: 1,\n\n /**\n * Select only shapes that are fully contained in the dragged selection rectangle.\n * @type Boolean\n * @default\n */\n selectionFullyContained: false,\n\n /**\n * Default cursor value used when hovering over an object on canvas\n * @type String\n * @default\n */\n hoverCursor: 'move',\n\n /**\n * Default cursor value used when moving an object on canvas\n * @type String\n * @default\n */\n moveCursor: 'move',\n\n /**\n * Default cursor value used for the entire canvas\n * @type String\n * @default\n */\n defaultCursor: 'default',\n\n /**\n * Cursor value used during free drawing\n * @type String\n * @default\n */\n freeDrawingCursor: 'crosshair',\n\n /**\n * Cursor value used for disabled elements ( corners with disabled action )\n * @type String\n * @since 2.0.0\n * @default\n */\n notAllowedCursor: 'not-allowed',\n\n /**\n * Default element class that's given to wrapper (div) element of canvas\n * @type String\n * @default\n */\n containerClass: 'canvas-container',\n\n /**\n * When true, object detection happens on per-pixel basis rather than on per-bounding-box\n * @type Boolean\n * @default\n */\n perPixelTargetFind: false,\n\n /**\n * Number of pixels around target pixel to tolerate (consider active) during object detection\n * @type Number\n * @default\n */\n targetFindTolerance: 0,\n\n /**\n * When true, target detection is skipped. Target detection will return always undefined.\n * click selection won't work anymore, events will fire with no targets.\n * if something is selected before setting it to true, it will be deselected at the first click.\n * area selection will still work. check the `selection` property too.\n * if you deactivate both, you should look into staticCanvas.\n * @type Boolean\n * @default\n */\n skipTargetFind: false,\n\n /**\n * When true, mouse events on canvas (mousedown/mousemove/mouseup) result in free drawing.\n * After mousedown, mousemove creates a shape,\n * and then mouseup finalizes it and adds an instance of `fabric.Path` onto canvas.\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-4#free_drawing}\n * @type Boolean\n * @default\n */\n isDrawingMode: false,\n\n /**\n * Indicates whether objects should remain in current stack position when selected.\n * When false objects are brought to top and rendered as part of the selection group\n * @type Boolean\n * @default\n */\n preserveObjectStacking: false,\n\n /**\n * Indicates the angle that an object will lock to while rotating.\n * @type Number\n * @since 1.6.7\n * @default\n */\n snapAngle: 0,\n\n /**\n * Indicates the distance from the snapAngle the rotation will lock to the snapAngle.\n * When `null`, the snapThreshold will default to the snapAngle.\n * @type null|Number\n * @since 1.6.7\n * @default\n */\n snapThreshold: null,\n\n /**\n * Indicates if the right click on canvas can output the context menu or not\n * @type Boolean\n * @since 1.6.5\n * @default\n */\n stopContextMenu: false,\n\n /**\n * Indicates if the canvas can fire right click events\n * @type Boolean\n * @since 1.6.5\n * @default\n */\n fireRightClick: false,\n\n /**\n * Indicates if the canvas can fire middle click events\n * @type Boolean\n * @since 1.7.8\n * @default\n */\n fireMiddleClick: false,\n\n /**\n * Keep track of the subTargets for Mouse Events\n * @type fabric.Object[]\n */\n targets: [],\n\n /**\n * When the option is enabled, PointerEvent is used instead of MouseEvent.\n * @type Boolean\n * @default\n */\n enablePointerEvents: false,\n\n /**\n * Keep track of the hovered target\n * @type fabric.Object\n * @private\n */\n _hoveredTarget: null,\n\n /**\n * hold the list of nested targets hovered\n * @type fabric.Object[]\n * @private\n */\n _hoveredTargets: [],\n\n /**\n * @private\n */\n _initInteractive: function() {\n this._currentTransform = null;\n this._groupSelector = null;\n this._initWrapperElement();\n this._createUpperCanvas();\n this._initEventListeners();\n\n this._initRetinaScaling();\n\n this.freeDrawingBrush = fabric.PencilBrush && new fabric.PencilBrush(this);\n\n this.calcOffset();\n },\n\n /**\n * Divides objects in two groups, one to render immediately\n * and one to render as activeGroup.\n * @return {Array} objects to render immediately and pushes the other in the activeGroup.\n */\n _chooseObjectsToRender: function() {\n var activeObjects = this.getActiveObjects(),\n object, objsToRender, activeGroupObjects;\n\n if (activeObjects.length > 0 && !this.preserveObjectStacking) {\n objsToRender = [];\n activeGroupObjects = [];\n for (var i = 0, length = this._objects.length; i < length; i++) {\n object = this._objects[i];\n if (activeObjects.indexOf(object) === -1 ) {\n objsToRender.push(object);\n }\n else {\n activeGroupObjects.push(object);\n }\n }\n if (activeObjects.length > 1) {\n this._activeObject._objects = activeGroupObjects;\n }\n objsToRender.push.apply(objsToRender, activeGroupObjects);\n }\n else {\n objsToRender = this._objects;\n }\n return objsToRender;\n },\n\n /**\n * Renders both the top canvas and the secondary container canvas.\n * @return {fabric.Canvas} instance\n * @chainable\n */\n renderAll: function () {\n if (this.contextTopDirty && !this._groupSelector && !this.isDrawingMode) {\n this.clearContext(this.contextTop);\n this.contextTopDirty = false;\n }\n if (this.hasLostContext) {\n this.renderTopLayer(this.contextTop);\n this.hasLostContext = false;\n }\n var canvasToDrawOn = this.contextContainer;\n this.renderCanvas(canvasToDrawOn, this._chooseObjectsToRender());\n return this;\n },\n\n renderTopLayer: function(ctx) {\n ctx.save();\n if (this.isDrawingMode && this._isCurrentlyDrawing) {\n this.freeDrawingBrush && this.freeDrawingBrush._render();\n this.contextTopDirty = true;\n }\n // we render the top context - last object\n if (this.selection && this._groupSelector) {\n this._drawSelection(ctx);\n this.contextTopDirty = true;\n }\n ctx.restore();\n },\n\n /**\n * Method to render only the top canvas.\n * Also used to render the group selection box.\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n renderTop: function () {\n var ctx = this.contextTop;\n this.clearContext(ctx);\n this.renderTopLayer(ctx);\n this.fire('after:render');\n return this;\n },\n\n /**\n * @private\n */\n _normalizePointer: function (object, pointer) {\n var m = object.calcTransformMatrix(),\n invertedM = fabric.util.invertTransform(m),\n vptPointer = this.restorePointerVpt(pointer);\n return fabric.util.transformPoint(vptPointer, invertedM);\n },\n\n /**\n * Returns true if object is transparent at a certain location\n * @param {fabric.Object} target Object to check\n * @param {Number} x Left coordinate\n * @param {Number} y Top coordinate\n * @return {Boolean}\n */\n isTargetTransparent: function (target, x, y) {\n // in case the target is the activeObject, we cannot execute this optimization\n // because we need to draw controls too.\n if (target.shouldCache() && target._cacheCanvas && target !== this._activeObject) {\n var normalizedPointer = this._normalizePointer(target, {x: x, y: y}),\n targetRelativeX = Math.max(target.cacheTranslationX + (normalizedPointer.x * target.zoomX), 0),\n targetRelativeY = Math.max(target.cacheTranslationY + (normalizedPointer.y * target.zoomY), 0);\n\n var isTransparent = fabric.util.isTransparent(\n target._cacheContext, Math.round(targetRelativeX), Math.round(targetRelativeY), this.targetFindTolerance);\n\n return isTransparent;\n }\n\n var ctx = this.contextCache,\n originalColor = target.selectionBackgroundColor, v = this.viewportTransform;\n\n target.selectionBackgroundColor = '';\n\n this.clearContext(ctx);\n\n ctx.save();\n ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n target.render(ctx);\n ctx.restore();\n\n target.selectionBackgroundColor = originalColor;\n\n var isTransparent = fabric.util.isTransparent(\n ctx, x, y, this.targetFindTolerance);\n\n return isTransparent;\n },\n\n /**\n * takes an event and determines if selection key has been pressed\n * @private\n * @param {Event} e Event object\n */\n _isSelectionKeyPressed: function(e) {\n var selectionKeyPressed = false;\n\n if (Array.isArray(this.selectionKey)) {\n selectionKeyPressed = !!this.selectionKey.find(function(key) { return e[key] === true; });\n }\n else {\n selectionKeyPressed = e[this.selectionKey];\n }\n\n return selectionKeyPressed;\n },\n\n /**\n * @private\n * @param {Event} e Event object\n * @param {fabric.Object} target\n */\n _shouldClearSelection: function (e, target) {\n var activeObjects = this.getActiveObjects(),\n activeObject = this._activeObject;\n\n return (\n !target\n ||\n (target &&\n activeObject &&\n activeObjects.length > 1 &&\n activeObjects.indexOf(target) === -1 &&\n activeObject !== target &&\n !this._isSelectionKeyPressed(e))\n ||\n (target && !target.evented)\n ||\n (target &&\n !target.selectable &&\n activeObject &&\n activeObject !== target)\n );\n },\n\n /**\n * centeredScaling from object can't override centeredScaling from canvas.\n * this should be fixed, since object setting should take precedence over canvas.\n * also this should be something that will be migrated in the control properties.\n * as ability to define the origin of the transformation that the control provide.\n * @private\n * @param {fabric.Object} target\n * @param {String} action\n * @param {Boolean} altKey\n */\n _shouldCenterTransform: function (target, action, altKey) {\n if (!target) {\n return;\n }\n\n var centerTransform;\n\n if (action === 'scale' || action === 'scaleX' || action === 'scaleY' || action === 'resizing') {\n centerTransform = this.centeredScaling || target.centeredScaling;\n }\n else if (action === 'rotate') {\n centerTransform = this.centeredRotation || target.centeredRotation;\n }\n\n return centerTransform ? !altKey : altKey;\n },\n\n /**\n * should disappear before release 4.0\n * @private\n */\n _getOriginFromCorner: function(target, corner) {\n var origin = {\n x: target.originX,\n y: target.originY\n };\n\n if (corner === 'ml' || corner === 'tl' || corner === 'bl') {\n origin.x = 'right';\n }\n else if (corner === 'mr' || corner === 'tr' || corner === 'br') {\n origin.x = 'left';\n }\n\n if (corner === 'tl' || corner === 'mt' || corner === 'tr') {\n origin.y = 'bottom';\n }\n else if (corner === 'bl' || corner === 'mb' || corner === 'br') {\n origin.y = 'top';\n }\n return origin;\n },\n\n /**\n * @private\n * @param {Boolean} alreadySelected true if target is already selected\n * @param {String} corner a string representing the corner ml, mr, tl ...\n * @param {Event} e Event object\n * @param {fabric.Object} [target] inserted back to help overriding. Unused\n */\n _getActionFromCorner: function(alreadySelected, corner, e, target) {\n if (!corner || !alreadySelected) {\n return 'drag';\n }\n var control = target.controls[corner];\n return control.getActionName(e, control, target);\n },\n\n /**\n * @private\n * @param {Event} e Event object\n * @param {fabric.Object} target\n */\n _setupCurrentTransform: function (e, target, alreadySelected) {\n if (!target) {\n return;\n }\n\n var pointer = this.getPointer(e), corner = target.__corner,\n control = target.controls[corner],\n actionHandler = (alreadySelected && corner) ?\n control.getActionHandler(e, target, control) : fabric.controlsUtils.dragHandler,\n action = this._getActionFromCorner(alreadySelected, corner, e, target),\n origin = this._getOriginFromCorner(target, corner),\n altKey = e[this.centeredKey],\n transform = {\n target: target,\n action: action,\n actionHandler: actionHandler,\n corner: corner,\n scaleX: target.scaleX,\n scaleY: target.scaleY,\n skewX: target.skewX,\n skewY: target.skewY,\n // used by transation\n offsetX: pointer.x - target.left,\n offsetY: pointer.y - target.top,\n originX: origin.x,\n originY: origin.y,\n ex: pointer.x,\n ey: pointer.y,\n lastX: pointer.x,\n lastY: pointer.y,\n // unsure they are useful anymore.\n // left: target.left,\n // top: target.top,\n theta: degreesToRadians(target.angle),\n // end of unsure\n width: target.width * target.scaleX,\n shiftKey: e.shiftKey,\n altKey: altKey,\n original: fabric.util.saveObjectTransform(target),\n };\n\n if (this._shouldCenterTransform(target, action, altKey)) {\n transform.originX = 'center';\n transform.originY = 'center';\n }\n transform.original.originX = origin.x;\n transform.original.originY = origin.y;\n this._currentTransform = transform;\n this._beforeTransform(e);\n },\n\n /**\n * Set the cursor type of the canvas element\n * @param {String} value Cursor type of the canvas element.\n * @see http://www.w3.org/TR/css3-ui/#cursor\n */\n setCursor: function (value) {\n this.upperCanvasEl.style.cursor = value;\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx to draw the selection on\n */\n _drawSelection: function (ctx) {\n var selector = this._groupSelector,\n viewportStart = new fabric.Point(selector.ex, selector.ey),\n start = fabric.util.transformPoint(viewportStart, this.viewportTransform),\n viewportExtent = new fabric.Point(selector.ex + selector.left, selector.ey + selector.top),\n extent = fabric.util.transformPoint(viewportExtent, this.viewportTransform),\n minX = Math.min(start.x, extent.x),\n minY = Math.min(start.y, extent.y),\n maxX = Math.max(start.x, extent.x),\n maxY = Math.max(start.y, extent.y),\n strokeOffset = this.selectionLineWidth / 2;\n\n if (this.selectionColor) {\n ctx.fillStyle = this.selectionColor;\n ctx.fillRect(minX, minY, maxX - minX, maxY - minY);\n }\n\n if (!this.selectionLineWidth || !this.selectionBorderColor) {\n return;\n }\n ctx.lineWidth = this.selectionLineWidth;\n ctx.strokeStyle = this.selectionBorderColor;\n\n minX += strokeOffset;\n minY += strokeOffset;\n maxX -= strokeOffset;\n maxY -= strokeOffset;\n // selection border\n fabric.Object.prototype._setLineDash.call(this, ctx, this.selectionDashArray);\n ctx.strokeRect(minX, minY, maxX - minX, maxY - minY);\n },\n\n /**\n * Method that determines what object we are clicking on\n * the skipGroup parameter is for internal use, is needed for shift+click action\n * 11/09/2018 TODO: would be cool if findTarget could discern between being a full target\n * or the outside part of the corner.\n * @param {Event} e mouse event\n * @param {Boolean} skipGroup when true, activeGroup is skipped and only objects are traversed through\n * @return {fabric.Object} the target found\n */\n findTarget: function (e, skipGroup) {\n if (this.skipTargetFind) {\n return;\n }\n\n var ignoreZoom = true,\n pointer = this.getPointer(e, ignoreZoom),\n activeObject = this._activeObject,\n aObjects = this.getActiveObjects(),\n activeTarget, activeTargetSubs,\n isTouch = isTouchEvent(e),\n shouldLookForActive = (aObjects.length > 1 && !skipGroup) || aObjects.length === 1;\n\n // first check current group (if one exists)\n // active group does not check sub targets like normal groups.\n // if active group just exits.\n this.targets = [];\n\n // if we hit the corner of an activeObject, let's return that.\n if (shouldLookForActive && activeObject._findTargetCorner(pointer, isTouch)) {\n return activeObject;\n }\n if (aObjects.length > 1 && !skipGroup && activeObject === this._searchPossibleTargets([activeObject], pointer)) {\n return activeObject;\n }\n if (aObjects.length === 1 &&\n activeObject === this._searchPossibleTargets([activeObject], pointer)) {\n if (!this.preserveObjectStacking) {\n return activeObject;\n }\n else {\n activeTarget = activeObject;\n activeTargetSubs = this.targets;\n this.targets = [];\n }\n }\n var target = this._searchPossibleTargets(this._objects, pointer);\n if (e[this.altSelectionKey] && target && activeTarget && target !== activeTarget) {\n target = activeTarget;\n this.targets = activeTargetSubs;\n }\n return target;\n },\n\n /**\n * Checks point is inside the object.\n * @param {Object} [pointer] x,y object of point coordinates we want to check.\n * @param {fabric.Object} obj Object to test against\n * @param {Object} [globalPointer] x,y object of point coordinates relative to canvas used to search per pixel target.\n * @return {Boolean} true if point is contained within an area of given object\n * @private\n */\n _checkTarget: function(pointer, obj, globalPointer) {\n if (obj &&\n obj.visible &&\n obj.evented &&\n // http://www.geog.ubc.ca/courses/klink/gis.notes/ncgia/u32.html\n // http://idav.ucdavis.edu/~okreylos/TAship/Spring2000/PointInPolygon.html\n obj.containsPoint(pointer)\n ) {\n if ((this.perPixelTargetFind || obj.perPixelTargetFind) && !obj.isEditing) {\n var isTransparent = this.isTargetTransparent(obj, globalPointer.x, globalPointer.y);\n if (!isTransparent) {\n return true;\n }\n }\n else {\n return true;\n }\n }\n },\n\n /**\n * Function used to search inside objects an object that contains pointer in bounding box or that contains pointerOnCanvas when painted\n * @param {Array} [objects] objects array to look into\n * @param {Object} [pointer] x,y object of point coordinates we want to check.\n * @return {fabric.Object} object that contains pointer\n * @private\n */\n _searchPossibleTargets: function(objects, pointer) {\n // Cache all targets where their bounding box contains point.\n var target, i = objects.length, subTarget;\n // Do not check for currently grouped objects, since we check the parent group itself.\n // until we call this function specifically to search inside the activeGroup\n while (i--) {\n var objToCheck = objects[i];\n var pointerToUse = objToCheck.group ?\n this._normalizePointer(objToCheck.group, pointer) : pointer;\n if (this._checkTarget(pointerToUse, objToCheck, pointer)) {\n target = objects[i];\n if (target.subTargetCheck && target instanceof fabric.Group) {\n subTarget = this._searchPossibleTargets(target._objects, pointer);\n subTarget && this.targets.push(subTarget);\n }\n break;\n }\n }\n return target;\n },\n\n /**\n * Returns pointer coordinates without the effect of the viewport\n * @param {Object} pointer with \"x\" and \"y\" number values\n * @return {Object} object with \"x\" and \"y\" number values\n */\n restorePointerVpt: function(pointer) {\n return fabric.util.transformPoint(\n pointer,\n fabric.util.invertTransform(this.viewportTransform)\n );\n },\n\n /**\n * Returns pointer coordinates relative to canvas.\n * Can return coordinates with or without viewportTransform.\n * ignoreZoom false gives back coordinates that represent\n * the point clicked on canvas element.\n * ignoreZoom true gives back coordinates after being processed\n * by the viewportTransform ( sort of coordinates of what is displayed\n * on the canvas where you are clicking.\n * ignoreZoom true = HTMLElement coordinates relative to top,left\n * ignoreZoom false, default = fabric space coordinates, the same used for shape position\n * To interact with your shapes top and left you want to use ignoreZoom true\n * most of the time, while ignoreZoom false will give you coordinates\n * compatible with the object.oCoords system.\n * of the time.\n * @param {Event} e\n * @param {Boolean} ignoreZoom\n * @return {Object} object with \"x\" and \"y\" number values\n */\n getPointer: function (e, ignoreZoom) {\n // return cached values if we are in the event processing chain\n if (this._absolutePointer && !ignoreZoom) {\n return this._absolutePointer;\n }\n if (this._pointer && ignoreZoom) {\n return this._pointer;\n }\n\n var pointer = getPointer(e),\n upperCanvasEl = this.upperCanvasEl,\n bounds = upperCanvasEl.getBoundingClientRect(),\n boundsWidth = bounds.width || 0,\n boundsHeight = bounds.height || 0,\n cssScale;\n\n if (!boundsWidth || !boundsHeight ) {\n if ('top' in bounds && 'bottom' in bounds) {\n boundsHeight = Math.abs( bounds.top - bounds.bottom );\n }\n if ('right' in bounds && 'left' in bounds) {\n boundsWidth = Math.abs( bounds.right - bounds.left );\n }\n }\n\n this.calcOffset();\n pointer.x = pointer.x - this._offset.left;\n pointer.y = pointer.y - this._offset.top;\n if (!ignoreZoom) {\n pointer = this.restorePointerVpt(pointer);\n }\n\n var retinaScaling = this.getRetinaScaling();\n if (retinaScaling !== 1) {\n pointer.x /= retinaScaling;\n pointer.y /= retinaScaling;\n }\n\n if (boundsWidth === 0 || boundsHeight === 0) {\n // If bounds are not available (i.e. not visible), do not apply scale.\n cssScale = { width: 1, height: 1 };\n }\n else {\n cssScale = {\n width: upperCanvasEl.width / boundsWidth,\n height: upperCanvasEl.height / boundsHeight\n };\n }\n\n return {\n x: pointer.x * cssScale.width,\n y: pointer.y * cssScale.height\n };\n },\n\n /**\n * @private\n * @throws {CANVAS_INIT_ERROR} If canvas can not be initialized\n */\n _createUpperCanvas: function () {\n var lowerCanvasClass = this.lowerCanvasEl.className.replace(/\\s*lower-canvas\\s*/, ''),\n lowerCanvasEl = this.lowerCanvasEl, upperCanvasEl = this.upperCanvasEl;\n\n // there is no need to create a new upperCanvas element if we have already one.\n if (upperCanvasEl) {\n upperCanvasEl.className = '';\n }\n else {\n upperCanvasEl = this._createCanvasElement();\n this.upperCanvasEl = upperCanvasEl;\n }\n fabric.util.addClass(upperCanvasEl, 'upper-canvas ' + lowerCanvasClass);\n\n this.wrapperEl.appendChild(upperCanvasEl);\n\n this._copyCanvasStyle(lowerCanvasEl, upperCanvasEl);\n this._applyCanvasStyle(upperCanvasEl);\n this.contextTop = upperCanvasEl.getContext('2d');\n },\n\n /**\n * Returns context of top canvas where interactions are drawn\n * @returns {CanvasRenderingContext2D}\n */\n getTopContext: function () {\n return this.contextTop;\n },\n\n /**\n * @private\n */\n _createCacheCanvas: function () {\n this.cacheCanvasEl = this._createCanvasElement();\n this.cacheCanvasEl.setAttribute('width', this.width);\n this.cacheCanvasEl.setAttribute('height', this.height);\n this.contextCache = this.cacheCanvasEl.getContext('2d');\n },\n\n /**\n * @private\n */\n _initWrapperElement: function () {\n this.wrapperEl = fabric.util.wrapElement(this.lowerCanvasEl, 'div', {\n 'class': this.containerClass\n });\n fabric.util.setStyle(this.wrapperEl, {\n width: this.width + 'px',\n height: this.height + 'px',\n position: 'relative'\n });\n fabric.util.makeElementUnselectable(this.wrapperEl);\n },\n\n /**\n * @private\n * @param {HTMLElement} element canvas element to apply styles on\n */\n _applyCanvasStyle: function (element) {\n var width = this.width || element.width,\n height = this.height || element.height;\n\n fabric.util.setStyle(element, {\n position: 'absolute',\n width: width + 'px',\n height: height + 'px',\n left: 0,\n top: 0,\n 'touch-action': this.allowTouchScrolling ? 'manipulation' : 'none',\n '-ms-touch-action': this.allowTouchScrolling ? 'manipulation' : 'none'\n });\n element.width = width;\n element.height = height;\n fabric.util.makeElementUnselectable(element);\n },\n\n /**\n * Copy the entire inline style from one element (fromEl) to another (toEl)\n * @private\n * @param {Element} fromEl Element style is copied from\n * @param {Element} toEl Element copied style is applied to\n */\n _copyCanvasStyle: function (fromEl, toEl) {\n toEl.style.cssText = fromEl.style.cssText;\n },\n\n /**\n * Returns context of canvas where object selection is drawn\n * @return {CanvasRenderingContext2D}\n */\n getSelectionContext: function() {\n return this.contextTop;\n },\n\n /**\n * Returns <canvas> element on which object selection is drawn\n * @return {HTMLCanvasElement}\n */\n getSelectionElement: function () {\n return this.upperCanvasEl;\n },\n\n /**\n * Returns currently active object\n * @return {fabric.Object} active object\n */\n getActiveObject: function () {\n return this._activeObject;\n },\n\n /**\n * Returns an array with the current selected objects\n * @return {fabric.Object} active object\n */\n getActiveObjects: function () {\n var active = this._activeObject;\n if (active) {\n if (active.type === 'activeSelection' && active._objects) {\n return active._objects.slice(0);\n }\n else {\n return [active];\n }\n }\n return [];\n },\n\n /**\n * @private\n * @param {fabric.Object} obj Object that was removed\n */\n _onObjectRemoved: function(obj) {\n // removing active object should fire \"selection:cleared\" events\n if (obj === this._activeObject) {\n this.fire('before:selection:cleared', { target: obj });\n this._discardActiveObject();\n this.fire('selection:cleared', { target: obj });\n obj.fire('deselected');\n }\n if (obj === this._hoveredTarget){\n this._hoveredTarget = null;\n this._hoveredTargets = [];\n }\n this.callSuper('_onObjectRemoved', obj);\n },\n\n /**\n * @private\n * Compares the old activeObject with the current one and fires correct events\n * @param {fabric.Object} obj old activeObject\n */\n _fireSelectionEvents: function(oldObjects, e) {\n var somethingChanged = false, objects = this.getActiveObjects(),\n added = [], removed = [];\n oldObjects.forEach(function(oldObject) {\n if (objects.indexOf(oldObject) === -1) {\n somethingChanged = true;\n oldObject.fire('deselected', {\n e: e,\n target: oldObject\n });\n removed.push(oldObject);\n }\n });\n objects.forEach(function(object) {\n if (oldObjects.indexOf(object) === -1) {\n somethingChanged = true;\n object.fire('selected', {\n e: e,\n target: object\n });\n added.push(object);\n }\n });\n if (oldObjects.length > 0 && objects.length > 0) {\n somethingChanged && this.fire('selection:updated', {\n e: e,\n selected: added,\n deselected: removed,\n });\n }\n else if (objects.length > 0) {\n this.fire('selection:created', {\n e: e,\n selected: added,\n });\n }\n else if (oldObjects.length > 0) {\n this.fire('selection:cleared', {\n e: e,\n deselected: removed,\n });\n }\n },\n\n /**\n * Sets given object as the only active object on canvas\n * @param {fabric.Object} object Object to set as an active one\n * @param {Event} [e] Event (passed along when firing \"object:selected\")\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n setActiveObject: function (object, e) {\n var currentActives = this.getActiveObjects();\n this._setActiveObject(object, e);\n this._fireSelectionEvents(currentActives, e);\n return this;\n },\n\n /**\n * This is a private method for now.\n * This is supposed to be equivalent to setActiveObject but without firing\n * any event. There is commitment to have this stay this way.\n * This is the functional part of setActiveObject.\n * @private\n * @param {Object} object to set as active\n * @param {Event} [e] Event (passed along when firing \"object:selected\")\n * @return {Boolean} true if the selection happened\n */\n _setActiveObject: function(object, e) {\n if (this._activeObject === object) {\n return false;\n }\n if (!this._discardActiveObject(e, object)) {\n return false;\n }\n if (object.onSelect({ e: e })) {\n return false;\n }\n this._activeObject = object;\n return true;\n },\n\n /**\n * This is a private method for now.\n * This is supposed to be equivalent to discardActiveObject but without firing\n * any events. There is commitment to have this stay this way.\n * This is the functional part of discardActiveObject.\n * @param {Event} [e] Event (passed along when firing \"object:deselected\")\n * @param {Object} object to set as active\n * @return {Boolean} true if the selection happened\n * @private\n */\n _discardActiveObject: function(e, object) {\n var obj = this._activeObject;\n if (obj) {\n // onDeselect return TRUE to cancel selection;\n if (obj.onDeselect({ e: e, object: object })) {\n return false;\n }\n this._activeObject = null;\n }\n return true;\n },\n\n /**\n * Discards currently active object and fire events. If the function is called by fabric\n * as a consequence of a mouse event, the event is passed as a parameter and\n * sent to the fire function for the custom events. When used as a method the\n * e param does not have any application.\n * @param {event} e\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n discardActiveObject: function (e) {\n var currentActives = this.getActiveObjects(), activeObject = this.getActiveObject();\n if (currentActives.length) {\n this.fire('before:selection:cleared', { target: activeObject, e: e });\n }\n this._discardActiveObject(e);\n this._fireSelectionEvents(currentActives, e);\n return this;\n },\n\n /**\n * Clears a canvas element and removes all event listeners\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n dispose: function () {\n var wrapper = this.wrapperEl;\n this.removeListeners();\n wrapper.removeChild(this.upperCanvasEl);\n wrapper.removeChild(this.lowerCanvasEl);\n this.contextCache = null;\n this.contextTop = null;\n ['upperCanvasEl', 'cacheCanvasEl'].forEach((function(element) {\n fabric.util.cleanUpJsdomNode(this[element]);\n this[element] = undefined;\n }).bind(this));\n if (wrapper.parentNode) {\n wrapper.parentNode.replaceChild(this.lowerCanvasEl, this.wrapperEl);\n }\n delete this.wrapperEl;\n fabric.StaticCanvas.prototype.dispose.call(this);\n return this;\n },\n\n /**\n * Clears all contexts (background, main, top) of an instance\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n clear: function () {\n // this.discardActiveGroup();\n this.discardActiveObject();\n this.clearContext(this.contextTop);\n return this.callSuper('clear');\n },\n\n /**\n * Draws objects' controls (borders/controls)\n * @param {CanvasRenderingContext2D} ctx Context to render controls on\n */\n drawControls: function(ctx) {\n var activeObject = this._activeObject;\n\n if (activeObject) {\n activeObject._renderControls(ctx);\n }\n },\n\n /**\n * @private\n */\n _toObject: function(instance, methodName, propertiesToInclude) {\n //If the object is part of the current selection group, it should\n //be transformed appropriately\n //i.e. it should be serialised as it would appear if the selection group\n //were to be destroyed.\n var originalProperties = this._realizeGroupTransformOnObject(instance),\n object = this.callSuper('_toObject', instance, methodName, propertiesToInclude);\n //Undo the damage we did by changing all of its properties\n this._unwindGroupTransformOnObject(instance, originalProperties);\n return object;\n },\n\n /**\n * Realises an object's group transformation on it\n * @private\n * @param {fabric.Object} [instance] the object to transform (gets mutated)\n * @returns the original values of instance which were changed\n */\n _realizeGroupTransformOnObject: function(instance) {\n if (instance.group && instance.group.type === 'activeSelection' && this._activeObject === instance.group) {\n var layoutProps = ['angle', 'flipX', 'flipY', 'left', 'scaleX', 'scaleY', 'skewX', 'skewY', 'top'];\n //Copy all the positionally relevant properties across now\n var originalValues = {};\n layoutProps.forEach(function(prop) {\n originalValues[prop] = instance[prop];\n });\n fabric.util.addTransformToObject(instance, this._activeObject.calcOwnMatrix());\n return originalValues;\n }\n else {\n return null;\n }\n },\n\n /**\n * Restores the changed properties of instance\n * @private\n * @param {fabric.Object} [instance] the object to un-transform (gets mutated)\n * @param {Object} [originalValues] the original values of instance, as returned by _realizeGroupTransformOnObject\n */\n _unwindGroupTransformOnObject: function(instance, originalValues) {\n if (originalValues) {\n instance.set(originalValues);\n }\n },\n\n /**\n * @private\n */\n _setSVGObject: function(markup, instance, reviver) {\n //If the object is in a selection group, simulate what would happen to that\n //object when the group is deselected\n var originalProperties = this._realizeGroupTransformOnObject(instance);\n this.callSuper('_setSVGObject', markup, instance, reviver);\n this._unwindGroupTransformOnObject(instance, originalProperties);\n },\n\n setViewportTransform: function (vpt) {\n if (this.renderOnAddRemove && this._activeObject && this._activeObject.isEditing) {\n this._activeObject.clearContextTop();\n }\n fabric.StaticCanvas.prototype.setViewportTransform.call(this, vpt);\n }\n });\n\n // copying static properties manually to work around Opera's bug,\n // where \"prototype\" property is enumerable and overrides existing prototype\n for (var prop in fabric.StaticCanvas) {\n if (prop !== 'prototype') {\n fabric.Canvas[prop] = fabric.StaticCanvas[prop];\n }\n }\n})();\n\n\n(function() {\n\n var addListener = fabric.util.addListener,\n removeListener = fabric.util.removeListener,\n RIGHT_CLICK = 3, MIDDLE_CLICK = 2, LEFT_CLICK = 1,\n addEventOptions = { passive: false };\n\n function checkClick(e, value) {\n return e.button && (e.button === value - 1);\n }\n\n fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n /**\n * Contains the id of the touch event that owns the fabric transform\n * @type Number\n * @private\n */\n mainTouchId: null,\n\n /**\n * Adds mouse listeners to canvas\n * @private\n */\n _initEventListeners: function () {\n // in case we initialized the class twice. This should not happen normally\n // but in some kind of applications where the canvas element may be changed\n // this is a workaround to having double listeners.\n this.removeListeners();\n this._bindEvents();\n this.addOrRemove(addListener, 'add');\n },\n\n /**\n * return an event prefix pointer or mouse.\n * @private\n */\n _getEventPrefix: function () {\n return this.enablePointerEvents ? 'pointer' : 'mouse';\n },\n\n addOrRemove: function(functor, eventjsFunctor) {\n var canvasElement = this.upperCanvasEl,\n eventTypePrefix = this._getEventPrefix();\n functor(fabric.window, 'resize', this._onResize);\n functor(canvasElement, eventTypePrefix + 'down', this._onMouseDown);\n functor(canvasElement, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n functor(canvasElement, eventTypePrefix + 'out', this._onMouseOut);\n functor(canvasElement, eventTypePrefix + 'enter', this._onMouseEnter);\n functor(canvasElement, 'wheel', this._onMouseWheel);\n functor(canvasElement, 'contextmenu', this._onContextMenu);\n functor(canvasElement, 'dblclick', this._onDoubleClick);\n functor(canvasElement, 'dragover', this._onDragOver);\n functor(canvasElement, 'dragenter', this._onDragEnter);\n functor(canvasElement, 'dragleave', this._onDragLeave);\n functor(canvasElement, 'drop', this._onDrop);\n if (!this.enablePointerEvents) {\n functor(canvasElement, 'touchstart', this._onTouchStart, addEventOptions);\n }\n if (typeof eventjs !== 'undefined' && eventjsFunctor in eventjs) {\n eventjs[eventjsFunctor](canvasElement, 'gesture', this._onGesture);\n eventjs[eventjsFunctor](canvasElement, 'drag', this._onDrag);\n eventjs[eventjsFunctor](canvasElement, 'orientation', this._onOrientationChange);\n eventjs[eventjsFunctor](canvasElement, 'shake', this._onShake);\n eventjs[eventjsFunctor](canvasElement, 'longpress', this._onLongPress);\n }\n },\n\n /**\n * Removes all event listeners\n */\n removeListeners: function() {\n this.addOrRemove(removeListener, 'remove');\n // if you dispose on a mouseDown, before mouse up, you need to clean document to...\n var eventTypePrefix = this._getEventPrefix();\n removeListener(fabric.document, eventTypePrefix + 'up', this._onMouseUp);\n removeListener(fabric.document, 'touchend', this._onTouchEnd, addEventOptions);\n removeListener(fabric.document, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n removeListener(fabric.document, 'touchmove', this._onMouseMove, addEventOptions);\n },\n\n /**\n * @private\n */\n _bindEvents: function() {\n if (this.eventsBound) {\n // for any reason we pass here twice we do not want to bind events twice.\n return;\n }\n this._onMouseDown = this._onMouseDown.bind(this);\n this._onTouchStart = this._onTouchStart.bind(this);\n this._onMouseMove = this._onMouseMove.bind(this);\n this._onMouseUp = this._onMouseUp.bind(this);\n this._onTouchEnd = this._onTouchEnd.bind(this);\n this._onResize = this._onResize.bind(this);\n this._onGesture = this._onGesture.bind(this);\n this._onDrag = this._onDrag.bind(this);\n this._onShake = this._onShake.bind(this);\n this._onLongPress = this._onLongPress.bind(this);\n this._onOrientationChange = this._onOrientationChange.bind(this);\n this._onMouseWheel = this._onMouseWheel.bind(this);\n this._onMouseOut = this._onMouseOut.bind(this);\n this._onMouseEnter = this._onMouseEnter.bind(this);\n this._onContextMenu = this._onContextMenu.bind(this);\n this._onDoubleClick = this._onDoubleClick.bind(this);\n this._onDragOver = this._onDragOver.bind(this);\n this._onDragEnter = this._simpleEventHandler.bind(this, 'dragenter');\n this._onDragLeave = this._simpleEventHandler.bind(this, 'dragleave');\n this._onDrop = this._onDrop.bind(this);\n this.eventsBound = true;\n },\n\n /**\n * @private\n * @param {Event} [e] Event object fired on Event.js gesture\n * @param {Event} [self] Inner Event object\n */\n _onGesture: function(e, self) {\n this.__onTransformGesture && this.__onTransformGesture(e, self);\n },\n\n /**\n * @private\n * @param {Event} [e] Event object fired on Event.js drag\n * @param {Event} [self] Inner Event object\n */\n _onDrag: function(e, self) {\n this.__onDrag && this.__onDrag(e, self);\n },\n\n /**\n * @private\n * @param {Event} [e] Event object fired on wheel event\n */\n _onMouseWheel: function(e) {\n this.__onMouseWheel(e);\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n _onMouseOut: function(e) {\n var target = this._hoveredTarget;\n this.fire('mouse:out', { target: target, e: e });\n this._hoveredTarget = null;\n target && target.fire('mouseout', { e: e });\n\n var _this = this;\n this._hoveredTargets.forEach(function(_target){\n _this.fire('mouse:out', { target: target, e: e });\n _target && target.fire('mouseout', { e: e });\n });\n this._hoveredTargets = [];\n\n if (this._iTextInstances) {\n this._iTextInstances.forEach(function(obj) {\n if (obj.isEditing) {\n obj.hiddenTextarea.focus();\n }\n });\n }\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mouseenter\n */\n _onMouseEnter: function(e) {\n // This find target and consequent 'mouse:over' is used to\n // clear old instances on hovered target.\n // calling findTarget has the side effect of killing target.__corner.\n // as a short term fix we are not firing this if we are currently transforming.\n // as a long term fix we need to separate the action of finding a target with the\n // side effects we added to it.\n if (!this._currentTransform && !this.findTarget(e)) {\n this.fire('mouse:over', { target: null, e: e });\n this._hoveredTarget = null;\n this._hoveredTargets = [];\n }\n },\n\n /**\n * @private\n * @param {Event} [e] Event object fired on Event.js orientation change\n * @param {Event} [self] Inner Event object\n */\n _onOrientationChange: function(e, self) {\n this.__onOrientationChange && this.__onOrientationChange(e, self);\n },\n\n /**\n * @private\n * @param {Event} [e] Event object fired on Event.js shake\n * @param {Event} [self] Inner Event object\n */\n _onShake: function(e, self) {\n this.__onShake && this.__onShake(e, self);\n },\n\n /**\n * @private\n * @param {Event} [e] Event object fired on Event.js shake\n * @param {Event} [self] Inner Event object\n */\n _onLongPress: function(e, self) {\n this.__onLongPress && this.__onLongPress(e, self);\n },\n\n /**\n * prevent default to allow drop event to be fired\n * @private\n * @param {Event} [e] Event object fired on Event.js shake\n */\n _onDragOver: function(e) {\n e.preventDefault();\n var target = this._simpleEventHandler('dragover', e);\n this._fireEnterLeaveEvents(target, e);\n },\n\n /**\n * `drop:before` is a an event that allow you to schedule logic\n * before the `drop` event. Prefer `drop` event always, but if you need\n * to run some drop-disabling logic on an event, since there is no way\n * to handle event handlers ordering, use `drop:before`\n * @param {Event} e\n */\n _onDrop: function (e) {\n this._simpleEventHandler('drop:before', e);\n return this._simpleEventHandler('drop', e);\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n _onContextMenu: function (e) {\n if (this.stopContextMenu) {\n e.stopPropagation();\n e.preventDefault();\n }\n return false;\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n _onDoubleClick: function (e) {\n this._cacheTransformEventData(e);\n this._handleEvent(e, 'dblclick');\n this._resetTransformEventData(e);\n },\n\n /**\n * Return a the id of an event.\n * returns either the pointerId or the identifier or 0 for the mouse event\n * @private\n * @param {Event} evt Event object\n */\n getPointerId: function(evt) {\n var changedTouches = evt.changedTouches;\n\n if (changedTouches) {\n return changedTouches[0] && changedTouches[0].identifier;\n }\n\n if (this.enablePointerEvents) {\n return evt.pointerId;\n }\n\n return -1;\n },\n\n /**\n * Determines if an event has the id of the event that is considered main\n * @private\n * @param {evt} event Event object\n */\n _isMainEvent: function(evt) {\n if (evt.isPrimary === true) {\n return true;\n }\n if (evt.isPrimary === false) {\n return false;\n }\n if (evt.type === 'touchend' && evt.touches.length === 0) {\n return true;\n }\n if (evt.changedTouches) {\n return evt.changedTouches[0].identifier === this.mainTouchId;\n }\n return true;\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n _onTouchStart: function(e) {\n e.preventDefault();\n if (this.mainTouchId === null) {\n this.mainTouchId = this.getPointerId(e);\n }\n this.__onMouseDown(e);\n this._resetTransformEventData();\n var canvasElement = this.upperCanvasEl,\n eventTypePrefix = this._getEventPrefix();\n addListener(fabric.document, 'touchend', this._onTouchEnd, addEventOptions);\n addListener(fabric.document, 'touchmove', this._onMouseMove, addEventOptions);\n // Unbind mousedown to prevent double triggers from touch devices\n removeListener(canvasElement, eventTypePrefix + 'down', this._onMouseDown);\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n _onMouseDown: function (e) {\n this.__onMouseDown(e);\n this._resetTransformEventData();\n var canvasElement = this.upperCanvasEl,\n eventTypePrefix = this._getEventPrefix();\n removeListener(canvasElement, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n addListener(fabric.document, eventTypePrefix + 'up', this._onMouseUp);\n addListener(fabric.document, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n _onTouchEnd: function(e) {\n if (e.touches.length > 0) {\n // if there are still touches stop here\n return;\n }\n this.__onMouseUp(e);\n this._resetTransformEventData();\n this.mainTouchId = null;\n var eventTypePrefix = this._getEventPrefix();\n removeListener(fabric.document, 'touchend', this._onTouchEnd, addEventOptions);\n removeListener(fabric.document, 'touchmove', this._onMouseMove, addEventOptions);\n var _this = this;\n if (this._willAddMouseDown) {\n clearTimeout(this._willAddMouseDown);\n }\n this._willAddMouseDown = setTimeout(function() {\n // Wait 400ms before rebinding mousedown to prevent double triggers\n // from touch devices\n addListener(_this.upperCanvasEl, eventTypePrefix + 'down', _this._onMouseDown);\n _this._willAddMouseDown = 0;\n }, 400);\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mouseup\n */\n _onMouseUp: function (e) {\n this.__onMouseUp(e);\n this._resetTransformEventData();\n var canvasElement = this.upperCanvasEl,\n eventTypePrefix = this._getEventPrefix();\n if (this._isMainEvent(e)) {\n removeListener(fabric.document, eventTypePrefix + 'up', this._onMouseUp);\n removeListener(fabric.document, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n addListener(canvasElement, eventTypePrefix + 'move', this._onMouseMove, addEventOptions);\n }\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousemove\n */\n _onMouseMove: function (e) {\n !this.allowTouchScrolling && e.preventDefault && e.preventDefault();\n this.__onMouseMove(e);\n },\n\n /**\n * @private\n */\n _onResize: function () {\n this.calcOffset();\n },\n\n /**\n * Decides whether the canvas should be redrawn in mouseup and mousedown events.\n * @private\n * @param {Object} target\n */\n _shouldRender: function(target) {\n var activeObject = this._activeObject;\n\n if (\n !!activeObject !== !!target ||\n (activeObject && target && (activeObject !== target))\n ) {\n // this covers: switch of target, from target to no target, selection of target\n // multiSelection with key and mouse\n return true;\n }\n else if (activeObject && activeObject.isEditing) {\n // if we mouse up/down over a editing textbox a cursor change,\n // there is no need to re render\n return false;\n }\n return false;\n },\n\n /**\n * Method that defines the actions when mouse is released on canvas.\n * The method resets the currentTransform parameters, store the image corner\n * position in the image object and render the canvas on top.\n * @private\n * @param {Event} e Event object fired on mouseup\n */\n __onMouseUp: function (e) {\n var target, transform = this._currentTransform,\n groupSelector = this._groupSelector, shouldRender = false,\n isClick = (!groupSelector || (groupSelector.left === 0 && groupSelector.top === 0));\n this._cacheTransformEventData(e);\n target = this._target;\n this._handleEvent(e, 'up:before');\n // if right/middle click just fire events and return\n // target undefined will make the _handleEvent search the target\n if (checkClick(e, RIGHT_CLICK)) {\n if (this.fireRightClick) {\n this._handleEvent(e, 'up', RIGHT_CLICK, isClick);\n }\n return;\n }\n\n if (checkClick(e, MIDDLE_CLICK)) {\n if (this.fireMiddleClick) {\n this._handleEvent(e, 'up', MIDDLE_CLICK, isClick);\n }\n this._resetTransformEventData();\n return;\n }\n\n if (this.isDrawingMode && this._isCurrentlyDrawing) {\n this._onMouseUpInDrawingMode(e);\n return;\n }\n\n if (!this._isMainEvent(e)) {\n return;\n }\n if (transform) {\n this._finalizeCurrentTransform(e);\n shouldRender = transform.actionPerformed;\n }\n if (!isClick) {\n var targetWasActive = target === this._activeObject;\n this._maybeGroupObjects(e);\n if (!shouldRender) {\n shouldRender = (\n this._shouldRender(target) ||\n (!targetWasActive && target === this._activeObject)\n );\n }\n }\n var corner, pointer;\n if (target) {\n corner = target._findTargetCorner(\n this.getPointer(e, true),\n fabric.util.isTouchEvent(e)\n );\n if (target.selectable && target !== this._activeObject && target.activeOn === 'up') {\n this.setActiveObject(target, e);\n shouldRender = true;\n }\n else {\n var control = target.controls[corner],\n mouseUpHandler = control && control.getMouseUpHandler(e, target, control);\n if (mouseUpHandler) {\n pointer = this.getPointer(e);\n mouseUpHandler(e, transform, pointer.x, pointer.y);\n }\n }\n target.isMoving = false;\n }\n // if we are ending up a transform on a different control or a new object\n // fire the original mouse up from the corner that started the transform\n if (transform && (transform.target !== target || transform.corner !== corner)) {\n var originalControl = transform.target && transform.target.controls[transform.corner],\n originalMouseUpHandler = originalControl && originalControl.getMouseUpHandler(e, target, control);\n pointer = pointer || this.getPointer(e);\n originalMouseUpHandler && originalMouseUpHandler(e, transform, pointer.x, pointer.y);\n }\n this._setCursorFromEvent(e, target);\n this._handleEvent(e, 'up', LEFT_CLICK, isClick);\n this._groupSelector = null;\n this._currentTransform = null;\n // reset the target information about which corner is selected\n target && (target.__corner = 0);\n if (shouldRender) {\n this.requestRenderAll();\n }\n else if (!isClick) {\n this.renderTop();\n }\n },\n\n /**\n * @private\n * Handle event firing for target and subtargets\n * @param {Event} e event from mouse\n * @param {String} eventType event to fire (up, down or move)\n * @return {Fabric.Object} target return the the target found, for internal reasons.\n */\n _simpleEventHandler: function(eventType, e) {\n var target = this.findTarget(e),\n targets = this.targets,\n options = {\n e: e,\n target: target,\n subTargets: targets,\n };\n this.fire(eventType, options);\n target && target.fire(eventType, options);\n if (!targets) {\n return target;\n }\n for (var i = 0; i < targets.length; i++) {\n targets[i].fire(eventType, options);\n }\n return target;\n },\n\n /**\n * @private\n * Handle event firing for target and subtargets\n * @param {Event} e event from mouse\n * @param {String} eventType event to fire (up, down or move)\n * @param {fabric.Object} targetObj receiving event\n * @param {Number} [button] button used in the event 1 = left, 2 = middle, 3 = right\n * @param {Boolean} isClick for left button only, indicates that the mouse up happened without move.\n */\n _handleEvent: function(e, eventType, button, isClick) {\n var target = this._target,\n targets = this.targets || [],\n options = {\n e: e,\n target: target,\n subTargets: targets,\n button: button || LEFT_CLICK,\n isClick: isClick || false,\n pointer: this._pointer,\n absolutePointer: this._absolutePointer,\n transform: this._currentTransform\n };\n if (eventType === 'up') {\n options.currentTarget = this.findTarget(e);\n options.currentSubTargets = this.targets;\n }\n this.fire('mouse:' + eventType, options);\n target && target.fire('mouse' + eventType, options);\n for (var i = 0; i < targets.length; i++) {\n targets[i].fire('mouse' + eventType, options);\n }\n },\n\n /**\n * @private\n * @param {Event} e send the mouse event that generate the finalize down, so it can be used in the event\n */\n _finalizeCurrentTransform: function(e) {\n\n var transform = this._currentTransform,\n target = transform.target,\n options = {\n e: e,\n target: target,\n transform: transform,\n action: transform.action,\n };\n\n if (target._scaling) {\n target._scaling = false;\n }\n\n target.setCoords();\n\n if (transform.actionPerformed || (this.stateful && target.hasStateChanged())) {\n this._fire('modified', options);\n }\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n _onMouseDownInDrawingMode: function(e) {\n this._isCurrentlyDrawing = true;\n if (this.getActiveObject()) {\n this.discardActiveObject(e).requestRenderAll();\n }\n var pointer = this.getPointer(e);\n this.freeDrawingBrush.onMouseDown(pointer, { e: e, pointer: pointer });\n this._handleEvent(e, 'down');\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mousemove\n */\n _onMouseMoveInDrawingMode: function(e) {\n if (this._isCurrentlyDrawing) {\n var pointer = this.getPointer(e);\n this.freeDrawingBrush.onMouseMove(pointer, { e: e, pointer: pointer });\n }\n this.setCursor(this.freeDrawingCursor);\n this._handleEvent(e, 'move');\n },\n\n /**\n * @private\n * @param {Event} e Event object fired on mouseup\n */\n _onMouseUpInDrawingMode: function(e) {\n var pointer = this.getPointer(e);\n this._isCurrentlyDrawing = this.freeDrawingBrush.onMouseUp({ e: e, pointer: pointer });\n this._handleEvent(e, 'up');\n },\n\n /**\n * Method that defines the actions when mouse is clicked on canvas.\n * The method inits the currentTransform parameters and renders all the\n * canvas so the current image can be placed on the top canvas and the rest\n * in on the container one.\n * @private\n * @param {Event} e Event object fired on mousedown\n */\n __onMouseDown: function (e) {\n this._cacheTransformEventData(e);\n this._handleEvent(e, 'down:before');\n var target = this._target;\n // if right click just fire events\n if (checkClick(e, RIGHT_CLICK)) {\n if (this.fireRightClick) {\n this._handleEvent(e, 'down', RIGHT_CLICK);\n }\n return;\n }\n\n if (checkClick(e, MIDDLE_CLICK)) {\n if (this.fireMiddleClick) {\n this._handleEvent(e, 'down', MIDDLE_CLICK);\n }\n return;\n }\n\n if (this.isDrawingMode) {\n this._onMouseDownInDrawingMode(e);\n return;\n }\n\n if (!this._isMainEvent(e)) {\n return;\n }\n\n // ignore if some object is being transformed at this moment\n if (this._currentTransform) {\n return;\n }\n\n var pointer = this._pointer;\n // save pointer for check in __onMouseUp event\n this._previousPointer = pointer;\n var shouldRender = this._shouldRender(target),\n shouldGroup = this._shouldGroup(e, target);\n if (this._shouldClearSelection(e, target)) {\n this.discardActiveObject(e);\n }\n else if (shouldGroup) {\n this._handleGrouping(e, target);\n target = this._activeObject;\n }\n\n if (this.selection && (!target ||\n (!target.selectable && !target.isEditing && target !== this._activeObject))) {\n this._groupSelector = {\n ex: this._absolutePointer.x,\n ey: this._absolutePointer.y,\n top: 0,\n left: 0\n };\n }\n\n if (target) {\n var alreadySelected = target === this._activeObject;\n if (target.selectable && target.activeOn === 'down') {\n this.setActiveObject(target, e);\n }\n var corner = target._findTargetCorner(\n this.getPointer(e, true),\n fabric.util.isTouchEvent(e)\n );\n target.__corner = corner;\n if (target === this._activeObject && (corner || !shouldGroup)) {\n this._setupCurrentTransform(e, target, alreadySelected);\n var control = target.controls[corner],\n pointer = this.getPointer(e),\n mouseDownHandler = control && control.getMouseDownHandler(e, target, control);\n if (mouseDownHandler) {\n mouseDownHandler(e, this._currentTransform, pointer.x, pointer.y);\n }\n }\n }\n this._handleEvent(e, 'down');\n // we must renderAll so that we update the visuals\n (shouldRender || shouldGroup) && this.requestRenderAll();\n },\n\n /**\n * reset cache form common information needed during event processing\n * @private\n */\n _resetTransformEventData: function() {\n this._target = null;\n this._pointer = null;\n this._absolutePointer = null;\n },\n\n /**\n * Cache common information needed during event processing\n * @private\n * @param {Event} e Event object fired on event\n */\n _cacheTransformEventData: function(e) {\n // reset in order to avoid stale caching\n this._resetTransformEventData();\n this._pointer = this.getPointer(e, true);\n this._absolutePointer = this.restorePointerVpt(this._pointer);\n this._target = this._currentTransform ? this._currentTransform.target : this.findTarget(e) || null;\n },\n\n /**\n * @private\n */\n _beforeTransform: function(e) {\n var t = this._currentTransform;\n this.stateful && t.target.saveState();\n this.fire('before:transform', {\n e: e,\n transform: t,\n });\n },\n\n /**\n * Method that defines the actions when mouse is hovering the canvas.\n * The currentTransform parameter will define whether the user is rotating/scaling/translating\n * an image or neither of them (only hovering). A group selection is also possible and would cancel\n * all any other type of action.\n * In case of an image transformation only the top canvas will be rendered.\n * @private\n * @param {Event} e Event object fired on mousemove\n */\n __onMouseMove: function (e) {\n this._handleEvent(e, 'move:before');\n this._cacheTransformEventData(e);\n var target, pointer;\n\n if (this.isDrawingMode) {\n this._onMouseMoveInDrawingMode(e);\n return;\n }\n\n if (!this._isMainEvent(e)) {\n return;\n }\n\n var groupSelector = this._groupSelector;\n\n // We initially clicked in an empty area, so we draw a box for multiple selection\n if (groupSelector) {\n pointer = this._absolutePointer;\n\n groupSelector.left = pointer.x - groupSelector.ex;\n groupSelector.top = pointer.y - groupSelector.ey;\n\n this.renderTop();\n }\n else if (!this._currentTransform) {\n target = this.findTarget(e) || null;\n this._setCursorFromEvent(e, target);\n this._fireOverOutEvents(target, e);\n }\n else {\n this._transformObject(e);\n }\n this._handleEvent(e, 'move');\n this._resetTransformEventData();\n },\n\n /**\n * Manage the mouseout, mouseover events for the fabric object on the canvas\n * @param {Fabric.Object} target the target where the target from the mousemove event\n * @param {Event} e Event object fired on mousemove\n * @private\n */\n _fireOverOutEvents: function(target, e) {\n var _hoveredTarget = this._hoveredTarget,\n _hoveredTargets = this._hoveredTargets, targets = this.targets,\n length = Math.max(_hoveredTargets.length, targets.length);\n\n this.fireSyntheticInOutEvents(target, e, {\n oldTarget: _hoveredTarget,\n evtOut: 'mouseout',\n canvasEvtOut: 'mouse:out',\n evtIn: 'mouseover',\n canvasEvtIn: 'mouse:over',\n });\n for (var i = 0; i < length; i++){\n this.fireSyntheticInOutEvents(targets[i], e, {\n oldTarget: _hoveredTargets[i],\n evtOut: 'mouseout',\n evtIn: 'mouseover',\n });\n }\n this._hoveredTarget = target;\n this._hoveredTargets = this.targets.concat();\n },\n\n /**\n * Manage the dragEnter, dragLeave events for the fabric objects on the canvas\n * @param {Fabric.Object} target the target where the target from the onDrag event\n * @param {Event} e Event object fired on ondrag\n * @private\n */\n _fireEnterLeaveEvents: function(target, e) {\n var _draggedoverTarget = this._draggedoverTarget,\n _hoveredTargets = this._hoveredTargets, targets = this.targets,\n length = Math.max(_hoveredTargets.length, targets.length);\n\n this.fireSyntheticInOutEvents(target, e, {\n oldTarget: _draggedoverTarget,\n evtOut: 'dragleave',\n evtIn: 'dragenter',\n });\n for (var i = 0; i < length; i++) {\n this.fireSyntheticInOutEvents(targets[i], e, {\n oldTarget: _hoveredTargets[i],\n evtOut: 'dragleave',\n evtIn: 'dragenter',\n });\n }\n this._draggedoverTarget = target;\n },\n\n /**\n * Manage the synthetic in/out events for the fabric objects on the canvas\n * @param {Fabric.Object} target the target where the target from the supported events\n * @param {Event} e Event object fired\n * @param {Object} config configuration for the function to work\n * @param {String} config.targetName property on the canvas where the old target is stored\n * @param {String} [config.canvasEvtOut] name of the event to fire at canvas level for out\n * @param {String} config.evtOut name of the event to fire for out\n * @param {String} [config.canvasEvtIn] name of the event to fire at canvas level for in\n * @param {String} config.evtIn name of the event to fire for in\n * @private\n */\n fireSyntheticInOutEvents: function(target, e, config) {\n var inOpt, outOpt, oldTarget = config.oldTarget, outFires, inFires,\n targetChanged = oldTarget !== target, canvasEvtIn = config.canvasEvtIn, canvasEvtOut = config.canvasEvtOut;\n if (targetChanged) {\n inOpt = { e: e, target: target, previousTarget: oldTarget };\n outOpt = { e: e, target: oldTarget, nextTarget: target };\n }\n inFires = target && targetChanged;\n outFires = oldTarget && targetChanged;\n if (outFires) {\n canvasEvtOut && this.fire(canvasEvtOut, outOpt);\n oldTarget.fire(config.evtOut, outOpt);\n }\n if (inFires) {\n canvasEvtIn && this.fire(canvasEvtIn, inOpt);\n target.fire(config.evtIn, inOpt);\n }\n },\n\n /**\n * Method that defines actions when an Event Mouse Wheel\n * @param {Event} e Event object fired on mouseup\n */\n __onMouseWheel: function(e) {\n this._cacheTransformEventData(e);\n this._handleEvent(e, 'wheel');\n this._resetTransformEventData();\n },\n\n /**\n * @private\n * @param {Event} e Event fired on mousemove\n */\n _transformObject: function(e) {\n var pointer = this.getPointer(e),\n transform = this._currentTransform;\n\n transform.reset = false;\n transform.shiftKey = e.shiftKey;\n transform.altKey = e[this.centeredKey];\n\n this._performTransformAction(e, transform, pointer);\n transform.actionPerformed && this.requestRenderAll();\n },\n\n /**\n * @private\n */\n _performTransformAction: function(e, transform, pointer) {\n var x = pointer.x,\n y = pointer.y,\n action = transform.action,\n actionPerformed = false,\n actionHandler = transform.actionHandler;\n // this object could be created from the function in the control handlers\n\n\n if (actionHandler) {\n actionPerformed = actionHandler(e, transform, x, y);\n }\n if (action === 'drag' && actionPerformed) {\n transform.target.isMoving = true;\n this.setCursor(transform.target.moveCursor || this.moveCursor);\n }\n transform.actionPerformed = transform.actionPerformed || actionPerformed;\n },\n\n /**\n * @private\n */\n _fire: fabric.controlsUtils.fireEvent,\n\n /**\n * Sets the cursor depending on where the canvas is being hovered.\n * Note: very buggy in Opera\n * @param {Event} e Event object\n * @param {Object} target Object that the mouse is hovering, if so.\n */\n _setCursorFromEvent: function (e, target) {\n if (!target) {\n this.setCursor(this.defaultCursor);\n return false;\n }\n var hoverCursor = target.hoverCursor || this.hoverCursor,\n activeSelection = this._activeObject && this._activeObject.type === 'activeSelection' ?\n this._activeObject : null,\n // only show proper corner when group selection is not active\n corner = (!activeSelection || !activeSelection.contains(target))\n // here we call findTargetCorner always with undefined for the touch parameter.\n // we assume that if you are using a cursor you do not need to interact with\n // the bigger touch area.\n && target._findTargetCorner(this.getPointer(e, true));\n\n if (!corner) {\n if (target.subTargetCheck){\n // hoverCursor should come from top-most subTarget,\n // so we walk the array backwards\n this.targets.concat().reverse().map(function(_target){\n hoverCursor = _target.hoverCursor || hoverCursor;\n });\n }\n this.setCursor(hoverCursor);\n }\n else {\n this.setCursor(this.getCornerCursor(corner, target, e));\n }\n },\n\n /**\n * @private\n */\n getCornerCursor: function(corner, target, e) {\n var control = target.controls[corner];\n return control.cursorStyleHandler(e, control, target);\n }\n });\n})();\n\n\n(function() {\n\n var min = Math.min,\n max = Math.max;\n\n fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n\n /**\n * @private\n * @param {Event} e Event object\n * @param {fabric.Object} target\n * @return {Boolean}\n */\n _shouldGroup: function(e, target) {\n var activeObject = this._activeObject;\n return activeObject && this._isSelectionKeyPressed(e) && target && target.selectable && this.selection &&\n (activeObject !== target || activeObject.type === 'activeSelection') && !target.onSelect({ e: e });\n },\n\n /**\n * @private\n * @param {Event} e Event object\n * @param {fabric.Object} target\n */\n _handleGrouping: function (e, target) {\n var activeObject = this._activeObject;\n // avoid multi select when shift click on a corner\n if (activeObject.__corner) {\n return;\n }\n if (target === activeObject) {\n // if it's a group, find target again, using activeGroup objects\n target = this.findTarget(e, true);\n // if even object is not found or we are on activeObjectCorner, bail out\n if (!target || !target.selectable) {\n return;\n }\n }\n if (activeObject && activeObject.type === 'activeSelection') {\n this._updateActiveSelection(target, e);\n }\n else {\n this._createActiveSelection(target, e);\n }\n },\n\n /**\n * @private\n */\n _updateActiveSelection: function(target, e) {\n var activeSelection = this._activeObject,\n currentActiveObjects = activeSelection._objects.slice(0);\n if (activeSelection.contains(target)) {\n activeSelection.removeWithUpdate(target);\n this._hoveredTarget = target;\n this._hoveredTargets = this.targets.concat();\n if (activeSelection.size() === 1) {\n // activate last remaining object\n this._setActiveObject(activeSelection.item(0), e);\n }\n }\n else {\n activeSelection.addWithUpdate(target);\n this._hoveredTarget = activeSelection;\n this._hoveredTargets = this.targets.concat();\n }\n this._fireSelectionEvents(currentActiveObjects, e);\n },\n\n /**\n * @private\n */\n _createActiveSelection: function(target, e) {\n var currentActives = this.getActiveObjects(), group = this._createGroup(target);\n this._hoveredTarget = group;\n // ISSUE 4115: should we consider subTargets here?\n // this._hoveredTargets = [];\n // this._hoveredTargets = this.targets.concat();\n this._setActiveObject(group, e);\n this._fireSelectionEvents(currentActives, e);\n },\n\n /**\n * @private\n * @param {Object} target\n */\n _createGroup: function(target) {\n var objects = this._objects,\n isActiveLower = objects.indexOf(this._activeObject) < objects.indexOf(target),\n groupObjects = isActiveLower\n ? [this._activeObject, target]\n : [target, this._activeObject];\n this._activeObject.isEditing && this._activeObject.exitEditing();\n return new fabric.ActiveSelection(groupObjects, {\n canvas: this\n });\n },\n\n /**\n * @private\n * @param {Event} e mouse event\n */\n _groupSelectedObjects: function (e) {\n\n var group = this._collectObjects(e),\n aGroup;\n\n // do not create group for 1 element only\n if (group.length === 1) {\n this.setActiveObject(group[0], e);\n }\n else if (group.length > 1) {\n aGroup = new fabric.ActiveSelection(group.reverse(), {\n canvas: this\n });\n this.setActiveObject(aGroup, e);\n }\n },\n\n /**\n * @private\n */\n _collectObjects: function(e) {\n var group = [],\n currentObject,\n x1 = this._groupSelector.ex,\n y1 = this._groupSelector.ey,\n x2 = x1 + this._groupSelector.left,\n y2 = y1 + this._groupSelector.top,\n selectionX1Y1 = new fabric.Point(min(x1, x2), min(y1, y2)),\n selectionX2Y2 = new fabric.Point(max(x1, x2), max(y1, y2)),\n allowIntersect = !this.selectionFullyContained,\n isClick = x1 === x2 && y1 === y2;\n // we iterate reverse order to collect top first in case of click.\n for (var i = this._objects.length; i--; ) {\n currentObject = this._objects[i];\n\n if (!currentObject || !currentObject.selectable || !currentObject.visible) {\n continue;\n }\n\n if ((allowIntersect && currentObject.intersectsWithRect(selectionX1Y1, selectionX2Y2, true)) ||\n currentObject.isContainedWithinRect(selectionX1Y1, selectionX2Y2, true) ||\n (allowIntersect && currentObject.containsPoint(selectionX1Y1, null, true)) ||\n (allowIntersect && currentObject.containsPoint(selectionX2Y2, null, true))\n ) {\n group.push(currentObject);\n // only add one object if it's a click\n if (isClick) {\n break;\n }\n }\n }\n\n if (group.length > 1) {\n group = group.filter(function(object) {\n return !object.onSelect({ e: e });\n });\n }\n\n return group;\n },\n\n /**\n * @private\n */\n _maybeGroupObjects: function(e) {\n if (this.selection && this._groupSelector) {\n this._groupSelectedObjects(e);\n }\n this.setCursor(this.defaultCursor);\n // clear selection and current transformation\n this._groupSelector = null;\n }\n });\n\n})();\n\n\n(function () {\n fabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n /**\n * Exports canvas element to a dataurl image. Note that when multiplier is used, cropping is scaled appropriately\n * @param {Object} [options] Options object\n * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n * @param {Number} [options.multiplier=1] Multiplier to scale by, to have consistent\n * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 2.0.0\n * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n * @see {@link http://jsfiddle.net/fabricjs/NfZVb/|jsFiddle demo}\n * @example Generate jpeg dataURL with lower quality\n * var dataURL = canvas.toDataURL({\n * format: 'jpeg',\n * quality: 0.8\n * });\n * @example Generate cropped png dataURL (clipping of canvas)\n * var dataURL = canvas.toDataURL({\n * format: 'png',\n * left: 100,\n * top: 100,\n * width: 200,\n * height: 200\n * });\n * @example Generate double scaled png dataURL\n * var dataURL = canvas.toDataURL({\n * format: 'png',\n * multiplier: 2\n * });\n */\n toDataURL: function (options) {\n options || (options = { });\n\n var format = options.format || 'png',\n quality = options.quality || 1,\n multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? this.getRetinaScaling() : 1),\n canvasEl = this.toCanvasElement(multiplier, options);\n return fabric.util.toDataURL(canvasEl, format, quality);\n },\n\n /**\n * Create a new HTMLCanvas element painted with the current canvas content.\n * No need to resize the actual one or repaint it.\n * Will transfer object ownership to a new canvas, paint it, and set everything back.\n * This is an intermediary step used to get to a dataUrl but also it is useful to\n * create quick image copies of a canvas without passing for the dataUrl string\n * @param {Number} [multiplier] a zoom factor.\n * @param {Object} [cropping] Cropping informations\n * @param {Number} [cropping.left] Cropping left offset.\n * @param {Number} [cropping.top] Cropping top offset.\n * @param {Number} [cropping.width] Cropping width.\n * @param {Number} [cropping.height] Cropping height.\n */\n toCanvasElement: function(multiplier, cropping) {\n multiplier = multiplier || 1;\n cropping = cropping || { };\n var scaledWidth = (cropping.width || this.width) * multiplier,\n scaledHeight = (cropping.height || this.height) * multiplier,\n zoom = this.getZoom(),\n originalWidth = this.width,\n originalHeight = this.height,\n newZoom = zoom * multiplier,\n vp = this.viewportTransform,\n translateX = (vp[4] - (cropping.left || 0)) * multiplier,\n translateY = (vp[5] - (cropping.top || 0)) * multiplier,\n originalInteractive = this.interactive,\n newVp = [newZoom, 0, 0, newZoom, translateX, translateY],\n originalRetina = this.enableRetinaScaling,\n canvasEl = fabric.util.createCanvasElement(),\n originalContextTop = this.contextTop;\n canvasEl.width = scaledWidth;\n canvasEl.height = scaledHeight;\n this.contextTop = null;\n this.enableRetinaScaling = false;\n this.interactive = false;\n this.viewportTransform = newVp;\n this.width = scaledWidth;\n this.height = scaledHeight;\n this.calcViewportBoundaries();\n this.renderCanvas(canvasEl.getContext('2d'), this._objects);\n this.viewportTransform = vp;\n this.width = originalWidth;\n this.height = originalHeight;\n this.calcViewportBoundaries();\n this.interactive = originalInteractive;\n this.enableRetinaScaling = originalRetina;\n this.contextTop = originalContextTop;\n return canvasEl;\n },\n });\n\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n /**\n * Populates canvas with data from the specified JSON.\n * JSON format must conform to the one of {@link fabric.Canvas#toJSON}\n * @param {String|Object} json JSON string or object\n * @param {Function} callback Callback, invoked when json is parsed\n * and corresponding objects (e.g: {@link fabric.Image})\n * are initialized\n * @param {Function} [reviver] Method for further parsing of JSON elements, called after each fabric object created.\n * @return {fabric.Canvas} instance\n * @chainable\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#deserialization}\n * @see {@link http://jsfiddle.net/fabricjs/fmgXt/|jsFiddle demo}\n * @example loadFromJSON\n * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas));\n * @example loadFromJSON with reviver\n * canvas.loadFromJSON(json, canvas.renderAll.bind(canvas), function(o, object) {\n * // `o` = json object\n * // `object` = fabric.Object instance\n * // ... do some stuff ...\n * });\n */\n loadFromJSON: function (json, callback, reviver) {\n if (!json) {\n return;\n }\n\n // serialize if it wasn't already\n var serialized = (typeof json === 'string')\n ? JSON.parse(json)\n : fabric.util.object.clone(json);\n\n var _this = this,\n clipPath = serialized.clipPath,\n renderOnAddRemove = this.renderOnAddRemove;\n\n this.renderOnAddRemove = false;\n\n delete serialized.clipPath;\n\n this._enlivenObjects(serialized.objects, function (enlivenedObjects) {\n _this.clear();\n _this._setBgOverlay(serialized, function () {\n if (clipPath) {\n _this._enlivenObjects([clipPath], function (enlivenedCanvasClip) {\n _this.clipPath = enlivenedCanvasClip[0];\n _this.__setupCanvas.call(_this, serialized, enlivenedObjects, renderOnAddRemove, callback);\n });\n }\n else {\n _this.__setupCanvas.call(_this, serialized, enlivenedObjects, renderOnAddRemove, callback);\n }\n });\n }, reviver);\n return this;\n },\n\n /**\n * @private\n * @param {Object} serialized Object with background and overlay information\n * @param {Array} restored canvas objects\n * @param {Function} cached renderOnAddRemove callback\n * @param {Function} callback Invoked after all background and overlay images/patterns loaded\n */\n __setupCanvas: function(serialized, enlivenedObjects, renderOnAddRemove, callback) {\n var _this = this;\n enlivenedObjects.forEach(function(obj, index) {\n // we splice the array just in case some custom classes restored from JSON\n // will add more object to canvas at canvas init.\n _this.insertAt(obj, index);\n });\n this.renderOnAddRemove = renderOnAddRemove;\n // remove parts i cannot set as options\n delete serialized.objects;\n delete serialized.backgroundImage;\n delete serialized.overlayImage;\n delete serialized.background;\n delete serialized.overlay;\n // this._initOptions does too many things to just\n // call it. Normally loading an Object from JSON\n // create the Object instance. Here the Canvas is\n // already an instance and we are just loading things over it\n this._setOptions(serialized);\n this.renderAll();\n callback && callback();\n },\n\n /**\n * @private\n * @param {Object} serialized Object with background and overlay information\n * @param {Function} callback Invoked after all background and overlay images/patterns loaded\n */\n _setBgOverlay: function(serialized, callback) {\n var loaded = {\n backgroundColor: false,\n overlayColor: false,\n backgroundImage: false,\n overlayImage: false\n };\n\n if (!serialized.backgroundImage && !serialized.overlayImage && !serialized.background && !serialized.overlay) {\n callback && callback();\n return;\n }\n\n var cbIfLoaded = function () {\n if (loaded.backgroundImage && loaded.overlayImage && loaded.backgroundColor && loaded.overlayColor) {\n callback && callback();\n }\n };\n\n this.__setBgOverlay('backgroundImage', serialized.backgroundImage, loaded, cbIfLoaded);\n this.__setBgOverlay('overlayImage', serialized.overlayImage, loaded, cbIfLoaded);\n this.__setBgOverlay('backgroundColor', serialized.background, loaded, cbIfLoaded);\n this.__setBgOverlay('overlayColor', serialized.overlay, loaded, cbIfLoaded);\n },\n\n /**\n * @private\n * @param {String} property Property to set (backgroundImage, overlayImage, backgroundColor, overlayColor)\n * @param {(Object|String)} value Value to set\n * @param {Object} loaded Set loaded property to true if property is set\n * @param {Object} callback Callback function to invoke after property is set\n */\n __setBgOverlay: function(property, value, loaded, callback) {\n var _this = this;\n\n if (!value) {\n loaded[property] = true;\n callback && callback();\n return;\n }\n\n if (property === 'backgroundImage' || property === 'overlayImage') {\n fabric.util.enlivenObjects([value], function(enlivedObject){\n _this[property] = enlivedObject[0];\n loaded[property] = true;\n callback && callback();\n });\n }\n else {\n this['set' + fabric.util.string.capitalize(property, true)](value, function() {\n loaded[property] = true;\n callback && callback();\n });\n }\n },\n\n /**\n * @private\n * @param {Array} objects\n * @param {Function} callback\n * @param {Function} [reviver]\n */\n _enlivenObjects: function (objects, callback, reviver) {\n if (!objects || objects.length === 0) {\n callback && callback([]);\n return;\n }\n\n fabric.util.enlivenObjects(objects, function(enlivenedObjects) {\n callback && callback(enlivenedObjects);\n }, null, reviver);\n },\n\n /**\n * @private\n * @param {String} format\n * @param {Function} callback\n */\n _toDataURL: function (format, callback) {\n this.clone(function (clone) {\n callback(clone.toDataURL(format));\n });\n },\n\n /**\n * @private\n * @param {String} format\n * @param {Number} multiplier\n * @param {Function} callback\n */\n _toDataURLWithMultiplier: function (format, multiplier, callback) {\n this.clone(function (clone) {\n callback(clone.toDataURLWithMultiplier(format, multiplier));\n });\n },\n\n /**\n * Clones canvas instance\n * @param {Object} [callback] Receives cloned instance as a first argument\n * @param {Array} [properties] Array of properties to include in the cloned canvas and children\n */\n clone: function (callback, properties) {\n var data = JSON.stringify(this.toJSON(properties));\n this.cloneWithoutData(function(clone) {\n clone.loadFromJSON(data, function() {\n callback && callback(clone);\n });\n });\n },\n\n /**\n * Clones canvas instance without cloning existing data.\n * This essentially copies canvas dimensions, clipping properties, etc.\n * but leaves data empty (so that you can populate it with your own)\n * @param {Object} [callback] Receives cloned instance as a first argument\n */\n cloneWithoutData: function(callback) {\n var el = fabric.util.createCanvasElement();\n\n el.width = this.width;\n el.height = this.height;\n\n var clone = new fabric.Canvas(el);\n if (this.backgroundImage) {\n clone.setBackgroundImage(this.backgroundImage.src, function() {\n clone.renderAll();\n callback && callback(clone);\n });\n clone.backgroundImageOpacity = this.backgroundImageOpacity;\n clone.backgroundImageStretch = this.backgroundImageStretch;\n }\n else {\n callback && callback(clone);\n }\n }\n});\n\n\n/**\n * Adds support for multi-touch gestures using the Event.js library.\n * Fires the following custom events:\n * - touch:gesture\n * - touch:drag\n * - touch:orientation\n * - touch:shake\n * - touch:longpress\n */\n(function() {\n\n var degreesToRadians = fabric.util.degreesToRadians,\n radiansToDegrees = fabric.util.radiansToDegrees;\n\n fabric.util.object.extend(fabric.Canvas.prototype, /** @lends fabric.Canvas.prototype */ {\n /**\n * Method that defines actions when an Event.js gesture is detected on an object. Currently only supports\n * 2 finger gestures.\n * @param {Event} e Event object by Event.js\n * @param {Event} self Event proxy object by Event.js\n */\n __onTransformGesture: function(e, self) {\n\n if (this.isDrawingMode || !e.touches || e.touches.length !== 2 || 'gesture' !== self.gesture) {\n return;\n }\n\n var target = this.findTarget(e);\n if ('undefined' !== typeof target) {\n this.__gesturesParams = {\n e: e,\n self: self,\n target: target\n };\n\n this.__gesturesRenderer();\n }\n\n this.fire('touch:gesture', {\n target: target, e: e, self: self\n });\n },\n __gesturesParams: null,\n __gesturesRenderer: function() {\n\n if (this.__gesturesParams === null || this._currentTransform === null) {\n return;\n }\n\n var self = this.__gesturesParams.self,\n t = this._currentTransform,\n e = this.__gesturesParams.e;\n\n t.action = 'scale';\n t.originX = t.originY = 'center';\n\n this._scaleObjectBy(self.scale, e);\n\n if (self.rotation !== 0) {\n t.action = 'rotate';\n this._rotateObjectByAngle(self.rotation, e);\n }\n\n this.requestRenderAll();\n\n t.action = 'drag';\n },\n\n /**\n * Method that defines actions when an Event.js drag is detected.\n *\n * @param {Event} e Event object by Event.js\n * @param {Event} self Event proxy object by Event.js\n */\n __onDrag: function(e, self) {\n this.fire('touch:drag', {\n e: e, self: self\n });\n },\n\n /**\n * Method that defines actions when an Event.js orientation event is detected.\n *\n * @param {Event} e Event object by Event.js\n * @param {Event} self Event proxy object by Event.js\n */\n __onOrientationChange: function(e, self) {\n this.fire('touch:orientation', {\n e: e, self: self\n });\n },\n\n /**\n * Method that defines actions when an Event.js shake event is detected.\n *\n * @param {Event} e Event object by Event.js\n * @param {Event} self Event proxy object by Event.js\n */\n __onShake: function(e, self) {\n this.fire('touch:shake', {\n e: e, self: self\n });\n },\n\n /**\n * Method that defines actions when an Event.js longpress event is detected.\n *\n * @param {Event} e Event object by Event.js\n * @param {Event} self Event proxy object by Event.js\n */\n __onLongPress: function(e, self) {\n this.fire('touch:longpress', {\n e: e, self: self\n });\n },\n\n /**\n * Scales an object by a factor\n * @param {Number} s The scale factor to apply to the current scale level\n * @param {Event} e Event object by Event.js\n */\n _scaleObjectBy: function(s, e) {\n var t = this._currentTransform,\n target = t.target;\n t.gestureScale = s;\n target._scaling = true;\n return fabric.controlsUtils.scalingEqually(e, t, 0, 0);\n },\n\n /**\n * Rotates object by an angle\n * @param {Number} curAngle The angle of rotation in degrees\n * @param {Event} e Event object by Event.js\n */\n _rotateObjectByAngle: function(curAngle, e) {\n var t = this._currentTransform;\n\n if (t.target.get('lockRotation')) {\n return;\n }\n t.target.rotate(radiansToDegrees(degreesToRadians(curAngle) + t.theta));\n this._fire('rotating', {\n target: t.target,\n e: e,\n transform: t,\n });\n }\n });\n})();\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend,\n clone = fabric.util.object.clone,\n toFixed = fabric.util.toFixed,\n capitalize = fabric.util.string.capitalize,\n degreesToRadians = fabric.util.degreesToRadians,\n objectCaching = !fabric.isLikelyNode,\n ALIASING_LIMIT = 2;\n\n if (fabric.Object) {\n return;\n }\n\n /**\n * Root object class from which all 2d shape classes inherit from\n * @class fabric.Object\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#objects}\n * @see {@link fabric.Object#initialize} for constructor definition\n *\n * @fires added\n * @fires removed\n *\n * @fires selected\n * @fires deselected\n * @fires modified\n * @fires modified\n * @fires moved\n * @fires scaled\n * @fires rotated\n * @fires skewed\n *\n * @fires rotating\n * @fires scaling\n * @fires moving\n * @fires skewing\n *\n * @fires mousedown\n * @fires mouseup\n * @fires mouseover\n * @fires mouseout\n * @fires mousewheel\n * @fires mousedblclick\n *\n * @fires dragover\n * @fires dragenter\n * @fires dragleave\n * @fires drop\n */\n fabric.Object = fabric.util.createClass(fabric.CommonMethods, /** @lends fabric.Object.prototype */ {\n\n /**\n * Type of an object (rect, circle, path, etc.).\n * Note that this property is meant to be read-only and not meant to be modified.\n * If you modify, certain parts of Fabric (such as JSON loading) won't work correctly.\n * @type String\n * @default\n */\n type: 'object',\n\n /**\n * Horizontal origin of transformation of an object (one of \"left\", \"right\", \"center\")\n * See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups\n * @type String\n * @default\n */\n originX: 'left',\n\n /**\n * Vertical origin of transformation of an object (one of \"top\", \"bottom\", \"center\")\n * See http://jsfiddle.net/1ow02gea/244/ on how originX/originY affect objects in groups\n * @type String\n * @default\n */\n originY: 'top',\n\n /**\n * Top position of an object. Note that by default it's relative to object top. You can change this by setting originY={top/center/bottom}\n * @type Number\n * @default\n */\n top: 0,\n\n /**\n * Left position of an object. Note that by default it's relative to object left. You can change this by setting originX={left/center/right}\n * @type Number\n * @default\n */\n left: 0,\n\n /**\n * Object width\n * @type Number\n * @default\n */\n width: 0,\n\n /**\n * Object height\n * @type Number\n * @default\n */\n height: 0,\n\n /**\n * Object scale factor (horizontal)\n * @type Number\n * @default\n */\n scaleX: 1,\n\n /**\n * Object scale factor (vertical)\n * @type Number\n * @default\n */\n scaleY: 1,\n\n /**\n * When true, an object is rendered as flipped horizontally\n * @type Boolean\n * @default\n */\n flipX: false,\n\n /**\n * When true, an object is rendered as flipped vertically\n * @type Boolean\n * @default\n */\n flipY: false,\n\n /**\n * Opacity of an object\n * @type Number\n * @default\n */\n opacity: 1,\n\n /**\n * Angle of rotation of an object (in degrees)\n * @type Number\n * @default\n */\n angle: 0,\n\n /**\n * Angle of skew on x axes of an object (in degrees)\n * @type Number\n * @default\n */\n skewX: 0,\n\n /**\n * Angle of skew on y axes of an object (in degrees)\n * @type Number\n * @default\n */\n skewY: 0,\n\n /**\n * Size of object's controlling corners (in pixels)\n * @type Number\n * @default\n */\n cornerSize: 13,\n\n /**\n * Size of object's controlling corners when touch interaction is detected\n * @type Number\n * @default\n */\n touchCornerSize: 24,\n\n /**\n * When true, object's controlling corners are rendered as transparent inside (i.e. stroke instead of fill)\n * @type Boolean\n * @default\n */\n transparentCorners: true,\n\n /**\n * Default cursor value used when hovering over this object on canvas\n * @type String\n * @default\n */\n hoverCursor: null,\n\n /**\n * Default cursor value used when moving this object on canvas\n * @type String\n * @default\n */\n moveCursor: null,\n\n /**\n * Padding between object and its controlling borders (in pixels)\n * @type Number\n * @default\n */\n padding: 0,\n\n /**\n * Color of controlling borders of an object (when it's active)\n * @type String\n * @default\n */\n borderColor: 'rgb(178,204,255)',\n\n /**\n * Array specifying dash pattern of an object's borders (hasBorder must be true)\n * @since 1.6.2\n * @type Array\n */\n borderDashArray: null,\n\n /**\n * Color of controlling corners of an object (when it's active)\n * @type String\n * @default\n */\n cornerColor: 'rgb(178,204,255)',\n\n /**\n * Color of controlling corners of an object (when it's active and transparentCorners false)\n * @since 1.6.2\n * @type String\n * @default\n */\n cornerStrokeColor: null,\n\n /**\n * Specify style of control, 'rect' or 'circle'\n * @since 1.6.2\n * @type String\n */\n cornerStyle: 'rect',\n\n /**\n * Array specifying dash pattern of an object's control (hasBorder must be true)\n * @since 1.6.2\n * @type Array\n */\n cornerDashArray: null,\n\n /**\n * When true, this object will use center point as the origin of transformation\n * when being scaled via the controls.\n * Backwards incompatibility note: This property replaces \"centerTransform\" (Boolean).\n * @since 1.3.4\n * @type Boolean\n * @default\n */\n centeredScaling: false,\n\n /**\n * When true, this object will use center point as the origin of transformation\n * when being rotated via the controls.\n * Backwards incompatibility note: This property replaces \"centerTransform\" (Boolean).\n * @since 1.3.4\n * @type Boolean\n * @default\n */\n centeredRotation: true,\n\n /**\n * Color of object's fill\n * takes css colors https://www.w3.org/TR/css-color-3/\n * @type String\n * @default\n */\n fill: 'rgb(0,0,0)',\n\n /**\n * Fill rule used to fill an object\n * accepted values are nonzero, evenodd\n * Backwards incompatibility note: This property was used for setting globalCompositeOperation until v1.4.12 (use `fabric.Object#globalCompositeOperation` instead)\n * @type String\n * @default\n */\n fillRule: 'nonzero',\n\n /**\n * Composite rule used for canvas globalCompositeOperation\n * @type String\n * @default\n */\n globalCompositeOperation: 'source-over',\n\n /**\n * Background color of an object.\n * takes css colors https://www.w3.org/TR/css-color-3/\n * @type String\n * @default\n */\n backgroundColor: '',\n\n /**\n * Selection Background color of an object. colored layer behind the object when it is active.\n * does not mix good with globalCompositeOperation methods.\n * @type String\n * @default\n */\n selectionBackgroundColor: '',\n\n /**\n * When defined, an object is rendered via stroke and this property specifies its color\n * takes css colors https://www.w3.org/TR/css-color-3/\n * @type String\n * @default\n */\n stroke: null,\n\n /**\n * Width of a stroke used to render this object\n * @type Number\n * @default\n */\n strokeWidth: 1,\n\n /**\n * Array specifying dash pattern of an object's stroke (stroke must be defined)\n * @type Array\n */\n strokeDashArray: null,\n\n /**\n * Line offset of an object's stroke\n * @type Number\n * @default\n */\n strokeDashOffset: 0,\n\n /**\n * Line endings style of an object's stroke (one of \"butt\", \"round\", \"square\")\n * @type String\n * @default\n */\n strokeLineCap: 'butt',\n\n /**\n * Corner style of an object's stroke (one of \"bevel\", \"round\", \"miter\")\n * @type String\n * @default\n */\n strokeLineJoin: 'miter',\n\n /**\n * Maximum miter length (used for strokeLineJoin = \"miter\") of an object's stroke\n * @type Number\n * @default\n */\n strokeMiterLimit: 4,\n\n /**\n * Shadow object representing shadow of this shape\n * @type fabric.Shadow\n * @default\n */\n shadow: null,\n\n /**\n * Opacity of object's controlling borders when object is active and moving\n * @type Number\n * @default\n */\n borderOpacityWhenMoving: 0.4,\n\n /**\n * Scale factor of object's controlling borders\n * bigger number will make a thicker border\n * border is 1, so this is basically a border thickness\n * since there is no way to change the border itself.\n * @type Number\n * @default\n */\n borderScaleFactor: 1,\n\n /**\n * Minimum allowed scale value of an object\n * @type Number\n * @default\n */\n minScaleLimit: 0,\n\n /**\n * When set to `false`, an object can not be selected for modification (using either point-click-based or group-based selection).\n * But events still fire on it.\n * @type Boolean\n * @default\n */\n selectable: true,\n\n /**\n * When set to `false`, an object can not be a target of events. All events propagate through it. Introduced in v1.3.4\n * @type Boolean\n * @default\n */\n evented: true,\n\n /**\n * When set to `false`, an object is not rendered on canvas\n * @type Boolean\n * @default\n */\n visible: true,\n\n /**\n * When set to `false`, object's controls are not displayed and can not be used to manipulate object\n * @type Boolean\n * @default\n */\n hasControls: true,\n\n /**\n * When set to `false`, object's controlling borders are not rendered\n * @type Boolean\n * @default\n */\n hasBorders: true,\n\n /**\n * When set to `true`, objects are \"found\" on canvas on per-pixel basis rather than according to bounding box\n * @type Boolean\n * @default\n */\n perPixelTargetFind: false,\n\n /**\n * When `false`, default object's values are not included in its serialization\n * @type Boolean\n * @default\n */\n includeDefaultValues: true,\n\n /**\n * When `true`, object horizontal movement is locked\n * @type Boolean\n * @default\n */\n lockMovementX: false,\n\n /**\n * When `true`, object vertical movement is locked\n * @type Boolean\n * @default\n */\n lockMovementY: false,\n\n /**\n * When `true`, object rotation is locked\n * @type Boolean\n * @default\n */\n lockRotation: false,\n\n /**\n * When `true`, object horizontal scaling is locked\n * @type Boolean\n * @default\n */\n lockScalingX: false,\n\n /**\n * When `true`, object vertical scaling is locked\n * @type Boolean\n * @default\n */\n lockScalingY: false,\n\n /**\n * When `true`, object horizontal skewing is locked\n * @type Boolean\n * @default\n */\n lockSkewingX: false,\n\n /**\n * When `true`, object vertical skewing is locked\n * @type Boolean\n * @default\n */\n lockSkewingY: false,\n\n /**\n * When `true`, object cannot be flipped by scaling into negative values\n * @type Boolean\n * @default\n */\n lockScalingFlip: false,\n\n /**\n * When `true`, object is not exported in OBJECT/JSON\n * @since 1.6.3\n * @type Boolean\n * @default\n */\n excludeFromExport: false,\n\n /**\n * When `true`, object is cached on an additional canvas.\n * When `false`, object is not cached unless necessary ( clipPath )\n * default to true\n * @since 1.7.0\n * @type Boolean\n * @default true\n */\n objectCaching: objectCaching,\n\n /**\n * When `true`, object properties are checked for cache invalidation. In some particular\n * situation you may want this to be disabled ( spray brush, very big, groups)\n * or if your application does not allow you to modify properties for groups child you want\n * to disable it for groups.\n * default to false\n * since 1.7.0\n * @type Boolean\n * @default false\n */\n statefullCache: false,\n\n /**\n * When `true`, cache does not get updated during scaling. The picture will get blocky if scaled\n * too much and will be redrawn with correct details at the end of scaling.\n * this setting is performance and application dependant.\n * default to true\n * since 1.7.0\n * @type Boolean\n * @default true\n */\n noScaleCache: true,\n\n /**\n * When `false`, the stoke width will scale with the object.\n * When `true`, the stroke will always match the exact pixel size entered for stroke width.\n * this Property does not work on Text classes or drawing call that uses strokeText,fillText methods\n * default to false\n * @since 2.6.0\n * @type Boolean\n * @default false\n * @type Boolean\n * @default false\n */\n strokeUniform: false,\n\n /**\n * When set to `true`, object's cache will be rerendered next render call.\n * since 1.7.0\n * @type Boolean\n * @default true\n */\n dirty: true,\n\n /**\n * keeps the value of the last hovered corner during mouse move.\n * 0 is no corner, or 'mt', 'ml', 'mtr' etc..\n * It should be private, but there is no harm in using it as\n * a read-only property.\n * @type number|string|any\n * @default 0\n */\n __corner: 0,\n\n /**\n * Determines if the fill or the stroke is drawn first (one of \"fill\" or \"stroke\")\n * @type String\n * @default\n */\n paintFirst: 'fill',\n\n /**\n * When 'down', object is set to active on mousedown/touchstart\n * When 'up', object is set to active on mouseup/touchend\n * Experimental. Let's see if this breaks anything before supporting officially\n * @private\n * since 4.4.0\n * @type String\n * @default 'down'\n */\n activeOn: 'down',\n\n /**\n * List of properties to consider when checking if state\n * of an object is changed (fabric.Object#hasStateChanged)\n * as well as for history (undo/redo) purposes\n * @type Array\n */\n stateProperties: (\n 'top left width height scaleX scaleY flipX flipY originX originY transformMatrix ' +\n 'stroke strokeWidth strokeDashArray strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit ' +\n 'angle opacity fill globalCompositeOperation shadow visible backgroundColor ' +\n 'skewX skewY fillRule paintFirst clipPath strokeUniform'\n ).split(' '),\n\n /**\n * List of properties to consider when checking if cache needs refresh\n * Those properties are checked by statefullCache ON ( or lazy mode if we want ) or from single\n * calls to Object.set(key, value). If the key is in this list, the object is marked as dirty\n * and refreshed at the next render\n * @type Array\n */\n cacheProperties: (\n 'fill stroke strokeWidth strokeDashArray width height paintFirst strokeUniform' +\n ' strokeLineCap strokeDashOffset strokeLineJoin strokeMiterLimit backgroundColor clipPath'\n ).split(' '),\n\n /**\n * List of properties to consider for animating colors.\n * @type Array\n */\n colorProperties: (\n 'fill stroke backgroundColor'\n ).split(' '),\n\n /**\n * a fabricObject that, without stroke define a clipping area with their shape. filled in black\n * the clipPath object gets used when the object has rendered, and the context is placed in the center\n * of the object cacheCanvas.\n * If you want 0,0 of a clipPath to align with an object center, use clipPath.originX/Y to 'center'\n * @type fabric.Object\n */\n clipPath: undefined,\n\n /**\n * Meaningful ONLY when the object is used as clipPath.\n * if true, the clipPath will make the object clip to the outside of the clipPath\n * since 2.4.0\n * @type boolean\n * @default false\n */\n inverted: false,\n\n /**\n * Meaningful ONLY when the object is used as clipPath.\n * if true, the clipPath will have its top and left relative to canvas, and will\n * not be influenced by the object transform. This will make the clipPath relative\n * to the canvas, but clipping just a particular object.\n * WARNING this is beta, this feature may change or be renamed.\n * since 2.4.0\n * @type boolean\n * @default false\n */\n absolutePositioned: false,\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n */\n initialize: function(options) {\n if (options) {\n this.setOptions(options);\n }\n },\n\n /**\n * Create a the canvas used to keep the cached copy of the object\n * @private\n */\n _createCacheCanvas: function() {\n this._cacheProperties = {};\n this._cacheCanvas = fabric.util.createCanvasElement();\n this._cacheContext = this._cacheCanvas.getContext('2d');\n this._updateCacheCanvas();\n // if canvas gets created, is empty, so dirty.\n this.dirty = true;\n },\n\n /**\n * Limit the cache dimensions so that X * Y do not cross fabric.perfLimitSizeTotal\n * and each side do not cross fabric.cacheSideLimit\n * those numbers are configurable so that you can get as much detail as you want\n * making bargain with performances.\n * @param {Object} dims\n * @param {Object} dims.width width of canvas\n * @param {Object} dims.height height of canvas\n * @param {Object} dims.zoomX zoomX zoom value to unscale the canvas before drawing cache\n * @param {Object} dims.zoomY zoomY zoom value to unscale the canvas before drawing cache\n * @return {Object}.width width of canvas\n * @return {Object}.height height of canvas\n * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n */\n _limitCacheSize: function(dims) {\n var perfLimitSizeTotal = fabric.perfLimitSizeTotal,\n width = dims.width, height = dims.height,\n max = fabric.maxCacheSideLimit, min = fabric.minCacheSideLimit;\n if (width <= max && height <= max && width * height <= perfLimitSizeTotal) {\n if (width < min) {\n dims.width = min;\n }\n if (height < min) {\n dims.height = min;\n }\n return dims;\n }\n var ar = width / height, limitedDims = fabric.util.limitDimsByArea(ar, perfLimitSizeTotal),\n capValue = fabric.util.capValue,\n x = capValue(min, limitedDims.x, max),\n y = capValue(min, limitedDims.y, max);\n if (width > x) {\n dims.zoomX /= width / x;\n dims.width = x;\n dims.capped = true;\n }\n if (height > y) {\n dims.zoomY /= height / y;\n dims.height = y;\n dims.capped = true;\n }\n return dims;\n },\n\n /**\n * Return the dimension and the zoom level needed to create a cache canvas\n * big enough to host the object to be cached.\n * @private\n * @return {Object}.x width of object to be cached\n * @return {Object}.y height of object to be cached\n * @return {Object}.width width of canvas\n * @return {Object}.height height of canvas\n * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n */\n _getCacheCanvasDimensions: function() {\n var objectScale = this.getTotalObjectScaling(),\n // caculate dimensions without skewing\n dim = this._getTransformedDimensions(0, 0),\n neededX = dim.x * objectScale.scaleX / this.scaleX,\n neededY = dim.y * objectScale.scaleY / this.scaleY;\n return {\n // for sure this ALIASING_LIMIT is slightly creating problem\n // in situation in which the cache canvas gets an upper limit\n // also objectScale contains already scaleX and scaleY\n width: neededX + ALIASING_LIMIT,\n height: neededY + ALIASING_LIMIT,\n zoomX: objectScale.scaleX,\n zoomY: objectScale.scaleY,\n x: neededX,\n y: neededY\n };\n },\n\n /**\n * Update width and height of the canvas for cache\n * returns true or false if canvas needed resize.\n * @private\n * @return {Boolean} true if the canvas has been resized\n */\n _updateCacheCanvas: function() {\n var targetCanvas = this.canvas;\n if (this.noScaleCache && targetCanvas && targetCanvas._currentTransform) {\n var target = targetCanvas._currentTransform.target,\n action = targetCanvas._currentTransform.action;\n if (this === target && action.slice && action.slice(0, 5) === 'scale') {\n return false;\n }\n }\n var canvas = this._cacheCanvas,\n dims = this._limitCacheSize(this._getCacheCanvasDimensions()),\n minCacheSize = fabric.minCacheSideLimit,\n width = dims.width, height = dims.height, drawingWidth, drawingHeight,\n zoomX = dims.zoomX, zoomY = dims.zoomY,\n dimensionsChanged = width !== this.cacheWidth || height !== this.cacheHeight,\n zoomChanged = this.zoomX !== zoomX || this.zoomY !== zoomY,\n shouldRedraw = dimensionsChanged || zoomChanged,\n additionalWidth = 0, additionalHeight = 0, shouldResizeCanvas = false;\n if (dimensionsChanged) {\n var canvasWidth = this._cacheCanvas.width,\n canvasHeight = this._cacheCanvas.height,\n sizeGrowing = width > canvasWidth || height > canvasHeight,\n sizeShrinking = (width < canvasWidth * 0.9 || height < canvasHeight * 0.9) &&\n canvasWidth > minCacheSize && canvasHeight > minCacheSize;\n shouldResizeCanvas = sizeGrowing || sizeShrinking;\n if (sizeGrowing && !dims.capped && (width > minCacheSize || height > minCacheSize)) {\n additionalWidth = width * 0.1;\n additionalHeight = height * 0.1;\n }\n }\n if (this instanceof fabric.Text && this.path) {\n shouldRedraw = true;\n shouldResizeCanvas = true;\n additionalWidth += this.getHeightOfLine(0) * this.zoomX;\n additionalHeight += this.getHeightOfLine(0) * this.zoomY;\n }\n if (shouldRedraw) {\n if (shouldResizeCanvas) {\n canvas.width = Math.ceil(width + additionalWidth);\n canvas.height = Math.ceil(height + additionalHeight);\n }\n else {\n this._cacheContext.setTransform(1, 0, 0, 1, 0, 0);\n this._cacheContext.clearRect(0, 0, canvas.width, canvas.height);\n }\n drawingWidth = dims.x / 2;\n drawingHeight = dims.y / 2;\n this.cacheTranslationX = Math.round(canvas.width / 2 - drawingWidth) + drawingWidth;\n this.cacheTranslationY = Math.round(canvas.height / 2 - drawingHeight) + drawingHeight;\n this.cacheWidth = width;\n this.cacheHeight = height;\n this._cacheContext.translate(this.cacheTranslationX, this.cacheTranslationY);\n this._cacheContext.scale(zoomX, zoomY);\n this.zoomX = zoomX;\n this.zoomY = zoomY;\n return true;\n }\n return false;\n },\n\n /**\n * Sets object's properties from options\n * @param {Object} [options] Options object\n */\n setOptions: function(options) {\n this._setOptions(options);\n this._initGradient(options.fill, 'fill');\n this._initGradient(options.stroke, 'stroke');\n this._initPattern(options.fill, 'fill');\n this._initPattern(options.stroke, 'stroke');\n },\n\n /**\n * Transforms context when rendering an object\n * @param {CanvasRenderingContext2D} ctx Context\n */\n transform: function(ctx) {\n var needFullTransform = (this.group && !this.group._transformDone) ||\n (this.group && this.canvas && ctx === this.canvas.contextTop);\n var m = this.calcTransformMatrix(!needFullTransform);\n ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n },\n\n /**\n * Returns an object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} Object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS,\n\n object = {\n type: this.type,\n version: fabric.version,\n originX: this.originX,\n originY: this.originY,\n left: toFixed(this.left, NUM_FRACTION_DIGITS),\n top: toFixed(this.top, NUM_FRACTION_DIGITS),\n width: toFixed(this.width, NUM_FRACTION_DIGITS),\n height: toFixed(this.height, NUM_FRACTION_DIGITS),\n fill: (this.fill && this.fill.toObject) ? this.fill.toObject() : this.fill,\n stroke: (this.stroke && this.stroke.toObject) ? this.stroke.toObject() : this.stroke,\n strokeWidth: toFixed(this.strokeWidth, NUM_FRACTION_DIGITS),\n strokeDashArray: this.strokeDashArray ? this.strokeDashArray.concat() : this.strokeDashArray,\n strokeLineCap: this.strokeLineCap,\n strokeDashOffset: this.strokeDashOffset,\n strokeLineJoin: this.strokeLineJoin,\n strokeUniform: this.strokeUniform,\n strokeMiterLimit: toFixed(this.strokeMiterLimit, NUM_FRACTION_DIGITS),\n scaleX: toFixed(this.scaleX, NUM_FRACTION_DIGITS),\n scaleY: toFixed(this.scaleY, NUM_FRACTION_DIGITS),\n angle: toFixed(this.angle, NUM_FRACTION_DIGITS),\n flipX: this.flipX,\n flipY: this.flipY,\n opacity: toFixed(this.opacity, NUM_FRACTION_DIGITS),\n shadow: (this.shadow && this.shadow.toObject) ? this.shadow.toObject() : this.shadow,\n visible: this.visible,\n backgroundColor: this.backgroundColor,\n fillRule: this.fillRule,\n paintFirst: this.paintFirst,\n globalCompositeOperation: this.globalCompositeOperation,\n skewX: toFixed(this.skewX, NUM_FRACTION_DIGITS),\n skewY: toFixed(this.skewY, NUM_FRACTION_DIGITS),\n };\n\n if (this.clipPath && !this.clipPath.excludeFromExport) {\n object.clipPath = this.clipPath.toObject(propertiesToInclude);\n object.clipPath.inverted = this.clipPath.inverted;\n object.clipPath.absolutePositioned = this.clipPath.absolutePositioned;\n }\n\n fabric.util.populateWithProperties(this, object, propertiesToInclude);\n if (!this.includeDefaultValues) {\n object = this._removeDefaultValues(object);\n }\n\n return object;\n },\n\n /**\n * Returns (dataless) object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} Object representation of an instance\n */\n toDatalessObject: function(propertiesToInclude) {\n // will be overwritten by subclasses\n return this.toObject(propertiesToInclude);\n },\n\n /**\n * @private\n * @param {Object} object\n */\n _removeDefaultValues: function(object) {\n var prototype = fabric.util.getKlass(object.type).prototype,\n stateProperties = prototype.stateProperties;\n stateProperties.forEach(function(prop) {\n if (prop === 'left' || prop === 'top') {\n return;\n }\n if (object[prop] === prototype[prop]) {\n delete object[prop];\n }\n // basically a check for [] === []\n if (Array.isArray(object[prop]) && Array.isArray(prototype[prop])\n && object[prop].length === 0 && prototype[prop].length === 0) {\n delete object[prop];\n }\n });\n\n return object;\n },\n\n /**\n * Returns a string representation of an instance\n * @return {String}\n */\n toString: function() {\n return '#';\n },\n\n /**\n * Return the object scale factor counting also the group scaling\n * @return {Object} object with scaleX and scaleY properties\n */\n getObjectScaling: function() {\n // if the object is a top level one, on the canvas, we go for simple aritmetic\n // otherwise the complex method with angles will return approximations and decimals\n // and will likely kill the cache when not needed\n // https://github.com/fabricjs/fabric.js/issues/7157\n if (!this.group) {\n return {\n scaleX: this.scaleX,\n scaleY: this.scaleY,\n };\n }\n // if we are inside a group total zoom calculation is complex, we defer to generic matrices\n var options = fabric.util.qrDecompose(this.calcTransformMatrix());\n return { scaleX: Math.abs(options.scaleX), scaleY: Math.abs(options.scaleY) };\n },\n\n /**\n * Return the object scale factor counting also the group scaling, zoom and retina\n * @return {Object} object with scaleX and scaleY properties\n */\n getTotalObjectScaling: function() {\n var scale = this.getObjectScaling(), scaleX = scale.scaleX, scaleY = scale.scaleY;\n if (this.canvas) {\n var zoom = this.canvas.getZoom();\n var retina = this.canvas.getRetinaScaling();\n scaleX *= zoom * retina;\n scaleY *= zoom * retina;\n }\n return { scaleX: scaleX, scaleY: scaleY };\n },\n\n /**\n * Return the object opacity counting also the group property\n * @return {Number}\n */\n getObjectOpacity: function() {\n var opacity = this.opacity;\n if (this.group) {\n opacity *= this.group.getObjectOpacity();\n }\n return opacity;\n },\n\n /**\n * @private\n * @param {String} key\n * @param {*} value\n * @return {fabric.Object} thisArg\n */\n _set: function(key, value) {\n var shouldConstrainValue = (key === 'scaleX' || key === 'scaleY'),\n isChanged = this[key] !== value, groupNeedsUpdate = false;\n\n if (shouldConstrainValue) {\n value = this._constrainScale(value);\n }\n if (key === 'scaleX' && value < 0) {\n this.flipX = !this.flipX;\n value *= -1;\n }\n else if (key === 'scaleY' && value < 0) {\n this.flipY = !this.flipY;\n value *= -1;\n }\n else if (key === 'shadow' && value && !(value instanceof fabric.Shadow)) {\n value = new fabric.Shadow(value);\n }\n else if (key === 'dirty' && this.group) {\n this.group.set('dirty', value);\n }\n\n this[key] = value;\n\n if (isChanged) {\n groupNeedsUpdate = this.group && this.group.isOnACache();\n if (this.cacheProperties.indexOf(key) > -1) {\n this.dirty = true;\n groupNeedsUpdate && this.group.set('dirty', true);\n }\n else if (groupNeedsUpdate && this.stateProperties.indexOf(key) > -1) {\n this.group.set('dirty', true);\n }\n }\n return this;\n },\n\n /**\n * This callback function is called by the parent group of an object every\n * time a non-delegated property changes on the group. It is passed the key\n * and value as parameters. Not adding in this function's signature to avoid\n * Travis build error about unused variables.\n */\n setOnGroup: function() {\n // implemented by sub-classes, as needed.\n },\n\n /**\n * Retrieves viewportTransform from Object's canvas if possible\n * @method getViewportTransform\n * @memberOf fabric.Object.prototype\n * @return {Array}\n */\n getViewportTransform: function() {\n if (this.canvas && this.canvas.viewportTransform) {\n return this.canvas.viewportTransform;\n }\n return fabric.iMatrix.concat();\n },\n\n /*\n * @private\n * return if the object would be visible in rendering\n * @memberOf fabric.Object.prototype\n * @return {Boolean}\n */\n isNotVisible: function() {\n return this.opacity === 0 ||\n (!this.width && !this.height && this.strokeWidth === 0) ||\n !this.visible;\n },\n\n /**\n * Renders an object on a specified context\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n render: function(ctx) {\n // do not render if width/height are zeros or object is not visible\n if (this.isNotVisible()) {\n return;\n }\n if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) {\n return;\n }\n ctx.save();\n this._setupCompositeOperation(ctx);\n this.drawSelectionBackground(ctx);\n this.transform(ctx);\n this._setOpacity(ctx);\n this._setShadow(ctx, this);\n if (this.shouldCache()) {\n this.renderCache();\n this.drawCacheOnCanvas(ctx);\n }\n else {\n this._removeCacheCanvas();\n this.dirty = false;\n this.drawObject(ctx);\n if (this.objectCaching && this.statefullCache) {\n this.saveState({ propertySet: 'cacheProperties' });\n }\n }\n ctx.restore();\n },\n\n renderCache: function(options) {\n options = options || {};\n if (!this._cacheCanvas || !this._cacheContext) {\n this._createCacheCanvas();\n }\n if (this.isCacheDirty()) {\n this.statefullCache && this.saveState({ propertySet: 'cacheProperties' });\n this.drawObject(this._cacheContext, options.forClipping);\n this.dirty = false;\n }\n },\n\n /**\n * Remove cacheCanvas and its dimensions from the objects\n */\n _removeCacheCanvas: function() {\n this._cacheCanvas = null;\n this._cacheContext = null;\n this.cacheWidth = 0;\n this.cacheHeight = 0;\n },\n\n /**\n * return true if the object will draw a stroke\n * Does not consider text styles. This is just a shortcut used at rendering time\n * We want it to be an approximation and be fast.\n * wrote to avoid extra caching, it has to return true when stroke happens,\n * can guess when it will not happen at 100% chance, does not matter if it misses\n * some use case where the stroke is invisible.\n * @since 3.0.0\n * @returns Boolean\n */\n hasStroke: function() {\n return this.stroke && this.stroke !== 'transparent' && this.strokeWidth !== 0;\n },\n\n /**\n * return true if the object will draw a fill\n * Does not consider text styles. This is just a shortcut used at rendering time\n * We want it to be an approximation and be fast.\n * wrote to avoid extra caching, it has to return true when fill happens,\n * can guess when it will not happen at 100% chance, does not matter if it misses\n * some use case where the fill is invisible.\n * @since 3.0.0\n * @returns Boolean\n */\n hasFill: function() {\n return this.fill && this.fill !== 'transparent';\n },\n\n /**\n * When set to `true`, force the object to have its own cache, even if it is inside a group\n * it may be needed when your object behave in a particular way on the cache and always needs\n * its own isolated canvas to render correctly.\n * Created to be overridden\n * since 1.7.12\n * @returns Boolean\n */\n needsItsOwnCache: function() {\n if (this.paintFirst === 'stroke' &&\n this.hasFill() && this.hasStroke() && typeof this.shadow === 'object') {\n return true;\n }\n if (this.clipPath) {\n return true;\n }\n return false;\n },\n\n /**\n * Decide if the object should cache or not. Create its own cache level\n * objectCaching is a global flag, wins over everything\n * needsItsOwnCache should be used when the object drawing method requires\n * a cache step. None of the fabric classes requires it.\n * Generally you do not cache objects in groups because the group outside is cached.\n * Read as: cache if is needed, or if the feature is enabled but we are not already caching.\n * @return {Boolean}\n */\n shouldCache: function() {\n this.ownCaching = this.needsItsOwnCache() || (\n this.objectCaching &&\n (!this.group || !this.group.isOnACache())\n );\n return this.ownCaching;\n },\n\n /**\n * Check if this object or a child object will cast a shadow\n * used by Group.shouldCache to know if child has a shadow recursively\n * @return {Boolean}\n */\n willDrawShadow: function() {\n return !!this.shadow && (this.shadow.offsetX !== 0 || this.shadow.offsetY !== 0);\n },\n\n /**\n * Execute the drawing operation for an object clipPath\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {fabric.Object} clipPath\n */\n drawClipPathOnCache: function(ctx, clipPath) {\n ctx.save();\n // DEBUG: uncomment this line, comment the following\n // ctx.globalAlpha = 0.4\n if (clipPath.inverted) {\n ctx.globalCompositeOperation = 'destination-out';\n }\n else {\n ctx.globalCompositeOperation = 'destination-in';\n }\n //ctx.scale(1 / 2, 1 / 2);\n if (clipPath.absolutePositioned) {\n var m = fabric.util.invertTransform(this.calcTransformMatrix());\n ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);\n }\n clipPath.transform(ctx);\n ctx.scale(1 / clipPath.zoomX, 1 / clipPath.zoomY);\n ctx.drawImage(clipPath._cacheCanvas, -clipPath.cacheTranslationX, -clipPath.cacheTranslationY);\n ctx.restore();\n },\n\n /**\n * Execute the drawing operation for an object on a specified context\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n drawObject: function(ctx, forClipping) {\n var originalFill = this.fill, originalStroke = this.stroke;\n if (forClipping) {\n this.fill = 'black';\n this.stroke = '';\n this._setClippingProperties(ctx);\n }\n else {\n this._renderBackground(ctx);\n }\n this._render(ctx);\n this._drawClipPath(ctx, this.clipPath);\n this.fill = originalFill;\n this.stroke = originalStroke;\n },\n\n /**\n * Prepare clipPath state and cache and draw it on instance's cache\n * @param {CanvasRenderingContext2D} ctx\n * @param {fabric.Object} clipPath\n */\n _drawClipPath: function (ctx, clipPath) {\n if (!clipPath) { return; }\n // needed to setup a couple of variables\n // path canvas gets overridden with this one.\n // TODO find a better solution?\n clipPath.canvas = this.canvas;\n clipPath.shouldCache();\n clipPath._transformDone = true;\n clipPath.renderCache({ forClipping: true });\n this.drawClipPathOnCache(ctx, clipPath);\n },\n\n /**\n * Paint the cached copy of the object on the target context.\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n drawCacheOnCanvas: function(ctx) {\n ctx.scale(1 / this.zoomX, 1 / this.zoomY);\n ctx.drawImage(this._cacheCanvas, -this.cacheTranslationX, -this.cacheTranslationY);\n },\n\n /**\n * Check if cache is dirty\n * @param {Boolean} skipCanvas skip canvas checks because this object is painted\n * on parent canvas.\n */\n isCacheDirty: function(skipCanvas) {\n if (this.isNotVisible()) {\n return false;\n }\n if (this._cacheCanvas && this._cacheContext && !skipCanvas && this._updateCacheCanvas()) {\n // in this case the context is already cleared.\n return true;\n }\n else {\n if (this.dirty ||\n (this.clipPath && this.clipPath.absolutePositioned) ||\n (this.statefullCache && this.hasStateChanged('cacheProperties'))\n ) {\n if (this._cacheCanvas && this._cacheContext && !skipCanvas) {\n var width = this.cacheWidth / this.zoomX;\n var height = this.cacheHeight / this.zoomY;\n this._cacheContext.clearRect(-width / 2, -height / 2, width, height);\n }\n return true;\n }\n }\n return false;\n },\n\n /**\n * Draws a background for the object big as its untransformed dimensions\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderBackground: function(ctx) {\n if (!this.backgroundColor) {\n return;\n }\n var dim = this._getNonTransformedDimensions();\n ctx.fillStyle = this.backgroundColor;\n\n ctx.fillRect(\n -dim.x / 2,\n -dim.y / 2,\n dim.x,\n dim.y\n );\n // if there is background color no other shadows\n // should be casted\n this._removeShadow(ctx);\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _setOpacity: function(ctx) {\n if (this.group && !this.group._transformDone) {\n ctx.globalAlpha = this.getObjectOpacity();\n }\n else {\n ctx.globalAlpha *= this.opacity;\n }\n },\n\n _setStrokeStyles: function(ctx, decl) {\n var stroke = decl.stroke;\n if (stroke) {\n ctx.lineWidth = decl.strokeWidth;\n ctx.lineCap = decl.strokeLineCap;\n ctx.lineDashOffset = decl.strokeDashOffset;\n ctx.lineJoin = decl.strokeLineJoin;\n ctx.miterLimit = decl.strokeMiterLimit;\n if (stroke.toLive) {\n if (stroke.gradientUnits === 'percentage' || stroke.gradientTransform || stroke.patternTransform) {\n // need to transform gradient in a pattern.\n // this is a slow process. If you are hitting this codepath, and the object\n // is not using caching, you should consider switching it on.\n // we need a canvas as big as the current object caching canvas.\n this._applyPatternForTransformedGradient(ctx, stroke);\n }\n else {\n // is a simple gradient or pattern\n ctx.strokeStyle = stroke.toLive(ctx, this);\n this._applyPatternGradientTransform(ctx, stroke);\n }\n }\n else {\n // is a color\n ctx.strokeStyle = decl.stroke;\n }\n }\n },\n\n _setFillStyles: function(ctx, decl) {\n var fill = decl.fill;\n if (fill) {\n if (fill.toLive) {\n ctx.fillStyle = fill.toLive(ctx, this);\n this._applyPatternGradientTransform(ctx, decl.fill);\n }\n else {\n ctx.fillStyle = fill;\n }\n }\n },\n\n _setClippingProperties: function(ctx) {\n ctx.globalAlpha = 1;\n ctx.strokeStyle = 'transparent';\n ctx.fillStyle = '#000000';\n },\n\n /**\n * @private\n * Sets line dash\n * @param {CanvasRenderingContext2D} ctx Context to set the dash line on\n * @param {Array} dashArray array representing dashes\n */\n _setLineDash: function(ctx, dashArray) {\n if (!dashArray || dashArray.length === 0) {\n return;\n }\n // Spec requires the concatenation of two copies the dash list when the number of elements is odd\n if (1 & dashArray.length) {\n dashArray.push.apply(dashArray, dashArray);\n }\n ctx.setLineDash(dashArray);\n },\n\n /**\n * Renders controls and borders for the object\n * the context here is not transformed\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {Object} [styleOverride] properties to override the object style\n */\n _renderControls: function(ctx, styleOverride) {\n var vpt = this.getViewportTransform(),\n matrix = this.calcTransformMatrix(),\n options, drawBorders, drawControls;\n styleOverride = styleOverride || { };\n drawBorders = typeof styleOverride.hasBorders !== 'undefined' ? styleOverride.hasBorders : this.hasBorders;\n drawControls = typeof styleOverride.hasControls !== 'undefined' ? styleOverride.hasControls : this.hasControls;\n matrix = fabric.util.multiplyTransformMatrices(vpt, matrix);\n options = fabric.util.qrDecompose(matrix);\n ctx.save();\n ctx.translate(options.translateX, options.translateY);\n ctx.lineWidth = 1 * this.borderScaleFactor;\n if (!this.group) {\n ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n }\n if (this.flipX) {\n options.angle -= 180;\n }\n ctx.rotate(degreesToRadians(this.group ? options.angle : this.angle));\n if (styleOverride.forActiveSelection || this.group) {\n drawBorders && this.drawBordersInGroup(ctx, options, styleOverride);\n }\n else {\n drawBorders && this.drawBorders(ctx, styleOverride);\n }\n drawControls && this.drawControls(ctx, styleOverride);\n ctx.restore();\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _setShadow: function(ctx) {\n if (!this.shadow) {\n return;\n }\n\n var shadow = this.shadow, canvas = this.canvas, scaling,\n multX = (canvas && canvas.viewportTransform[0]) || 1,\n multY = (canvas && canvas.viewportTransform[3]) || 1;\n if (shadow.nonScaling) {\n scaling = { scaleX: 1, scaleY: 1 };\n }\n else {\n scaling = this.getObjectScaling();\n }\n if (canvas && canvas._isRetinaScaling()) {\n multX *= fabric.devicePixelRatio;\n multY *= fabric.devicePixelRatio;\n }\n ctx.shadowColor = shadow.color;\n ctx.shadowBlur = shadow.blur * fabric.browserShadowBlurConstant *\n (multX + multY) * (scaling.scaleX + scaling.scaleY) / 4;\n ctx.shadowOffsetX = shadow.offsetX * multX * scaling.scaleX;\n ctx.shadowOffsetY = shadow.offsetY * multY * scaling.scaleY;\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _removeShadow: function(ctx) {\n if (!this.shadow) {\n return;\n }\n\n ctx.shadowColor = '';\n ctx.shadowBlur = ctx.shadowOffsetX = ctx.shadowOffsetY = 0;\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {Object} filler fabric.Pattern or fabric.Gradient\n * @return {Object} offset.offsetX offset for text rendering\n * @return {Object} offset.offsetY offset for text rendering\n */\n _applyPatternGradientTransform: function(ctx, filler) {\n if (!filler || !filler.toLive) {\n return { offsetX: 0, offsetY: 0 };\n }\n var t = filler.gradientTransform || filler.patternTransform;\n var offsetX = -this.width / 2 + filler.offsetX || 0,\n offsetY = -this.height / 2 + filler.offsetY || 0;\n\n if (filler.gradientUnits === 'percentage') {\n ctx.transform(this.width, 0, 0, this.height, offsetX, offsetY);\n }\n else {\n ctx.transform(1, 0, 0, 1, offsetX, offsetY);\n }\n if (t) {\n ctx.transform(t[0], t[1], t[2], t[3], t[4], t[5]);\n }\n return { offsetX: offsetX, offsetY: offsetY };\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderPaintInOrder: function(ctx) {\n if (this.paintFirst === 'stroke') {\n this._renderStroke(ctx);\n this._renderFill(ctx);\n }\n else {\n this._renderFill(ctx);\n this._renderStroke(ctx);\n }\n },\n\n /**\n * @private\n * function that actually render something on the context.\n * empty here to allow Obects to work on tests to benchmark fabric functionalites\n * not related to rendering\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(/* ctx */) {\n\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderFill: function(ctx) {\n if (!this.fill) {\n return;\n }\n\n ctx.save();\n this._setFillStyles(ctx, this);\n if (this.fillRule === 'evenodd') {\n ctx.fill('evenodd');\n }\n else {\n ctx.fill();\n }\n ctx.restore();\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderStroke: function(ctx) {\n if (!this.stroke || this.strokeWidth === 0) {\n return;\n }\n\n if (this.shadow && !this.shadow.affectStroke) {\n this._removeShadow(ctx);\n }\n\n ctx.save();\n if (this.strokeUniform && this.group) {\n var scaling = this.getObjectScaling();\n ctx.scale(1 / scaling.scaleX, 1 / scaling.scaleY);\n }\n else if (this.strokeUniform) {\n ctx.scale(1 / this.scaleX, 1 / this.scaleY);\n }\n this._setLineDash(ctx, this.strokeDashArray);\n this._setStrokeStyles(ctx, this);\n ctx.stroke();\n ctx.restore();\n },\n\n /**\n * This function try to patch the missing gradientTransform on canvas gradients.\n * transforming a context to transform the gradient, is going to transform the stroke too.\n * we want to transform the gradient but not the stroke operation, so we create\n * a transformed gradient on a pattern and then we use the pattern instead of the gradient.\n * this method has drwabacks: is slow, is in low resolution, needs a patch for when the size\n * is limited.\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {fabric.Gradient} filler a fabric gradient instance\n */\n _applyPatternForTransformedGradient: function(ctx, filler) {\n var dims = this._limitCacheSize(this._getCacheCanvasDimensions()),\n pCanvas = fabric.util.createCanvasElement(), pCtx, retinaScaling = this.canvas.getRetinaScaling(),\n width = dims.x / this.scaleX / retinaScaling, height = dims.y / this.scaleY / retinaScaling;\n pCanvas.width = width;\n pCanvas.height = height;\n pCtx = pCanvas.getContext('2d');\n pCtx.beginPath(); pCtx.moveTo(0, 0); pCtx.lineTo(width, 0); pCtx.lineTo(width, height);\n pCtx.lineTo(0, height); pCtx.closePath();\n pCtx.translate(width / 2, height / 2);\n pCtx.scale(\n dims.zoomX / this.scaleX / retinaScaling,\n dims.zoomY / this.scaleY / retinaScaling\n );\n this._applyPatternGradientTransform(pCtx, filler);\n pCtx.fillStyle = filler.toLive(ctx);\n pCtx.fill();\n ctx.translate(-this.width / 2 - this.strokeWidth / 2, -this.height / 2 - this.strokeWidth / 2);\n ctx.scale(\n retinaScaling * this.scaleX / dims.zoomX,\n retinaScaling * this.scaleY / dims.zoomY\n );\n ctx.strokeStyle = pCtx.createPattern(pCanvas, 'no-repeat');\n },\n\n /**\n * This function is an helper for svg import. it returns the center of the object in the svg\n * untransformed coordinates\n * @private\n * @return {Object} center point from element coordinates\n */\n _findCenterFromElement: function() {\n return { x: this.left + this.width / 2, y: this.top + this.height / 2 };\n },\n\n /**\n * This function is an helper for svg import. it decompose the transformMatrix\n * and assign properties to object.\n * untransformed coordinates\n * @private\n * @chainable\n */\n _assignTransformMatrixProps: function() {\n if (this.transformMatrix) {\n var options = fabric.util.qrDecompose(this.transformMatrix);\n this.flipX = false;\n this.flipY = false;\n this.set('scaleX', options.scaleX);\n this.set('scaleY', options.scaleY);\n this.angle = options.angle;\n this.skewX = options.skewX;\n this.skewY = 0;\n }\n },\n\n /**\n * This function is an helper for svg import. it removes the transform matrix\n * and set to object properties that fabricjs can handle\n * @private\n * @param {Object} preserveAspectRatioOptions\n * @return {thisArg}\n */\n _removeTransformMatrix: function(preserveAspectRatioOptions) {\n var center = this._findCenterFromElement();\n if (this.transformMatrix) {\n this._assignTransformMatrixProps();\n center = fabric.util.transformPoint(center, this.transformMatrix);\n }\n this.transformMatrix = null;\n if (preserveAspectRatioOptions) {\n this.scaleX *= preserveAspectRatioOptions.scaleX;\n this.scaleY *= preserveAspectRatioOptions.scaleY;\n this.cropX = preserveAspectRatioOptions.cropX;\n this.cropY = preserveAspectRatioOptions.cropY;\n center.x += preserveAspectRatioOptions.offsetLeft;\n center.y += preserveAspectRatioOptions.offsetTop;\n this.width = preserveAspectRatioOptions.width;\n this.height = preserveAspectRatioOptions.height;\n }\n this.setPositionByOrigin(center, 'center', 'center');\n },\n\n /**\n * Clones an instance, using a callback method will work for every object.\n * @param {Function} callback Callback is invoked with a clone as a first argument\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n */\n clone: function(callback, propertiesToInclude) {\n var objectForm = this.toObject(propertiesToInclude);\n if (this.constructor.fromObject) {\n this.constructor.fromObject(objectForm, callback);\n }\n else {\n fabric.Object._fromObject('Object', objectForm, callback);\n }\n },\n\n /**\n * Creates an instance of fabric.Image out of an object\n * makes use of toCanvasElement.\n * Once this method was based on toDataUrl and loadImage, so it also had a quality\n * and format option. toCanvasElement is faster and produce no loss of quality.\n * If you need to get a real Jpeg or Png from an object, using toDataURL is the right way to do it.\n * toCanvasElement and then toBlob from the obtained canvas is also a good option.\n * This method is sync now, but still support the callback because we did not want to break.\n * When fabricJS 5.0 will be planned, this will probably be changed to not have a callback.\n * @param {Function} callback callback, invoked with an instance as a first argument\n * @param {Object} [options] for clone as image, passed to toDataURL\n * @param {Number} [options.multiplier=1] Multiplier to scale by\n * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4\n * @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4\n * @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2\n * @return {fabric.Object} thisArg\n */\n cloneAsImage: function(callback, options) {\n var canvasEl = this.toCanvasElement(options);\n if (callback) {\n callback(new fabric.Image(canvasEl));\n }\n return this;\n },\n\n /**\n * Converts an object into a HTMLCanvas element\n * @param {Object} options Options object\n * @param {Number} [options.multiplier=1] Multiplier to scale by\n * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4\n * @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4\n * @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2\n * @return {HTMLCanvasElement} Returns DOM element with the fabric.Object\n */\n toCanvasElement: function(options) {\n options || (options = { });\n\n var utils = fabric.util, origParams = utils.saveObjectTransform(this),\n originalGroup = this.group,\n originalShadow = this.shadow, abs = Math.abs,\n multiplier = (options.multiplier || 1) * (options.enableRetinaScaling ? fabric.devicePixelRatio : 1);\n delete this.group;\n if (options.withoutTransform) {\n utils.resetObjectTransform(this);\n }\n if (options.withoutShadow) {\n this.shadow = null;\n }\n\n var el = fabric.util.createCanvasElement(),\n // skip canvas zoom and calculate with setCoords now.\n boundingRect = this.getBoundingRect(true, true),\n shadow = this.shadow, scaling,\n shadowOffset = { x: 0, y: 0 }, shadowBlur,\n width, height;\n\n if (shadow) {\n shadowBlur = shadow.blur;\n if (shadow.nonScaling) {\n scaling = { scaleX: 1, scaleY: 1 };\n }\n else {\n scaling = this.getObjectScaling();\n }\n // consider non scaling shadow.\n shadowOffset.x = 2 * Math.round(abs(shadow.offsetX) + shadowBlur) * (abs(scaling.scaleX));\n shadowOffset.y = 2 * Math.round(abs(shadow.offsetY) + shadowBlur) * (abs(scaling.scaleY));\n }\n width = boundingRect.width + shadowOffset.x;\n height = boundingRect.height + shadowOffset.y;\n // if the current width/height is not an integer\n // we need to make it so.\n el.width = Math.ceil(width);\n el.height = Math.ceil(height);\n var canvas = new fabric.StaticCanvas(el, {\n enableRetinaScaling: false,\n renderOnAddRemove: false,\n skipOffscreen: false,\n });\n if (options.format === 'jpeg') {\n canvas.backgroundColor = '#fff';\n }\n this.setPositionByOrigin(new fabric.Point(canvas.width / 2, canvas.height / 2), 'center', 'center');\n\n var originalCanvas = this.canvas;\n canvas.add(this);\n var canvasEl = canvas.toCanvasElement(multiplier || 1, options);\n this.shadow = originalShadow;\n this.set('canvas', originalCanvas);\n if (originalGroup) {\n this.group = originalGroup;\n }\n this.set(origParams).setCoords();\n // canvas.dispose will call image.dispose that will nullify the elements\n // since this canvas is a simple element for the process, we remove references\n // to objects in this way in order to avoid object trashing.\n canvas._objects = [];\n canvas.dispose();\n canvas = null;\n\n return canvasEl;\n },\n\n /**\n * Converts an object into a data-url-like string\n * @param {Object} options Options object\n * @param {String} [options.format=png] The format of the output image. Either \"jpeg\" or \"png\"\n * @param {Number} [options.quality=1] Quality level (0..1). Only used for jpeg.\n * @param {Number} [options.multiplier=1] Multiplier to scale by\n * @param {Number} [options.left] Cropping left offset. Introduced in v1.2.14\n * @param {Number} [options.top] Cropping top offset. Introduced in v1.2.14\n * @param {Number} [options.width] Cropping width. Introduced in v1.2.14\n * @param {Number} [options.height] Cropping height. Introduced in v1.2.14\n * @param {Boolean} [options.enableRetinaScaling] Enable retina scaling for clone image. Introduce in 1.6.4\n * @param {Boolean} [options.withoutTransform] Remove current object transform ( no scale , no angle, no flip, no skew ). Introduced in 2.3.4\n * @param {Boolean} [options.withoutShadow] Remove current object shadow. Introduced in 2.4.2\n * @return {String} Returns a data: URL containing a representation of the object in the format specified by options.format\n */\n toDataURL: function(options) {\n options || (options = { });\n return fabric.util.toDataURL(this.toCanvasElement(options), options.format || 'png', options.quality || 1);\n },\n\n /**\n * Returns true if specified type is identical to the type of an instance\n * @param {String} type Type to check against\n * @return {Boolean}\n */\n isType: function(type) {\n return arguments.length > 1 ? Array.from(arguments).includes(this.type) : this.type === type;\n },\n\n /**\n * Returns complexity of an instance\n * @return {Number} complexity of this instance (is 1 unless subclassed)\n */\n complexity: function() {\n return 1;\n },\n\n /**\n * Returns a JSON representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} JSON\n */\n toJSON: function(propertiesToInclude) {\n // delegate, not alias\n return this.toObject(propertiesToInclude);\n },\n\n /**\n * Sets \"angle\" of an instance with centered rotation\n * @param {Number} angle Angle value (in degrees)\n * @return {fabric.Object} thisArg\n * @chainable\n */\n rotate: function(angle) {\n var shouldCenterOrigin = (this.originX !== 'center' || this.originY !== 'center') && this.centeredRotation;\n\n if (shouldCenterOrigin) {\n this._setOriginToCenter();\n }\n\n this.set('angle', angle);\n\n if (shouldCenterOrigin) {\n this._resetOrigin();\n }\n\n return this;\n },\n\n /**\n * Centers object horizontally on canvas to which it was added last.\n * You might need to call `setCoords` on an object after centering, to update controls area.\n * @return {fabric.Object} thisArg\n * @chainable\n */\n centerH: function () {\n this.canvas && this.canvas.centerObjectH(this);\n return this;\n },\n\n /**\n * Centers object horizontally on current viewport of canvas to which it was added last.\n * You might need to call `setCoords` on an object after centering, to update controls area.\n * @return {fabric.Object} thisArg\n * @chainable\n */\n viewportCenterH: function () {\n this.canvas && this.canvas.viewportCenterObjectH(this);\n return this;\n },\n\n /**\n * Centers object vertically on canvas to which it was added last.\n * You might need to call `setCoords` on an object after centering, to update controls area.\n * @return {fabric.Object} thisArg\n * @chainable\n */\n centerV: function () {\n this.canvas && this.canvas.centerObjectV(this);\n return this;\n },\n\n /**\n * Centers object vertically on current viewport of canvas to which it was added last.\n * You might need to call `setCoords` on an object after centering, to update controls area.\n * @return {fabric.Object} thisArg\n * @chainable\n */\n viewportCenterV: function () {\n this.canvas && this.canvas.viewportCenterObjectV(this);\n return this;\n },\n\n /**\n * Centers object vertically and horizontally on canvas to which is was added last\n * You might need to call `setCoords` on an object after centering, to update controls area.\n * @return {fabric.Object} thisArg\n * @chainable\n */\n center: function () {\n this.canvas && this.canvas.centerObject(this);\n return this;\n },\n\n /**\n * Centers object on current viewport of canvas to which it was added last.\n * You might need to call `setCoords` on an object after centering, to update controls area.\n * @return {fabric.Object} thisArg\n * @chainable\n */\n viewportCenter: function () {\n this.canvas && this.canvas.viewportCenterObject(this);\n return this;\n },\n\n /**\n * Returns coordinates of a pointer relative to an object\n * @param {Event} e Event to operate upon\n * @param {Object} [pointer] Pointer to operate upon (instead of event)\n * @return {Object} Coordinates of a pointer (x, y)\n */\n getLocalPointer: function(e, pointer) {\n pointer = pointer || this.canvas.getPointer(e);\n var pClicked = new fabric.Point(pointer.x, pointer.y),\n objectLeftTop = this._getLeftTopCoords();\n if (this.angle) {\n pClicked = fabric.util.rotatePoint(\n pClicked, objectLeftTop, degreesToRadians(-this.angle));\n }\n return {\n x: pClicked.x - objectLeftTop.x,\n y: pClicked.y - objectLeftTop.y\n };\n },\n\n /**\n * Sets canvas globalCompositeOperation for specific object\n * custom composition operation for the particular object can be specified using globalCompositeOperation property\n * @param {CanvasRenderingContext2D} ctx Rendering canvas context\n */\n _setupCompositeOperation: function (ctx) {\n if (this.globalCompositeOperation) {\n ctx.globalCompositeOperation = this.globalCompositeOperation;\n }\n },\n\n /**\n * cancel instance's running animations\n * override if necessary to dispose artifacts such as `clipPath`\n */\n dispose: function () {\n if (fabric.runningAnimations) {\n fabric.runningAnimations.cancelByTarget(this);\n }\n }\n });\n\n fabric.util.createAccessors && fabric.util.createAccessors(fabric.Object);\n\n extend(fabric.Object.prototype, fabric.Observable);\n\n /**\n * Defines the number of fraction digits to use when serializing object values.\n * You can use it to increase/decrease precision of such values like left, top, scaleX, scaleY, etc.\n * @static\n * @memberOf fabric.Object\n * @constant\n * @type Number\n */\n fabric.Object.NUM_FRACTION_DIGITS = 2;\n\n /**\n * Defines which properties should be enlivened from the object passed to {@link fabric.Object._fromObject}\n * @static\n * @memberOf fabric.Object\n * @constant\n * @type string[]\n */\n fabric.Object.ENLIVEN_PROPS = ['clipPath'];\n\n fabric.Object._fromObject = function(className, object, callback, extraParam) {\n var klass = fabric[className];\n object = clone(object, true);\n fabric.util.enlivenPatterns([object.fill, object.stroke], function(patterns) {\n if (typeof patterns[0] !== 'undefined') {\n object.fill = patterns[0];\n }\n if (typeof patterns[1] !== 'undefined') {\n object.stroke = patterns[1];\n }\n fabric.util.enlivenObjectEnlivables(object, object, function () {\n var instance = extraParam ? new klass(object[extraParam], object) : new klass(object);\n callback && callback(instance);\n });\n });\n };\n\n /**\n * Unique id used internally when creating SVG elements\n * @static\n * @memberOf fabric.Object\n * @type Number\n */\n fabric.Object.__uid = 0;\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n var degreesToRadians = fabric.util.degreesToRadians,\n originXOffset = {\n left: -0.5,\n center: 0,\n right: 0.5\n },\n originYOffset = {\n top: -0.5,\n center: 0,\n bottom: 0.5\n };\n\n fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n /**\n * Translates the coordinates from a set of origin to another (based on the object's dimensions)\n * @param {fabric.Point} point The point which corresponds to the originX and originY params\n * @param {String} fromOriginX Horizontal origin: 'left', 'center' or 'right'\n * @param {String} fromOriginY Vertical origin: 'top', 'center' or 'bottom'\n * @param {String} toOriginX Horizontal origin: 'left', 'center' or 'right'\n * @param {String} toOriginY Vertical origin: 'top', 'center' or 'bottom'\n * @return {fabric.Point}\n */\n translateToGivenOrigin: function(point, fromOriginX, fromOriginY, toOriginX, toOriginY) {\n var x = point.x,\n y = point.y,\n offsetX, offsetY, dim;\n\n if (typeof fromOriginX === 'string') {\n fromOriginX = originXOffset[fromOriginX];\n }\n else {\n fromOriginX -= 0.5;\n }\n\n if (typeof toOriginX === 'string') {\n toOriginX = originXOffset[toOriginX];\n }\n else {\n toOriginX -= 0.5;\n }\n\n offsetX = toOriginX - fromOriginX;\n\n if (typeof fromOriginY === 'string') {\n fromOriginY = originYOffset[fromOriginY];\n }\n else {\n fromOriginY -= 0.5;\n }\n\n if (typeof toOriginY === 'string') {\n toOriginY = originYOffset[toOriginY];\n }\n else {\n toOriginY -= 0.5;\n }\n\n offsetY = toOriginY - fromOriginY;\n\n if (offsetX || offsetY) {\n dim = this._getTransformedDimensions();\n x = point.x + offsetX * dim.x;\n y = point.y + offsetY * dim.y;\n }\n\n return new fabric.Point(x, y);\n },\n\n /**\n * Translates the coordinates from origin to center coordinates (based on the object's dimensions)\n * @param {fabric.Point} point The point which corresponds to the originX and originY params\n * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n * @return {fabric.Point}\n */\n translateToCenterPoint: function(point, originX, originY) {\n var p = this.translateToGivenOrigin(point, originX, originY, 'center', 'center');\n if (this.angle) {\n return fabric.util.rotatePoint(p, point, degreesToRadians(this.angle));\n }\n return p;\n },\n\n /**\n * Translates the coordinates from center to origin coordinates (based on the object's dimensions)\n * @param {fabric.Point} center The point which corresponds to center of the object\n * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n * @return {fabric.Point}\n */\n translateToOriginPoint: function(center, originX, originY) {\n var p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);\n if (this.angle) {\n return fabric.util.rotatePoint(p, center, degreesToRadians(this.angle));\n }\n return p;\n },\n\n /**\n * Returns the real center coordinates of the object\n * @return {fabric.Point}\n */\n getCenterPoint: function() {\n var leftTop = new fabric.Point(this.left, this.top);\n return this.translateToCenterPoint(leftTop, this.originX, this.originY);\n },\n\n /**\n * Returns the coordinates of the object based on center coordinates\n * @param {fabric.Point} point The point which corresponds to the originX and originY params\n * @return {fabric.Point}\n */\n // getOriginPoint: function(center) {\n // return this.translateToOriginPoint(center, this.originX, this.originY);\n // },\n\n /**\n * Returns the coordinates of the object as if it has a different origin\n * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n * @return {fabric.Point}\n */\n getPointByOrigin: function(originX, originY) {\n var center = this.getCenterPoint();\n return this.translateToOriginPoint(center, originX, originY);\n },\n\n /**\n * Returns the point in local coordinates\n * @param {fabric.Point} point The point relative to the global coordinate system\n * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n * @return {fabric.Point}\n */\n toLocalPoint: function(point, originX, originY) {\n var center = this.getCenterPoint(),\n p, p2;\n\n if (typeof originX !== 'undefined' && typeof originY !== 'undefined' ) {\n p = this.translateToGivenOrigin(center, 'center', 'center', originX, originY);\n }\n else {\n p = new fabric.Point(this.left, this.top);\n }\n\n p2 = new fabric.Point(point.x, point.y);\n if (this.angle) {\n p2 = fabric.util.rotatePoint(p2, center, -degreesToRadians(this.angle));\n }\n return p2.subtractEquals(p);\n },\n\n /**\n * Returns the point in global coordinates\n * @param {fabric.Point} The point relative to the local coordinate system\n * @return {fabric.Point}\n */\n // toGlobalPoint: function(point) {\n // return fabric.util.rotatePoint(point, this.getCenterPoint(), degreesToRadians(this.angle)).addEquals(new fabric.Point(this.left, this.top));\n // },\n\n /**\n * Sets the position of the object taking into consideration the object's origin\n * @param {fabric.Point} pos The new position of the object\n * @param {String} originX Horizontal origin: 'left', 'center' or 'right'\n * @param {String} originY Vertical origin: 'top', 'center' or 'bottom'\n * @return {void}\n */\n setPositionByOrigin: function(pos, originX, originY) {\n var center = this.translateToCenterPoint(pos, originX, originY),\n position = this.translateToOriginPoint(center, this.originX, this.originY);\n this.set('left', position.x);\n this.set('top', position.y);\n },\n\n /**\n * @param {String} to One of 'left', 'center', 'right'\n */\n adjustPosition: function(to) {\n var angle = degreesToRadians(this.angle),\n hypotFull = this.getScaledWidth(),\n xFull = fabric.util.cos(angle) * hypotFull,\n yFull = fabric.util.sin(angle) * hypotFull,\n offsetFrom, offsetTo;\n\n //TODO: this function does not consider mixed situation like top, center.\n if (typeof this.originX === 'string') {\n offsetFrom = originXOffset[this.originX];\n }\n else {\n offsetFrom = this.originX - 0.5;\n }\n if (typeof to === 'string') {\n offsetTo = originXOffset[to];\n }\n else {\n offsetTo = to - 0.5;\n }\n this.left += xFull * (offsetTo - offsetFrom);\n this.top += yFull * (offsetTo - offsetFrom);\n this.setCoords();\n this.originX = to;\n },\n\n /**\n * Sets the origin/position of the object to it's center point\n * @private\n * @return {void}\n */\n _setOriginToCenter: function() {\n this._originalOriginX = this.originX;\n this._originalOriginY = this.originY;\n\n var center = this.getCenterPoint();\n\n this.originX = 'center';\n this.originY = 'center';\n\n this.left = center.x;\n this.top = center.y;\n },\n\n /**\n * Resets the origin/position of the object to it's original origin\n * @private\n * @return {void}\n */\n _resetOrigin: function() {\n var originPoint = this.translateToOriginPoint(\n this.getCenterPoint(),\n this._originalOriginX,\n this._originalOriginY);\n\n this.originX = this._originalOriginX;\n this.originY = this._originalOriginY;\n\n this.left = originPoint.x;\n this.top = originPoint.y;\n\n this._originalOriginX = null;\n this._originalOriginY = null;\n },\n\n /**\n * @private\n */\n _getLeftTopCoords: function() {\n return this.translateToOriginPoint(this.getCenterPoint(), 'left', 'top');\n },\n });\n\n})();\n\n\n(function() {\n\n function arrayFromCoords(coords) {\n return [\n new fabric.Point(coords.tl.x, coords.tl.y),\n new fabric.Point(coords.tr.x, coords.tr.y),\n new fabric.Point(coords.br.x, coords.br.y),\n new fabric.Point(coords.bl.x, coords.bl.y)\n ];\n }\n\n var util = fabric.util,\n degreesToRadians = util.degreesToRadians,\n multiplyMatrices = util.multiplyTransformMatrices,\n transformPoint = util.transformPoint;\n\n util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n /**\n * Describe object's corner position in canvas element coordinates.\n * properties are depending on control keys and padding the main controls.\n * each property is an object with x, y and corner.\n * The `corner` property contains in a similar manner the 4 points of the\n * interactive area of the corner.\n * The coordinates depends from the controls positionHandler and are used\n * to draw and locate controls\n * @memberOf fabric.Object.prototype\n */\n oCoords: null,\n\n /**\n * Describe object's corner position in canvas object absolute coordinates\n * properties are tl,tr,bl,br and describe the four main corner.\n * each property is an object with x, y, instance of Fabric.Point.\n * The coordinates depends from this properties: width, height, scaleX, scaleY\n * skewX, skewY, angle, strokeWidth, top, left.\n * Those coordinates are useful to understand where an object is. They get updated\n * with oCoords but they do not need to be updated when zoom or panning change.\n * The coordinates get updated with @method setCoords.\n * You can calculate them without updating with @method calcACoords();\n * @memberOf fabric.Object.prototype\n */\n aCoords: null,\n\n /**\n * Describe object's corner position in canvas element coordinates.\n * includes padding. Used of object detection.\n * set and refreshed with setCoords.\n * @memberOf fabric.Object.prototype\n */\n lineCoords: null,\n\n /**\n * storage for object transform matrix\n */\n ownMatrixCache: null,\n\n /**\n * storage for object full transform matrix\n */\n matrixCache: null,\n\n /**\n * custom controls interface\n * controls are added by default_controls.js\n */\n controls: { },\n\n /**\n * return correct set of coordinates for intersection\n * this will return either aCoords or lineCoords.\n * @param {Boolean} absolute will return aCoords if true or lineCoords\n * @return {Object} {tl, tr, br, bl} points\n */\n _getCoords: function(absolute, calculate) {\n if (calculate) {\n return (absolute ? this.calcACoords() : this.calcLineCoords());\n }\n if (!this.aCoords || !this.lineCoords) {\n this.setCoords(true);\n }\n return (absolute ? this.aCoords : this.lineCoords);\n },\n\n /**\n * return correct set of coordinates for intersection\n * this will return either aCoords or lineCoords.\n * The coords are returned in an array.\n * @return {Array} [tl, tr, br, bl] of points\n */\n getCoords: function(absolute, calculate) {\n return arrayFromCoords(this._getCoords(absolute, calculate));\n },\n\n /**\n * Checks if object intersects with an area formed by 2 points\n * @param {Object} pointTL top-left point of area\n * @param {Object} pointBR bottom-right point of area\n * @param {Boolean} [absolute] use coordinates without viewportTransform\n * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n * @return {Boolean} true if object intersects with an area formed by 2 points\n */\n intersectsWithRect: function(pointTL, pointBR, absolute, calculate) {\n var coords = this.getCoords(absolute, calculate),\n intersection = fabric.Intersection.intersectPolygonRectangle(\n coords,\n pointTL,\n pointBR\n );\n return intersection.status === 'Intersection';\n },\n\n /**\n * Checks if object intersects with another object\n * @param {Object} other Object to test\n * @param {Boolean} [absolute] use coordinates without viewportTransform\n * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n * @return {Boolean} true if object intersects with another object\n */\n intersectsWithObject: function(other, absolute, calculate) {\n var intersection = fabric.Intersection.intersectPolygonPolygon(\n this.getCoords(absolute, calculate),\n other.getCoords(absolute, calculate)\n );\n\n return intersection.status === 'Intersection'\n || other.isContainedWithinObject(this, absolute, calculate)\n || this.isContainedWithinObject(other, absolute, calculate);\n },\n\n /**\n * Checks if object is fully contained within area of another object\n * @param {Object} other Object to test\n * @param {Boolean} [absolute] use coordinates without viewportTransform\n * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n * @return {Boolean} true if object is fully contained within area of another object\n */\n isContainedWithinObject: function(other, absolute, calculate) {\n var points = this.getCoords(absolute, calculate),\n otherCoords = absolute ? other.aCoords : other.lineCoords,\n i = 0, lines = other._getImageLines(otherCoords);\n for (; i < 4; i++) {\n if (!other.containsPoint(points[i], lines)) {\n return false;\n }\n }\n return true;\n },\n\n /**\n * Checks if object is fully contained within area formed by 2 points\n * @param {Object} pointTL top-left point of area\n * @param {Object} pointBR bottom-right point of area\n * @param {Boolean} [absolute] use coordinates without viewportTransform\n * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n * @return {Boolean} true if object is fully contained within area formed by 2 points\n */\n isContainedWithinRect: function(pointTL, pointBR, absolute, calculate) {\n var boundingRect = this.getBoundingRect(absolute, calculate);\n\n return (\n boundingRect.left >= pointTL.x &&\n boundingRect.left + boundingRect.width <= pointBR.x &&\n boundingRect.top >= pointTL.y &&\n boundingRect.top + boundingRect.height <= pointBR.y\n );\n },\n\n /**\n * Checks if point is inside the object\n * @param {fabric.Point} point Point to check against\n * @param {Object} [lines] object returned from @method _getImageLines\n * @param {Boolean} [absolute] use coordinates without viewportTransform\n * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n * @return {Boolean} true if point is inside the object\n */\n containsPoint: function(point, lines, absolute, calculate) {\n var coords = this._getCoords(absolute, calculate),\n lines = lines || this._getImageLines(coords),\n xPoints = this._findCrossPoints(point, lines);\n // if xPoints is odd then point is inside the object\n return (xPoints !== 0 && xPoints % 2 === 1);\n },\n\n /**\n * Checks if object is contained within the canvas with current viewportTransform\n * the check is done stopping at first point that appears on screen\n * @param {Boolean} [calculate] use coordinates of current position instead of .aCoords\n * @return {Boolean} true if object is fully or partially contained within canvas\n */\n isOnScreen: function(calculate) {\n if (!this.canvas) {\n return false;\n }\n var pointTL = this.canvas.vptCoords.tl, pointBR = this.canvas.vptCoords.br;\n var points = this.getCoords(true, calculate);\n // if some point is on screen, the object is on screen.\n if (points.some(function(point) {\n return point.x <= pointBR.x && point.x >= pointTL.x &&\n point.y <= pointBR.y && point.y >= pointTL.y;\n })) {\n return true;\n }\n // no points on screen, check intersection with absolute coordinates\n if (this.intersectsWithRect(pointTL, pointBR, true, calculate)) {\n return true;\n }\n return this._containsCenterOfCanvas(pointTL, pointBR, calculate);\n },\n\n /**\n * Checks if the object contains the midpoint between canvas extremities\n * Does not make sense outside the context of isOnScreen and isPartiallyOnScreen\n * @private\n * @param {Fabric.Point} pointTL Top Left point\n * @param {Fabric.Point} pointBR Top Right point\n * @param {Boolean} calculate use coordinates of current position instead of .oCoords\n * @return {Boolean} true if the object contains the point\n */\n _containsCenterOfCanvas: function(pointTL, pointBR, calculate) {\n // worst case scenario the object is so big that contains the screen\n var centerPoint = { x: (pointTL.x + pointBR.x) / 2, y: (pointTL.y + pointBR.y) / 2 };\n if (this.containsPoint(centerPoint, null, true, calculate)) {\n return true;\n }\n return false;\n },\n\n /**\n * Checks if object is partially contained within the canvas with current viewportTransform\n * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords\n * @return {Boolean} true if object is partially contained within canvas\n */\n isPartiallyOnScreen: function(calculate) {\n if (!this.canvas) {\n return false;\n }\n var pointTL = this.canvas.vptCoords.tl, pointBR = this.canvas.vptCoords.br;\n if (this.intersectsWithRect(pointTL, pointBR, true, calculate)) {\n return true;\n }\n var allPointsAreOutside = this.getCoords(true, calculate).every(function(point) {\n return (point.x >= pointBR.x || point.x <= pointTL.x) &&\n (point.y >= pointBR.y || point.y <= pointTL.y);\n });\n return allPointsAreOutside && this._containsCenterOfCanvas(pointTL, pointBR, calculate);\n },\n\n /**\n * Method that returns an object with the object edges in it, given the coordinates of the corners\n * @private\n * @param {Object} oCoords Coordinates of the object corners\n */\n _getImageLines: function(oCoords) {\n\n var lines = {\n topline: {\n o: oCoords.tl,\n d: oCoords.tr\n },\n rightline: {\n o: oCoords.tr,\n d: oCoords.br\n },\n bottomline: {\n o: oCoords.br,\n d: oCoords.bl\n },\n leftline: {\n o: oCoords.bl,\n d: oCoords.tl\n }\n };\n\n // // debugging\n // if (this.canvas.contextTop) {\n // this.canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);\n //\n // this.canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);\n //\n // this.canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);\n //\n // this.canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);\n // }\n\n return lines;\n },\n\n /**\n * Helper method to determine how many cross points are between the 4 object edges\n * and the horizontal line determined by a point on canvas\n * @private\n * @param {fabric.Point} point Point to check\n * @param {Object} lines Coordinates of the object being evaluated\n */\n // remove yi, not used but left code here just in case.\n _findCrossPoints: function(point, lines) {\n var b1, b2, a1, a2, xi, // yi,\n xcount = 0,\n iLine;\n\n for (var lineKey in lines) {\n iLine = lines[lineKey];\n // optimisation 1: line below point. no cross\n if ((iLine.o.y < point.y) && (iLine.d.y < point.y)) {\n continue;\n }\n // optimisation 2: line above point. no cross\n if ((iLine.o.y >= point.y) && (iLine.d.y >= point.y)) {\n continue;\n }\n // optimisation 3: vertical line case\n if ((iLine.o.x === iLine.d.x) && (iLine.o.x >= point.x)) {\n xi = iLine.o.x;\n // yi = point.y;\n }\n // calculate the intersection point\n else {\n b1 = 0;\n b2 = (iLine.d.y - iLine.o.y) / (iLine.d.x - iLine.o.x);\n a1 = point.y - b1 * point.x;\n a2 = iLine.o.y - b2 * iLine.o.x;\n\n xi = -(a1 - a2) / (b1 - b2);\n // yi = a1 + b1 * xi;\n }\n // dont count xi < point.x cases\n if (xi >= point.x) {\n xcount += 1;\n }\n // optimisation 4: specific for square images\n if (xcount === 2) {\n break;\n }\n }\n return xcount;\n },\n\n /**\n * Returns coordinates of object's bounding rectangle (left, top, width, height)\n * the box is intended as aligned to axis of canvas.\n * @param {Boolean} [absolute] use coordinates without viewportTransform\n * @param {Boolean} [calculate] use coordinates of current position instead of .oCoords / .aCoords\n * @return {Object} Object with left, top, width, height properties\n */\n getBoundingRect: function(absolute, calculate) {\n var coords = this.getCoords(absolute, calculate);\n return util.makeBoundingBoxFromPoints(coords);\n },\n\n /**\n * Returns width of an object's bounding box counting transformations\n * before 2.0 it was named getWidth();\n * @return {Number} width value\n */\n getScaledWidth: function() {\n return this._getTransformedDimensions().x;\n },\n\n /**\n * Returns height of an object bounding box counting transformations\n * before 2.0 it was named getHeight();\n * @return {Number} height value\n */\n getScaledHeight: function() {\n return this._getTransformedDimensions().y;\n },\n\n /**\n * Makes sure the scale is valid and modifies it if necessary\n * @private\n * @param {Number} value\n * @return {Number}\n */\n _constrainScale: function(value) {\n if (Math.abs(value) < this.minScaleLimit) {\n if (value < 0) {\n return -this.minScaleLimit;\n }\n else {\n return this.minScaleLimit;\n }\n }\n else if (value === 0) {\n return 0.0001;\n }\n return value;\n },\n\n /**\n * Scales an object (equally by x and y)\n * @param {Number} value Scale factor\n * @return {fabric.Object} thisArg\n * @chainable\n */\n scale: function(value) {\n this._set('scaleX', value);\n this._set('scaleY', value);\n return this.setCoords();\n },\n\n /**\n * Scales an object to a given width, with respect to bounding box (scaling by x/y equally)\n * @param {Number} value New width value\n * @param {Boolean} absolute ignore viewport\n * @return {fabric.Object} thisArg\n * @chainable\n */\n scaleToWidth: function(value, absolute) {\n // adjust to bounding rect factor so that rotated shapes would fit as well\n var boundingRectFactor = this.getBoundingRect(absolute).width / this.getScaledWidth();\n return this.scale(value / this.width / boundingRectFactor);\n },\n\n /**\n * Scales an object to a given height, with respect to bounding box (scaling by x/y equally)\n * @param {Number} value New height value\n * @param {Boolean} absolute ignore viewport\n * @return {fabric.Object} thisArg\n * @chainable\n */\n scaleToHeight: function(value, absolute) {\n // adjust to bounding rect factor so that rotated shapes would fit as well\n var boundingRectFactor = this.getBoundingRect(absolute).height / this.getScaledHeight();\n return this.scale(value / this.height / boundingRectFactor);\n },\n\n calcLineCoords: function() {\n var vpt = this.getViewportTransform(),\n padding = this.padding, angle = degreesToRadians(this.angle),\n cos = util.cos(angle), sin = util.sin(angle),\n cosP = cos * padding, sinP = sin * padding, cosPSinP = cosP + sinP,\n cosPMinusSinP = cosP - sinP, aCoords = this.calcACoords();\n\n var lineCoords = {\n tl: transformPoint(aCoords.tl, vpt),\n tr: transformPoint(aCoords.tr, vpt),\n bl: transformPoint(aCoords.bl, vpt),\n br: transformPoint(aCoords.br, vpt),\n };\n\n if (padding) {\n lineCoords.tl.x -= cosPMinusSinP;\n lineCoords.tl.y -= cosPSinP;\n lineCoords.tr.x += cosPSinP;\n lineCoords.tr.y -= cosPMinusSinP;\n lineCoords.bl.x -= cosPSinP;\n lineCoords.bl.y += cosPMinusSinP;\n lineCoords.br.x += cosPMinusSinP;\n lineCoords.br.y += cosPSinP;\n }\n\n return lineCoords;\n },\n\n calcOCoords: function() {\n var rotateMatrix = this._calcRotateMatrix(),\n translateMatrix = this._calcTranslateMatrix(),\n vpt = this.getViewportTransform(),\n startMatrix = multiplyMatrices(vpt, translateMatrix),\n finalMatrix = multiplyMatrices(startMatrix, rotateMatrix),\n finalMatrix = multiplyMatrices(finalMatrix, [1 / vpt[0], 0, 0, 1 / vpt[3], 0, 0]),\n dim = this._calculateCurrentDimensions(),\n coords = {};\n this.forEachControl(function(control, key, fabricObject) {\n coords[key] = control.positionHandler(dim, finalMatrix, fabricObject);\n });\n\n // debug code\n // var canvas = this.canvas;\n // setTimeout(function() {\n // canvas.contextTop.clearRect(0, 0, 700, 700);\n // canvas.contextTop.fillStyle = 'green';\n // Object.keys(coords).forEach(function(key) {\n // var control = coords[key];\n // canvas.contextTop.fillRect(control.x, control.y, 3, 3);\n // });\n // }, 50);\n return coords;\n },\n\n calcACoords: function() {\n var rotateMatrix = this._calcRotateMatrix(),\n translateMatrix = this._calcTranslateMatrix(),\n finalMatrix = multiplyMatrices(translateMatrix, rotateMatrix),\n dim = this._getTransformedDimensions(),\n w = dim.x / 2, h = dim.y / 2;\n return {\n // corners\n tl: transformPoint({ x: -w, y: -h }, finalMatrix),\n tr: transformPoint({ x: w, y: -h }, finalMatrix),\n bl: transformPoint({ x: -w, y: h }, finalMatrix),\n br: transformPoint({ x: w, y: h }, finalMatrix)\n };\n },\n\n /**\n * Sets corner and controls position coordinates based on current angle, width and height, left and top.\n * oCoords are used to find the corners\n * aCoords are used to quickly find an object on the canvas\n * lineCoords are used to quickly find object during pointer events.\n * See {@link https://github.com/fabricjs/fabric.js/wiki/When-to-call-setCoords} and {@link http://fabricjs.com/fabric-gotchas}\n *\n * @param {Boolean} [skipCorners] skip calculation of oCoords.\n * @return {fabric.Object} thisArg\n * @chainable\n */\n setCoords: function(skipCorners) {\n this.aCoords = this.calcACoords();\n // in case we are in a group, for how the inner group target check works,\n // lineCoords are exactly aCoords. Since the vpt gets absorbed by the normalized pointer.\n this.lineCoords = this.group ? this.aCoords : this.calcLineCoords();\n if (skipCorners) {\n return this;\n }\n // set coordinates of the draggable boxes in the corners used to scale/rotate the image\n this.oCoords = this.calcOCoords();\n this._setCornerCoords && this._setCornerCoords();\n return this;\n },\n\n /**\n * calculate rotation matrix of an object\n * @return {Array} rotation matrix for the object\n */\n _calcRotateMatrix: function() {\n return util.calcRotateMatrix(this);\n },\n\n /**\n * calculate the translation matrix for an object transform\n * @return {Array} rotation matrix for the object\n */\n _calcTranslateMatrix: function() {\n var center = this.getCenterPoint();\n return [1, 0, 0, 1, center.x, center.y];\n },\n\n transformMatrixKey: function(skipGroup) {\n var sep = '_', prefix = '';\n if (!skipGroup && this.group) {\n prefix = this.group.transformMatrixKey(skipGroup) + sep;\n };\n return prefix + this.top + sep + this.left + sep + this.scaleX + sep + this.scaleY +\n sep + this.skewX + sep + this.skewY + sep + this.angle + sep + this.originX + sep + this.originY +\n sep + this.width + sep + this.height + sep + this.strokeWidth + this.flipX + this.flipY;\n },\n\n /**\n * calculate transform matrix that represents the current transformations from the\n * object's properties.\n * @param {Boolean} [skipGroup] return transform matrix for object not counting parent transformations\n * There are some situation in which this is useful to avoid the fake rotation.\n * @return {Array} transform matrix for the object\n */\n calcTransformMatrix: function(skipGroup) {\n var matrix = this.calcOwnMatrix();\n if (skipGroup || !this.group) {\n return matrix;\n }\n var key = this.transformMatrixKey(skipGroup), cache = this.matrixCache || (this.matrixCache = {});\n if (cache.key === key) {\n return cache.value;\n }\n if (this.group) {\n matrix = multiplyMatrices(this.group.calcTransformMatrix(false), matrix);\n }\n cache.key = key;\n cache.value = matrix;\n return matrix;\n },\n\n /**\n * calculate transform matrix that represents the current transformations from the\n * object's properties, this matrix does not include the group transformation\n * @return {Array} transform matrix for the object\n */\n calcOwnMatrix: function() {\n var key = this.transformMatrixKey(true), cache = this.ownMatrixCache || (this.ownMatrixCache = {});\n if (cache.key === key) {\n return cache.value;\n }\n var tMatrix = this._calcTranslateMatrix(),\n options = {\n angle: this.angle,\n translateX: tMatrix[4],\n translateY: tMatrix[5],\n scaleX: this.scaleX,\n scaleY: this.scaleY,\n skewX: this.skewX,\n skewY: this.skewY,\n flipX: this.flipX,\n flipY: this.flipY,\n };\n cache.key = key;\n cache.value = util.composeMatrix(options);\n return cache.value;\n },\n\n /*\n * Calculate object dimensions from its properties\n * @private\n * @return {Object} .x width dimension\n * @return {Object} .y height dimension\n */\n _getNonTransformedDimensions: function() {\n var strokeWidth = this.strokeWidth,\n w = this.width + strokeWidth,\n h = this.height + strokeWidth;\n return { x: w, y: h };\n },\n\n /*\n * Calculate object bounding box dimensions from its properties scale, skew.\n * @param {Number} skewX, a value to override current skewX\n * @param {Number} skewY, a value to override current skewY\n * @private\n * @return {Object} .x width dimension\n * @return {Object} .y height dimension\n */\n _getTransformedDimensions: function(skewX, skewY) {\n if (typeof skewX === 'undefined') {\n skewX = this.skewX;\n }\n if (typeof skewY === 'undefined') {\n skewY = this.skewY;\n }\n var dimensions, dimX, dimY,\n noSkew = skewX === 0 && skewY === 0;\n\n if (this.strokeUniform) {\n dimX = this.width;\n dimY = this.height;\n }\n else {\n dimensions = this._getNonTransformedDimensions();\n dimX = dimensions.x;\n dimY = dimensions.y;\n }\n if (noSkew) {\n return this._finalizeDimensions(dimX * this.scaleX, dimY * this.scaleY);\n }\n var bbox = util.sizeAfterTransform(dimX, dimY, {\n scaleX: this.scaleX,\n scaleY: this.scaleY,\n skewX: skewX,\n skewY: skewY,\n });\n return this._finalizeDimensions(bbox.x, bbox.y);\n },\n\n /*\n * Calculate object bounding box dimensions from its properties scale, skew.\n * @param Number width width of the bbox\n * @param Number height height of the bbox\n * @private\n * @return {Object} .x finalized width dimension\n * @return {Object} .y finalized height dimension\n */\n _finalizeDimensions: function(width, height) {\n return this.strokeUniform ?\n { x: width + this.strokeWidth, y: height + this.strokeWidth }\n :\n { x: width, y: height };\n },\n\n /*\n * Calculate object dimensions for controls box, including padding and canvas zoom.\n * and active selection\n * private\n */\n _calculateCurrentDimensions: function() {\n var vpt = this.getViewportTransform(),\n dim = this._getTransformedDimensions(),\n p = transformPoint(dim, vpt, true);\n return p.scalarAdd(2 * this.padding);\n },\n });\n})();\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n /**\n * Moves an object to the bottom of the stack of drawn objects\n * @return {fabric.Object} thisArg\n * @chainable\n */\n sendToBack: function() {\n if (this.group) {\n fabric.StaticCanvas.prototype.sendToBack.call(this.group, this);\n }\n else if (this.canvas) {\n this.canvas.sendToBack(this);\n }\n return this;\n },\n\n /**\n * Moves an object to the top of the stack of drawn objects\n * @return {fabric.Object} thisArg\n * @chainable\n */\n bringToFront: function() {\n if (this.group) {\n fabric.StaticCanvas.prototype.bringToFront.call(this.group, this);\n }\n else if (this.canvas) {\n this.canvas.bringToFront(this);\n }\n return this;\n },\n\n /**\n * Moves an object down in stack of drawn objects\n * @param {Boolean} [intersecting] If `true`, send object behind next lower intersecting object\n * @return {fabric.Object} thisArg\n * @chainable\n */\n sendBackwards: function(intersecting) {\n if (this.group) {\n fabric.StaticCanvas.prototype.sendBackwards.call(this.group, this, intersecting);\n }\n else if (this.canvas) {\n this.canvas.sendBackwards(this, intersecting);\n }\n return this;\n },\n\n /**\n * Moves an object up in stack of drawn objects\n * @param {Boolean} [intersecting] If `true`, send object in front of next upper intersecting object\n * @return {fabric.Object} thisArg\n * @chainable\n */\n bringForward: function(intersecting) {\n if (this.group) {\n fabric.StaticCanvas.prototype.bringForward.call(this.group, this, intersecting);\n }\n else if (this.canvas) {\n this.canvas.bringForward(this, intersecting);\n }\n return this;\n },\n\n /**\n * Moves an object to specified level in stack of drawn objects\n * @param {Number} index New position of object\n * @return {fabric.Object} thisArg\n * @chainable\n */\n moveTo: function(index) {\n if (this.group && this.group.type !== 'activeSelection') {\n fabric.StaticCanvas.prototype.moveTo.call(this.group, this, index);\n }\n else if (this.canvas) {\n this.canvas.moveTo(this, index);\n }\n return this;\n }\n});\n\n\n/* _TO_SVG_START_ */\n(function() {\n function getSvgColorString(prop, value) {\n if (!value) {\n return prop + ': none; ';\n }\n else if (value.toLive) {\n return prop + ': url(#SVGID_' + value.id + '); ';\n }\n else {\n var color = new fabric.Color(value),\n str = prop + ': ' + color.toRgb() + '; ',\n opacity = color.getAlpha();\n if (opacity !== 1) {\n //change the color in rgb + opacity\n str += prop + '-opacity: ' + opacity.toString() + '; ';\n }\n return str;\n }\n }\n\n var toFixed = fabric.util.toFixed;\n\n fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n /**\n * Returns styles-string for svg-export\n * @param {Boolean} skipShadow a boolean to skip shadow filter output\n * @return {String}\n */\n getSvgStyles: function(skipShadow) {\n\n var fillRule = this.fillRule ? this.fillRule : 'nonzero',\n strokeWidth = this.strokeWidth ? this.strokeWidth : '0',\n strokeDashArray = this.strokeDashArray ? this.strokeDashArray.join(' ') : 'none',\n strokeDashOffset = this.strokeDashOffset ? this.strokeDashOffset : '0',\n strokeLineCap = this.strokeLineCap ? this.strokeLineCap : 'butt',\n strokeLineJoin = this.strokeLineJoin ? this.strokeLineJoin : 'miter',\n strokeMiterLimit = this.strokeMiterLimit ? this.strokeMiterLimit : '4',\n opacity = typeof this.opacity !== 'undefined' ? this.opacity : '1',\n visibility = this.visible ? '' : ' visibility: hidden;',\n filter = skipShadow ? '' : this.getSvgFilter(),\n fill = getSvgColorString('fill', this.fill),\n stroke = getSvgColorString('stroke', this.stroke);\n\n return [\n stroke,\n 'stroke-width: ', strokeWidth, '; ',\n 'stroke-dasharray: ', strokeDashArray, '; ',\n 'stroke-linecap: ', strokeLineCap, '; ',\n 'stroke-dashoffset: ', strokeDashOffset, '; ',\n 'stroke-linejoin: ', strokeLineJoin, '; ',\n 'stroke-miterlimit: ', strokeMiterLimit, '; ',\n fill,\n 'fill-rule: ', fillRule, '; ',\n 'opacity: ', opacity, ';',\n filter,\n visibility\n ].join('');\n },\n\n /**\n * Returns styles-string for svg-export\n * @param {Object} style the object from which to retrieve style properties\n * @param {Boolean} useWhiteSpace a boolean to include an additional attribute in the style.\n * @return {String}\n */\n getSvgSpanStyles: function(style, useWhiteSpace) {\n var term = '; ';\n var fontFamily = style.fontFamily ?\n 'font-family: ' + (((style.fontFamily.indexOf('\\'') === -1 && style.fontFamily.indexOf('\"') === -1) ?\n '\\'' + style.fontFamily + '\\'' : style.fontFamily)) + term : '';\n var strokeWidth = style.strokeWidth ? 'stroke-width: ' + style.strokeWidth + term : '',\n fontFamily = fontFamily,\n fontSize = style.fontSize ? 'font-size: ' + style.fontSize + 'px' + term : '',\n fontStyle = style.fontStyle ? 'font-style: ' + style.fontStyle + term : '',\n fontWeight = style.fontWeight ? 'font-weight: ' + style.fontWeight + term : '',\n fill = style.fill ? getSvgColorString('fill', style.fill) : '',\n stroke = style.stroke ? getSvgColorString('stroke', style.stroke) : '',\n textDecoration = this.getSvgTextDecoration(style),\n deltaY = style.deltaY ? 'baseline-shift: ' + (-style.deltaY) + '; ' : '';\n if (textDecoration) {\n textDecoration = 'text-decoration: ' + textDecoration + term;\n }\n\n return [\n stroke,\n strokeWidth,\n fontFamily,\n fontSize,\n fontStyle,\n fontWeight,\n textDecoration,\n fill,\n deltaY,\n useWhiteSpace ? 'white-space: pre; ' : ''\n ].join('');\n },\n\n /**\n * Returns text-decoration property for svg-export\n * @param {Object} style the object from which to retrieve style properties\n * @return {String}\n */\n getSvgTextDecoration: function(style) {\n return ['overline', 'underline', 'line-through'].filter(function(decoration) {\n return style[decoration.replace('-', '')];\n }).join(' ');\n },\n\n /**\n * Returns filter for svg shadow\n * @return {String}\n */\n getSvgFilter: function() {\n return this.shadow ? 'filter: url(#SVGID_' + this.shadow.id + ');' : '';\n },\n\n /**\n * Returns id attribute for svg output\n * @return {String}\n */\n getSvgCommons: function() {\n return [\n this.id ? 'id=\"' + this.id + '\" ' : '',\n this.clipPath ? 'clip-path=\"url(#' + this.clipPath.clipPathId + ')\" ' : '',\n ].join('');\n },\n\n /**\n * Returns transform-string for svg-export\n * @param {Boolean} use the full transform or the single object one.\n * @return {String}\n */\n getSvgTransform: function(full, additionalTransform) {\n var transform = full ? this.calcTransformMatrix() : this.calcOwnMatrix(),\n svgTransform = 'transform=\"' + fabric.util.matrixToSVG(transform);\n return svgTransform +\n (additionalTransform || '') + '\" ';\n },\n\n _setSVGBg: function(textBgRects) {\n if (this.backgroundColor) {\n var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n textBgRects.push(\n '\\t\\t\\n');\n }\n },\n\n /**\n * Returns svg representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n toSVG: function(reviver) {\n return this._createBaseSVGMarkup(this._toSVG(reviver), { reviver: reviver });\n },\n\n /**\n * Returns svg clipPath representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n toClipPathSVG: function(reviver) {\n return '\\t' + this._createBaseClipPathSVGMarkup(this._toSVG(reviver), { reviver: reviver });\n },\n\n /**\n * @private\n */\n _createBaseClipPathSVGMarkup: function(objectMarkup, options) {\n options = options || {};\n var reviver = options.reviver,\n additionalTransform = options.additionalTransform || '',\n commonPieces = [\n this.getSvgTransform(true, additionalTransform),\n this.getSvgCommons(),\n ].join(''),\n // insert commons in the markup, style and svgCommons\n index = objectMarkup.indexOf('COMMON_PARTS');\n objectMarkup[index] = commonPieces;\n return reviver ? reviver(objectMarkup.join('')) : objectMarkup.join('');\n },\n\n /**\n * @private\n */\n _createBaseSVGMarkup: function(objectMarkup, options) {\n options = options || {};\n var noStyle = options.noStyle,\n reviver = options.reviver,\n styleInfo = noStyle ? '' : 'style=\"' + this.getSvgStyles() + '\" ',\n shadowInfo = options.withShadow ? 'style=\"' + this.getSvgFilter() + '\" ' : '',\n clipPath = this.clipPath,\n vectorEffect = this.strokeUniform ? 'vector-effect=\"non-scaling-stroke\" ' : '',\n absoluteClipPath = clipPath && clipPath.absolutePositioned,\n stroke = this.stroke, fill = this.fill, shadow = this.shadow,\n commonPieces, markup = [], clipPathMarkup,\n // insert commons in the markup, style and svgCommons\n index = objectMarkup.indexOf('COMMON_PARTS'),\n additionalTransform = options.additionalTransform;\n if (clipPath) {\n clipPath.clipPathId = 'CLIPPATH_' + fabric.Object.__uid++;\n clipPathMarkup = '\\n' +\n clipPath.toClipPathSVG(reviver) +\n '\\n';\n }\n if (absoluteClipPath) {\n markup.push(\n '\\n'\n );\n }\n markup.push(\n '\\n'\n );\n commonPieces = [\n styleInfo,\n vectorEffect,\n noStyle ? '' : this.addPaintOrder(), ' ',\n additionalTransform ? 'transform=\"' + additionalTransform + '\" ' : '',\n ].join('');\n objectMarkup[index] = commonPieces;\n if (fill && fill.toLive) {\n markup.push(fill.toSVG(this));\n }\n if (stroke && stroke.toLive) {\n markup.push(stroke.toSVG(this));\n }\n if (shadow) {\n markup.push(shadow.toSVG(this));\n }\n if (clipPath) {\n markup.push(clipPathMarkup);\n }\n markup.push(objectMarkup.join(''));\n markup.push('\\n');\n absoluteClipPath && markup.push('\\n');\n return reviver ? reviver(markup.join('')) : markup.join('');\n },\n\n addPaintOrder: function() {\n return this.paintFirst !== 'fill' ? ' paint-order=\"' + this.paintFirst + '\" ' : '';\n }\n });\n})();\n/* _TO_SVG_END_ */\n\n\n(function() {\n\n var extend = fabric.util.object.extend,\n originalSet = 'stateProperties';\n\n /*\n Depends on `stateProperties`\n */\n function saveProps(origin, destination, props) {\n var tmpObj = { }, deep = true;\n props.forEach(function(prop) {\n tmpObj[prop] = origin[prop];\n });\n\n extend(origin[destination], tmpObj, deep);\n }\n\n function _isEqual(origValue, currentValue, firstPass) {\n if (origValue === currentValue) {\n // if the objects are identical, return\n return true;\n }\n else if (Array.isArray(origValue)) {\n if (!Array.isArray(currentValue) || origValue.length !== currentValue.length) {\n return false;\n }\n for (var i = 0, len = origValue.length; i < len; i++) {\n if (!_isEqual(origValue[i], currentValue[i])) {\n return false;\n }\n }\n return true;\n }\n else if (origValue && typeof origValue === 'object') {\n var keys = Object.keys(origValue), key;\n if (!currentValue ||\n typeof currentValue !== 'object' ||\n (!firstPass && keys.length !== Object.keys(currentValue).length)\n ) {\n return false;\n }\n for (var i = 0, len = keys.length; i < len; i++) {\n key = keys[i];\n // since clipPath is in the statefull cache list and the clipPath objects\n // would be iterated as an object, this would lead to possible infinite recursion\n // we do not want to compare those.\n if (key === 'canvas' || key === 'group') {\n continue;\n }\n if (!_isEqual(origValue[key], currentValue[key])) {\n return false;\n }\n }\n return true;\n }\n }\n\n\n fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n /**\n * Returns true if object state (one of its state properties) was changed\n * @param {String} [propertySet] optional name for the set of property we want to save\n * @return {Boolean} true if instance' state has changed since `{@link fabric.Object#saveState}` was called\n */\n hasStateChanged: function(propertySet) {\n propertySet = propertySet || originalSet;\n var dashedPropertySet = '_' + propertySet;\n if (Object.keys(this[dashedPropertySet]).length < this[propertySet].length) {\n return true;\n }\n return !_isEqual(this[dashedPropertySet], this, true);\n },\n\n /**\n * Saves state of an object\n * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n * @return {fabric.Object} thisArg\n */\n saveState: function(options) {\n var propertySet = options && options.propertySet || originalSet,\n destination = '_' + propertySet;\n if (!this[destination]) {\n return this.setupState(options);\n }\n saveProps(this, destination, this[propertySet]);\n if (options && options.stateProperties) {\n saveProps(this, destination, options.stateProperties);\n }\n return this;\n },\n\n /**\n * Setups state of an object\n * @param {Object} [options] Object with additional `stateProperties` array to include when saving state\n * @return {fabric.Object} thisArg\n */\n setupState: function(options) {\n options = options || { };\n var propertySet = options.propertySet || originalSet;\n options.propertySet = propertySet;\n this['_' + propertySet] = { };\n this.saveState(options);\n return this;\n }\n });\n})();\n\n\n(function() {\n\n var degreesToRadians = fabric.util.degreesToRadians;\n\n fabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n /**\n * Determines which corner has been clicked\n * @private\n * @param {Object} pointer The pointer indicating the mouse position\n * @return {String|Boolean} corner code (tl, tr, bl, br, etc.), or false if nothing is found\n */\n _findTargetCorner: function(pointer, forTouch) {\n // objects in group, anykind, are not self modificable,\n // must not return an hovered corner.\n if (!this.hasControls || this.group || (!this.canvas || this.canvas._activeObject !== this)) {\n return false;\n }\n\n var ex = pointer.x,\n ey = pointer.y,\n xPoints,\n lines, keys = Object.keys(this.oCoords),\n j = keys.length - 1, i;\n this.__corner = 0;\n\n // cycle in reverse order so we pick first the one on top\n for (; j >= 0; j--) {\n i = keys[j];\n if (!this.isControlVisible(i)) {\n continue;\n }\n\n lines = this._getImageLines(forTouch ? this.oCoords[i].touchCorner : this.oCoords[i].corner);\n // // debugging\n //\n // this.canvas.contextTop.fillRect(lines.bottomline.d.x, lines.bottomline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.bottomline.o.x, lines.bottomline.o.y, 2, 2);\n //\n // this.canvas.contextTop.fillRect(lines.leftline.d.x, lines.leftline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.leftline.o.x, lines.leftline.o.y, 2, 2);\n //\n // this.canvas.contextTop.fillRect(lines.topline.d.x, lines.topline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.topline.o.x, lines.topline.o.y, 2, 2);\n //\n // this.canvas.contextTop.fillRect(lines.rightline.d.x, lines.rightline.d.y, 2, 2);\n // this.canvas.contextTop.fillRect(lines.rightline.o.x, lines.rightline.o.y, 2, 2);\n\n xPoints = this._findCrossPoints({ x: ex, y: ey }, lines);\n if (xPoints !== 0 && xPoints % 2 === 1) {\n this.__corner = i;\n return i;\n }\n }\n return false;\n },\n\n /**\n * Calls a function for each control. The function gets called,\n * with the control, the object that is calling the iterator and the control's key\n * @param {Function} fn function to iterate over the controls over\n */\n forEachControl: function(fn) {\n for (var i in this.controls) {\n fn(this.controls[i], i, this);\n };\n },\n\n /**\n * Sets the coordinates of the draggable boxes in the corners of\n * the image used to scale/rotate it.\n * note: if we would switch to ROUND corner area, all of this would disappear.\n * everything would resolve to a single point and a pythagorean theorem for the distance\n * @private\n */\n _setCornerCoords: function() {\n var coords = this.oCoords;\n\n for (var control in coords) {\n var controlObject = this.controls[control];\n coords[control].corner = controlObject.calcCornerCoords(\n this.angle, this.cornerSize, coords[control].x, coords[control].y, false);\n coords[control].touchCorner = controlObject.calcCornerCoords(\n this.angle, this.touchCornerSize, coords[control].x, coords[control].y, true);\n }\n },\n\n /**\n * Draws a colored layer behind the object, inside its selection borders.\n * Requires public options: padding, selectionBackgroundColor\n * this function is called when the context is transformed\n * has checks to be skipped when the object is on a staticCanvas\n * @param {CanvasRenderingContext2D} ctx Context to draw on\n * @return {fabric.Object} thisArg\n * @chainable\n */\n drawSelectionBackground: function(ctx) {\n if (!this.selectionBackgroundColor ||\n (this.canvas && !this.canvas.interactive) ||\n (this.canvas && this.canvas._activeObject !== this)\n ) {\n return this;\n }\n ctx.save();\n var center = this.getCenterPoint(), wh = this._calculateCurrentDimensions(),\n vpt = this.canvas.viewportTransform;\n ctx.translate(center.x, center.y);\n ctx.scale(1 / vpt[0], 1 / vpt[3]);\n ctx.rotate(degreesToRadians(this.angle));\n ctx.fillStyle = this.selectionBackgroundColor;\n ctx.fillRect(-wh.x / 2, -wh.y / 2, wh.x, wh.y);\n ctx.restore();\n return this;\n },\n\n /**\n * Draws borders of an object's bounding box.\n * Requires public properties: width, height\n * Requires public options: padding, borderColor\n * @param {CanvasRenderingContext2D} ctx Context to draw on\n * @param {Object} styleOverride object to override the object style\n * @return {fabric.Object} thisArg\n * @chainable\n */\n drawBorders: function(ctx, styleOverride) {\n styleOverride = styleOverride || {};\n var wh = this._calculateCurrentDimensions(),\n strokeWidth = this.borderScaleFactor,\n width = wh.x + strokeWidth,\n height = wh.y + strokeWidth,\n hasControls = typeof styleOverride.hasControls !== 'undefined' ?\n styleOverride.hasControls : this.hasControls,\n shouldStroke = false;\n\n ctx.save();\n ctx.strokeStyle = styleOverride.borderColor || this.borderColor;\n this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray);\n\n ctx.strokeRect(\n -width / 2,\n -height / 2,\n width,\n height\n );\n\n if (hasControls) {\n ctx.beginPath();\n this.forEachControl(function(control, key, fabricObject) {\n // in this moment, the ctx is centered on the object.\n // width and height of the above function are the size of the bbox.\n if (control.withConnection && control.getVisibility(fabricObject, key)) {\n // reset movement for each control\n shouldStroke = true;\n ctx.moveTo(control.x * width, control.y * height);\n ctx.lineTo(\n control.x * width + control.offsetX,\n control.y * height + control.offsetY\n );\n }\n });\n if (shouldStroke) {\n ctx.stroke();\n }\n }\n ctx.restore();\n return this;\n },\n\n /**\n * Draws borders of an object's bounding box when it is inside a group.\n * Requires public properties: width, height\n * Requires public options: padding, borderColor\n * @param {CanvasRenderingContext2D} ctx Context to draw on\n * @param {object} options object representing current object parameters\n * @param {Object} styleOverride object to override the object style\n * @return {fabric.Object} thisArg\n * @chainable\n */\n drawBordersInGroup: function(ctx, options, styleOverride) {\n styleOverride = styleOverride || {};\n var bbox = fabric.util.sizeAfterTransform(this.width, this.height, options),\n strokeWidth = this.strokeWidth,\n strokeUniform = this.strokeUniform,\n borderScaleFactor = this.borderScaleFactor,\n width =\n bbox.x + strokeWidth * (strokeUniform ? this.canvas.getZoom() : options.scaleX) + borderScaleFactor,\n height =\n bbox.y + strokeWidth * (strokeUniform ? this.canvas.getZoom() : options.scaleY) + borderScaleFactor;\n ctx.save();\n this._setLineDash(ctx, styleOverride.borderDashArray || this.borderDashArray);\n ctx.strokeStyle = styleOverride.borderColor || this.borderColor;\n ctx.strokeRect(\n -width / 2,\n -height / 2,\n width,\n height\n );\n\n ctx.restore();\n return this;\n },\n\n /**\n * Draws corners of an object's bounding box.\n * Requires public properties: width, height\n * Requires public options: cornerSize, padding\n * @param {CanvasRenderingContext2D} ctx Context to draw on\n * @param {Object} styleOverride object to override the object style\n * @return {fabric.Object} thisArg\n * @chainable\n */\n drawControls: function(ctx, styleOverride) {\n styleOverride = styleOverride || {};\n ctx.save();\n var retinaScaling = this.canvas.getRetinaScaling(), matrix, p;\n ctx.setTransform(retinaScaling, 0, 0, retinaScaling, 0, 0);\n ctx.strokeStyle = ctx.fillStyle = styleOverride.cornerColor || this.cornerColor;\n if (!this.transparentCorners) {\n ctx.strokeStyle = styleOverride.cornerStrokeColor || this.cornerStrokeColor;\n }\n this._setLineDash(ctx, styleOverride.cornerDashArray || this.cornerDashArray);\n this.setCoords();\n if (this.group) {\n // fabricJS does not really support drawing controls inside groups,\n // this piece of code here helps having at least the control in places.\n // If an application needs to show some objects as selected because of some UI state\n // can still call Object._renderControls() on any object they desire, independently of groups.\n // using no padding, circular controls and hiding the rotating cursor is higly suggested,\n matrix = this.group.calcTransformMatrix();\n }\n this.forEachControl(function(control, key, fabricObject) {\n p = fabricObject.oCoords[key];\n if (control.getVisibility(fabricObject, key)) {\n if (matrix) {\n p = fabric.util.transformPoint(p, matrix);\n }\n control.render(ctx, p.x, p.y, styleOverride, fabricObject);\n }\n });\n ctx.restore();\n\n return this;\n },\n\n /**\n * Returns true if the specified control is visible, false otherwise.\n * @param {String} controlKey The key of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n * @returns {Boolean} true if the specified control is visible, false otherwise\n */\n isControlVisible: function(controlKey) {\n return this.controls[controlKey] && this.controls[controlKey].getVisibility(this, controlKey);\n },\n\n /**\n * Sets the visibility of the specified control.\n * @param {String} controlKey The key of the control. Possible values are 'tl', 'tr', 'br', 'bl', 'ml', 'mt', 'mr', 'mb', 'mtr'.\n * @param {Boolean} visible true to set the specified control visible, false otherwise\n * @return {fabric.Object} thisArg\n * @chainable\n */\n setControlVisible: function(controlKey, visible) {\n if (!this._controlsVisibility) {\n this._controlsVisibility = {};\n }\n this._controlsVisibility[controlKey] = visible;\n return this;\n },\n\n /**\n * Sets the visibility state of object controls.\n * @param {Object} [options] Options object\n * @param {Boolean} [options.bl] true to enable the bottom-left control, false to disable it\n * @param {Boolean} [options.br] true to enable the bottom-right control, false to disable it\n * @param {Boolean} [options.mb] true to enable the middle-bottom control, false to disable it\n * @param {Boolean} [options.ml] true to enable the middle-left control, false to disable it\n * @param {Boolean} [options.mr] true to enable the middle-right control, false to disable it\n * @param {Boolean} [options.mt] true to enable the middle-top control, false to disable it\n * @param {Boolean} [options.tl] true to enable the top-left control, false to disable it\n * @param {Boolean} [options.tr] true to enable the top-right control, false to disable it\n * @param {Boolean} [options.mtr] true to enable the middle-top-rotate control, false to disable it\n * @return {fabric.Object} thisArg\n * @chainable\n */\n setControlsVisibility: function(options) {\n options || (options = { });\n\n for (var p in options) {\n this.setControlVisible(p, options[p]);\n }\n return this;\n },\n\n\n /**\n * This callback function is called every time _discardActiveObject or _setActiveObject\n * try to to deselect this object. If the function returns true, the process is cancelled\n * @param {Object} [options] options sent from the upper functions\n * @param {Event} [options.e] event if the process is generated by an event\n */\n onDeselect: function() {\n // implemented by sub-classes, as needed.\n },\n\n\n /**\n * This callback function is called every time _discardActiveObject or _setActiveObject\n * try to to select this object. If the function returns true, the process is cancelled\n * @param {Object} [options] options sent from the upper functions\n * @param {Event} [options.e] event if the process is generated by an event\n */\n onSelect: function() {\n // implemented by sub-classes, as needed.\n }\n });\n})();\n\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n /**\n * Animation duration (in ms) for fx* methods\n * @type Number\n * @default\n */\n FX_DURATION: 500,\n\n /**\n * Centers object horizontally with animation.\n * @param {fabric.Object} object Object to center\n * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n * @param {Function} [callbacks.onComplete] Invoked on completion\n * @param {Function} [callbacks.onChange] Invoked on every step of animation\n * @return {fabric.AnimationContext} context\n */\n fxCenterObjectH: function (object, callbacks) {\n callbacks = callbacks || { };\n\n var empty = function() { },\n onComplete = callbacks.onComplete || empty,\n onChange = callbacks.onChange || empty,\n _this = this;\n\n return fabric.util.animate({\n target: this,\n startValue: object.left,\n endValue: this.getCenterPoint().x,\n duration: this.FX_DURATION,\n onChange: function(value) {\n object.set('left', value);\n _this.requestRenderAll();\n onChange();\n },\n onComplete: function() {\n object.setCoords();\n onComplete();\n }\n });\n },\n\n /**\n * Centers object vertically with animation.\n * @param {fabric.Object} object Object to center\n * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n * @param {Function} [callbacks.onComplete] Invoked on completion\n * @param {Function} [callbacks.onChange] Invoked on every step of animation\n * @return {fabric.AnimationContext} context\n */\n fxCenterObjectV: function (object, callbacks) {\n callbacks = callbacks || { };\n\n var empty = function() { },\n onComplete = callbacks.onComplete || empty,\n onChange = callbacks.onChange || empty,\n _this = this;\n\n return fabric.util.animate({\n target: this,\n startValue: object.top,\n endValue: this.getCenterPoint().y,\n duration: this.FX_DURATION,\n onChange: function(value) {\n object.set('top', value);\n _this.requestRenderAll();\n onChange();\n },\n onComplete: function() {\n object.setCoords();\n onComplete();\n }\n });\n },\n\n /**\n * Same as `fabric.Canvas#remove` but animated\n * @param {fabric.Object} object Object to remove\n * @param {Object} [callbacks] Callbacks object with optional \"onComplete\" and/or \"onChange\" properties\n * @param {Function} [callbacks.onComplete] Invoked on completion\n * @param {Function} [callbacks.onChange] Invoked on every step of animation\n * @return {fabric.AnimationContext} context\n */\n fxRemove: function (object, callbacks) {\n callbacks = callbacks || { };\n\n var empty = function() { },\n onComplete = callbacks.onComplete || empty,\n onChange = callbacks.onChange || empty,\n _this = this;\n\n return fabric.util.animate({\n target: this,\n startValue: object.opacity,\n endValue: 0,\n duration: this.FX_DURATION,\n onChange: function(value) {\n object.set('opacity', value);\n _this.requestRenderAll();\n onChange();\n },\n onComplete: function () {\n _this.remove(object);\n onComplete();\n }\n });\n }\n});\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n /**\n * Animates object's properties\n * @param {String|Object} property Property to animate (if string) or properties to animate (if object)\n * @param {Number|Object} value Value to animate property to (if string was given first) or options object\n * @return {fabric.Object} thisArg\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#animation}\n * @return {fabric.AnimationContext | fabric.AnimationContext[]} animation context (or an array if passed multiple properties)\n *\n * As object — multiple properties\n *\n * object.animate({ left: ..., top: ... });\n * object.animate({ left: ..., top: ... }, { duration: ... });\n *\n * As string — one property\n *\n * object.animate('left', ...);\n * object.animate('left', { duration: ... });\n *\n */\n animate: function () {\n if (arguments[0] && typeof arguments[0] === 'object') {\n var propsToAnimate = [], prop, skipCallbacks, out = [];\n for (prop in arguments[0]) {\n propsToAnimate.push(prop);\n }\n for (var i = 0, len = propsToAnimate.length; i < len; i++) {\n prop = propsToAnimate[i];\n skipCallbacks = i !== len - 1;\n out.push(this._animate(prop, arguments[0][prop], arguments[1], skipCallbacks));\n }\n return out;\n }\n else {\n return this._animate.apply(this, arguments);\n }\n },\n\n /**\n * @private\n * @param {String} property Property to animate\n * @param {String} to Value to animate to\n * @param {Object} [options] Options object\n * @param {Boolean} [skipCallbacks] When true, callbacks like onchange and oncomplete are not invoked\n */\n _animate: function(property, to, options, skipCallbacks) {\n var _this = this, propPair;\n\n to = to.toString();\n\n if (!options) {\n options = { };\n }\n else {\n options = fabric.util.object.clone(options);\n }\n\n if (~property.indexOf('.')) {\n propPair = property.split('.');\n }\n\n var propIsColor =\n _this.colorProperties.indexOf(property) > -1 ||\n (propPair && _this.colorProperties.indexOf(propPair[1]) > -1);\n\n var currentValue = propPair\n ? this.get(propPair[0])[propPair[1]]\n : this.get(property);\n\n if (!('from' in options)) {\n options.from = currentValue;\n }\n\n if (!propIsColor) {\n if (~to.indexOf('=')) {\n to = currentValue + parseFloat(to.replace('=', ''));\n }\n else {\n to = parseFloat(to);\n }\n }\n\n var _options = {\n target: this,\n startValue: options.from,\n endValue: to,\n byValue: options.by,\n easing: options.easing,\n duration: options.duration,\n abort: options.abort && function(value, valueProgress, timeProgress) {\n return options.abort.call(_this, value, valueProgress, timeProgress);\n },\n onChange: function (value, valueProgress, timeProgress) {\n if (propPair) {\n _this[propPair[0]][propPair[1]] = value;\n }\n else {\n _this.set(property, value);\n }\n if (skipCallbacks) {\n return;\n }\n options.onChange && options.onChange(value, valueProgress, timeProgress);\n },\n onComplete: function (value, valueProgress, timeProgress) {\n if (skipCallbacks) {\n return;\n }\n\n _this.setCoords();\n options.onComplete && options.onComplete(value, valueProgress, timeProgress);\n }\n };\n\n if (propIsColor) {\n return fabric.util.animateColor(_options.startValue, _options.endValue, _options.duration, _options);\n }\n else {\n return fabric.util.animate(_options);\n }\n }\n});\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend,\n clone = fabric.util.object.clone,\n coordProps = { x1: 1, x2: 1, y1: 1, y2: 1 };\n\n if (fabric.Line) {\n fabric.warn('fabric.Line is already defined');\n return;\n }\n\n /**\n * Line class\n * @class fabric.Line\n * @extends fabric.Object\n * @see {@link fabric.Line#initialize} for constructor definition\n */\n fabric.Line = fabric.util.createClass(fabric.Object, /** @lends fabric.Line.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'line',\n\n /**\n * x value or first line edge\n * @type Number\n * @default\n */\n x1: 0,\n\n /**\n * y value or first line edge\n * @type Number\n * @default\n */\n y1: 0,\n\n /**\n * x value or second line edge\n * @type Number\n * @default\n */\n x2: 0,\n\n /**\n * y value or second line edge\n * @type Number\n * @default\n */\n y2: 0,\n\n cacheProperties: fabric.Object.prototype.cacheProperties.concat('x1', 'x2', 'y1', 'y2'),\n\n /**\n * Constructor\n * @param {Array} [points] Array of points\n * @param {Object} [options] Options object\n * @return {fabric.Line} thisArg\n */\n initialize: function(points, options) {\n if (!points) {\n points = [0, 0, 0, 0];\n }\n\n this.callSuper('initialize', options);\n\n this.set('x1', points[0]);\n this.set('y1', points[1]);\n this.set('x2', points[2]);\n this.set('y2', points[3]);\n\n this._setWidthHeight(options);\n },\n\n /**\n * @private\n * @param {Object} [options] Options\n */\n _setWidthHeight: function(options) {\n options || (options = { });\n\n this.width = Math.abs(this.x2 - this.x1);\n this.height = Math.abs(this.y2 - this.y1);\n\n this.left = 'left' in options\n ? options.left\n : this._getLeftToOriginX();\n\n this.top = 'top' in options\n ? options.top\n : this._getTopToOriginY();\n },\n\n /**\n * @private\n * @param {String} key\n * @param {*} value\n */\n _set: function(key, value) {\n this.callSuper('_set', key, value);\n if (typeof coordProps[key] !== 'undefined') {\n this._setWidthHeight();\n }\n return this;\n },\n\n /**\n * @private\n * @return {Number} leftToOriginX Distance from left edge of canvas to originX of Line.\n */\n _getLeftToOriginX: makeEdgeToOriginGetter(\n { // property names\n origin: 'originX',\n axis1: 'x1',\n axis2: 'x2',\n dimension: 'width'\n },\n { // possible values of origin\n nearest: 'left',\n center: 'center',\n farthest: 'right'\n }\n ),\n\n /**\n * @private\n * @return {Number} topToOriginY Distance from top edge of canvas to originY of Line.\n */\n _getTopToOriginY: makeEdgeToOriginGetter(\n { // property names\n origin: 'originY',\n axis1: 'y1',\n axis2: 'y2',\n dimension: 'height'\n },\n { // possible values of origin\n nearest: 'top',\n center: 'center',\n farthest: 'bottom'\n }\n ),\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n ctx.beginPath();\n\n\n var p = this.calcLinePoints();\n ctx.moveTo(p.x1, p.y1);\n ctx.lineTo(p.x2, p.y2);\n\n ctx.lineWidth = this.strokeWidth;\n\n // TODO: test this\n // make sure setting \"fill\" changes color of a line\n // (by copying fillStyle to strokeStyle, since line is stroked, not filled)\n var origStrokeStyle = ctx.strokeStyle;\n ctx.strokeStyle = this.stroke || ctx.fillStyle;\n this.stroke && this._renderStroke(ctx);\n ctx.strokeStyle = origStrokeStyle;\n },\n\n /**\n * This function is an helper for svg import. it returns the center of the object in the svg\n * untransformed coordinates\n * @private\n * @return {Object} center point from element coordinates\n */\n _findCenterFromElement: function() {\n return {\n x: (this.x1 + this.x2) / 2,\n y: (this.y1 + this.y2) / 2,\n };\n },\n\n /**\n * Returns object representation of an instance\n * @method toObject\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n return extend(this.callSuper('toObject', propertiesToInclude), this.calcLinePoints());\n },\n\n /*\n * Calculate object dimensions from its properties\n * @private\n */\n _getNonTransformedDimensions: function() {\n var dim = this.callSuper('_getNonTransformedDimensions');\n if (this.strokeLineCap === 'butt') {\n if (this.width === 0) {\n dim.y -= this.strokeWidth;\n }\n if (this.height === 0) {\n dim.x -= this.strokeWidth;\n }\n }\n return dim;\n },\n\n /**\n * Recalculates line points given width and height\n * @private\n */\n calcLinePoints: function() {\n var xMult = this.x1 <= this.x2 ? -1 : 1,\n yMult = this.y1 <= this.y2 ? -1 : 1,\n x1 = (xMult * this.width * 0.5),\n y1 = (yMult * this.height * 0.5),\n x2 = (xMult * this.width * -0.5),\n y2 = (yMult * this.height * -0.5);\n\n return {\n x1: x1,\n x2: x2,\n y1: y1,\n y2: y2\n };\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n var p = this.calcLinePoints();\n return [\n '\\n'\n ];\n },\n /* _TO_SVG_END_ */\n });\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by {@link fabric.Line.fromElement})\n * @static\n * @memberOf fabric.Line\n * @see http://www.w3.org/TR/SVG/shapes.html#LineElement\n */\n fabric.Line.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x1 y1 x2 y2'.split(' '));\n\n /**\n * Returns fabric.Line instance from an SVG element\n * @static\n * @memberOf fabric.Line\n * @param {SVGElement} element Element to parse\n * @param {Object} [options] Options object\n * @param {Function} [callback] callback function invoked after parsing\n */\n fabric.Line.fromElement = function(element, callback, options) {\n options = options || { };\n var parsedAttributes = fabric.parseAttributes(element, fabric.Line.ATTRIBUTE_NAMES),\n points = [\n parsedAttributes.x1 || 0,\n parsedAttributes.y1 || 0,\n parsedAttributes.x2 || 0,\n parsedAttributes.y2 || 0\n ];\n callback(new fabric.Line(points, extend(parsedAttributes, options)));\n };\n /* _FROM_SVG_END_ */\n\n /**\n * Returns fabric.Line instance from an object representation\n * @static\n * @memberOf fabric.Line\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] invoked with new instance as first argument\n */\n fabric.Line.fromObject = function(object, callback) {\n function _callback(instance) {\n delete instance.points;\n callback && callback(instance);\n };\n var options = clone(object, true);\n options.points = [object.x1, object.y1, object.x2, object.y2];\n fabric.Object._fromObject('Line', options, _callback, 'points');\n };\n\n /**\n * Produces a function that calculates distance from canvas edge to Line origin.\n */\n function makeEdgeToOriginGetter(propertyNames, originValues) {\n var origin = propertyNames.origin,\n axis1 = propertyNames.axis1,\n axis2 = propertyNames.axis2,\n dimension = propertyNames.dimension,\n nearest = originValues.nearest,\n center = originValues.center,\n farthest = originValues.farthest;\n\n return function() {\n switch (this.get(origin)) {\n case nearest:\n return Math.min(this.get(axis1), this.get(axis2));\n case center:\n return Math.min(this.get(axis1), this.get(axis2)) + (0.5 * this.get(dimension));\n case farthest:\n return Math.max(this.get(axis1), this.get(axis2));\n }\n };\n\n }\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n degreesToRadians = fabric.util.degreesToRadians;\n\n if (fabric.Circle) {\n fabric.warn('fabric.Circle is already defined.');\n return;\n }\n\n /**\n * Circle class\n * @class fabric.Circle\n * @extends fabric.Object\n * @see {@link fabric.Circle#initialize} for constructor definition\n */\n fabric.Circle = fabric.util.createClass(fabric.Object, /** @lends fabric.Circle.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'circle',\n\n /**\n * Radius of this circle\n * @type Number\n * @default\n */\n radius: 0,\n\n /**\n * degrees of start of the circle.\n * probably will change to degrees in next major version\n * @type Number 0 - 359\n * @default 0\n */\n startAngle: 0,\n\n /**\n * End angle of the circle\n * probably will change to degrees in next major version\n * @type Number 1 - 360\n * @default 360\n */\n endAngle: 360,\n\n cacheProperties: fabric.Object.prototype.cacheProperties.concat('radius', 'startAngle', 'endAngle'),\n\n /**\n * @private\n * @param {String} key\n * @param {*} value\n * @return {fabric.Circle} thisArg\n */\n _set: function(key, value) {\n this.callSuper('_set', key, value);\n\n if (key === 'radius') {\n this.setRadius(value);\n }\n\n return this;\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n return this.callSuper('toObject', ['radius', 'startAngle', 'endAngle'].concat(propertiesToInclude));\n },\n\n /* _TO_SVG_START_ */\n\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n var svgString, x = 0, y = 0,\n angle = (this.endAngle - this.startAngle) % 360;\n\n if (angle === 0) {\n svgString = [\n '\\n'\n ];\n }\n else {\n var start = degreesToRadians(this.startAngle),\n end = degreesToRadians(this.endAngle),\n radius = this.radius,\n startX = fabric.util.cos(start) * radius,\n startY = fabric.util.sin(start) * radius,\n endX = fabric.util.cos(end) * radius,\n endY = fabric.util.sin(end) * radius,\n largeFlag = angle > 180 ? '1' : '0';\n svgString = [\n '\\n'\n ];\n }\n return svgString;\n },\n /* _TO_SVG_END_ */\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx context to render on\n */\n _render: function(ctx) {\n ctx.beginPath();\n ctx.arc(\n 0,\n 0,\n this.radius,\n degreesToRadians(this.startAngle),\n degreesToRadians(this.endAngle),\n false\n );\n this._renderPaintInOrder(ctx);\n },\n\n /**\n * Returns horizontal radius of an object (according to how an object is scaled)\n * @return {Number}\n */\n getRadiusX: function() {\n return this.get('radius') * this.get('scaleX');\n },\n\n /**\n * Returns vertical radius of an object (according to how an object is scaled)\n * @return {Number}\n */\n getRadiusY: function() {\n return this.get('radius') * this.get('scaleY');\n },\n\n /**\n * Sets radius of an object (and updates width accordingly)\n * @return {fabric.Circle} thisArg\n */\n setRadius: function(value) {\n this.radius = value;\n return this.set('width', value * 2).set('height', value * 2);\n },\n });\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by {@link fabric.Circle.fromElement})\n * @static\n * @memberOf fabric.Circle\n * @see: http://www.w3.org/TR/SVG/shapes.html#CircleElement\n */\n fabric.Circle.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy r'.split(' '));\n\n /**\n * Returns {@link fabric.Circle} instance from an SVG element\n * @static\n * @memberOf fabric.Circle\n * @param {SVGElement} element Element to parse\n * @param {Function} [callback] Options callback invoked after parsing is finished\n * @param {Object} [options] Options object\n * @throws {Error} If value of `r` attribute is missing or invalid\n */\n fabric.Circle.fromElement = function(element, callback) {\n var parsedAttributes = fabric.parseAttributes(element, fabric.Circle.ATTRIBUTE_NAMES);\n\n if (!isValidRadius(parsedAttributes)) {\n throw new Error('value of `r` attribute is required and can not be negative');\n }\n\n parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.radius;\n parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.radius;\n callback(new fabric.Circle(parsedAttributes));\n };\n\n /**\n * @private\n */\n function isValidRadius(attributes) {\n return (('radius' in attributes) && (attributes.radius >= 0));\n }\n /* _FROM_SVG_END_ */\n\n /**\n * Returns {@link fabric.Circle} instance from an object representation\n * @static\n * @memberOf fabric.Circle\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] invoked with new instance as first argument\n * @return {void}\n */\n fabric.Circle.fromObject = function(object, callback) {\n fabric.Object._fromObject('Circle', object, callback);\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { });\n\n if (fabric.Triangle) {\n fabric.warn('fabric.Triangle is already defined');\n return;\n }\n\n /**\n * Triangle class\n * @class fabric.Triangle\n * @extends fabric.Object\n * @return {fabric.Triangle} thisArg\n * @see {@link fabric.Triangle#initialize} for constructor definition\n */\n fabric.Triangle = fabric.util.createClass(fabric.Object, /** @lends fabric.Triangle.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'triangle',\n\n /**\n * Width is set to 100 to compensate the old initialize code that was setting it to 100\n * @type Number\n * @default\n */\n width: 100,\n\n /**\n * Height is set to 100 to compensate the old initialize code that was setting it to 100\n * @type Number\n * @default\n */\n height: 100,\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n var widthBy2 = this.width / 2,\n heightBy2 = this.height / 2;\n\n ctx.beginPath();\n ctx.moveTo(-widthBy2, heightBy2);\n ctx.lineTo(0, -heightBy2);\n ctx.lineTo(widthBy2, heightBy2);\n ctx.closePath();\n\n this._renderPaintInOrder(ctx);\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n var widthBy2 = this.width / 2,\n heightBy2 = this.height / 2,\n points = [\n -widthBy2 + ' ' + heightBy2,\n '0 ' + -heightBy2,\n widthBy2 + ' ' + heightBy2\n ].join(',');\n return [\n ''\n ];\n },\n /* _TO_SVG_END_ */\n });\n\n /**\n * Returns {@link fabric.Triangle} instance from an object representation\n * @static\n * @memberOf fabric.Triangle\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] invoked with new instance as first argument\n */\n fabric.Triangle.fromObject = function(object, callback) {\n return fabric.Object._fromObject('Triangle', object, callback);\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n piBy2 = Math.PI * 2;\n\n if (fabric.Ellipse) {\n fabric.warn('fabric.Ellipse is already defined.');\n return;\n }\n\n /**\n * Ellipse class\n * @class fabric.Ellipse\n * @extends fabric.Object\n * @return {fabric.Ellipse} thisArg\n * @see {@link fabric.Ellipse#initialize} for constructor definition\n */\n fabric.Ellipse = fabric.util.createClass(fabric.Object, /** @lends fabric.Ellipse.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'ellipse',\n\n /**\n * Horizontal radius\n * @type Number\n * @default\n */\n rx: 0,\n\n /**\n * Vertical radius\n * @type Number\n * @default\n */\n ry: 0,\n\n cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'),\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n * @return {fabric.Ellipse} thisArg\n */\n initialize: function(options) {\n this.callSuper('initialize', options);\n this.set('rx', options && options.rx || 0);\n this.set('ry', options && options.ry || 0);\n },\n\n /**\n * @private\n * @param {String} key\n * @param {*} value\n * @return {fabric.Ellipse} thisArg\n */\n _set: function(key, value) {\n this.callSuper('_set', key, value);\n switch (key) {\n\n case 'rx':\n this.rx = value;\n this.set('width', value * 2);\n break;\n\n case 'ry':\n this.ry = value;\n this.set('height', value * 2);\n break;\n\n }\n return this;\n },\n\n /**\n * Returns horizontal radius of an object (according to how an object is scaled)\n * @return {Number}\n */\n getRx: function() {\n return this.get('rx') * this.get('scaleX');\n },\n\n /**\n * Returns Vertical radius of an object (according to how an object is scaled)\n * @return {Number}\n */\n getRy: function() {\n return this.get('ry') * this.get('scaleY');\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n return [\n '\\n'\n ];\n },\n /* _TO_SVG_END_ */\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx context to render on\n */\n _render: function(ctx) {\n ctx.beginPath();\n ctx.save();\n ctx.transform(1, 0, 0, this.ry / this.rx, 0, 0);\n ctx.arc(\n 0,\n 0,\n this.rx,\n 0,\n piBy2,\n false);\n ctx.restore();\n this._renderPaintInOrder(ctx);\n },\n });\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by {@link fabric.Ellipse.fromElement})\n * @static\n * @memberOf fabric.Ellipse\n * @see http://www.w3.org/TR/SVG/shapes.html#EllipseElement\n */\n fabric.Ellipse.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('cx cy rx ry'.split(' '));\n\n /**\n * Returns {@link fabric.Ellipse} instance from an SVG element\n * @static\n * @memberOf fabric.Ellipse\n * @param {SVGElement} element Element to parse\n * @param {Function} [callback] Options callback invoked after parsing is finished\n * @return {fabric.Ellipse}\n */\n fabric.Ellipse.fromElement = function(element, callback) {\n\n var parsedAttributes = fabric.parseAttributes(element, fabric.Ellipse.ATTRIBUTE_NAMES);\n\n parsedAttributes.left = (parsedAttributes.left || 0) - parsedAttributes.rx;\n parsedAttributes.top = (parsedAttributes.top || 0) - parsedAttributes.ry;\n callback(new fabric.Ellipse(parsedAttributes));\n };\n /* _FROM_SVG_END_ */\n\n /**\n * Returns {@link fabric.Ellipse} instance from an object representation\n * @static\n * @memberOf fabric.Ellipse\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] invoked with new instance as first argument\n * @return {void}\n */\n fabric.Ellipse.fromObject = function(object, callback) {\n fabric.Object._fromObject('Ellipse', object, callback);\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend;\n\n if (fabric.Rect) {\n fabric.warn('fabric.Rect is already defined');\n return;\n }\n\n /**\n * Rectangle class\n * @class fabric.Rect\n * @extends fabric.Object\n * @return {fabric.Rect} thisArg\n * @see {@link fabric.Rect#initialize} for constructor definition\n */\n fabric.Rect = fabric.util.createClass(fabric.Object, /** @lends fabric.Rect.prototype */ {\n\n /**\n * List of properties to consider when checking if state of an object is changed ({@link fabric.Object#hasStateChanged})\n * as well as for history (undo/redo) purposes\n * @type Array\n */\n stateProperties: fabric.Object.prototype.stateProperties.concat('rx', 'ry'),\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'rect',\n\n /**\n * Horizontal border radius\n * @type Number\n * @default\n */\n rx: 0,\n\n /**\n * Vertical border radius\n * @type Number\n * @default\n */\n ry: 0,\n\n cacheProperties: fabric.Object.prototype.cacheProperties.concat('rx', 'ry'),\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n * @return {Object} thisArg\n */\n initialize: function(options) {\n this.callSuper('initialize', options);\n this._initRxRy();\n },\n\n /**\n * Initializes rx/ry attributes\n * @private\n */\n _initRxRy: function() {\n if (this.rx && !this.ry) {\n this.ry = this.rx;\n }\n else if (this.ry && !this.rx) {\n this.rx = this.ry;\n }\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n\n // 1x1 case (used in spray brush) optimization was removed because\n // with caching and higher zoom level this makes more damage than help\n\n var rx = this.rx ? Math.min(this.rx, this.width / 2) : 0,\n ry = this.ry ? Math.min(this.ry, this.height / 2) : 0,\n w = this.width,\n h = this.height,\n x = -this.width / 2,\n y = -this.height / 2,\n isRounded = rx !== 0 || ry !== 0,\n /* \"magic number\" for bezier approximations of arcs (http://itc.ktu.lt/itc354/Riskus354.pdf) */\n k = 1 - 0.5522847498;\n ctx.beginPath();\n\n ctx.moveTo(x + rx, y);\n\n ctx.lineTo(x + w - rx, y);\n isRounded && ctx.bezierCurveTo(x + w - k * rx, y, x + w, y + k * ry, x + w, y + ry);\n\n ctx.lineTo(x + w, y + h - ry);\n isRounded && ctx.bezierCurveTo(x + w, y + h - k * ry, x + w - k * rx, y + h, x + w - rx, y + h);\n\n ctx.lineTo(x + rx, y + h);\n isRounded && ctx.bezierCurveTo(x + k * rx, y + h, x, y + h - k * ry, x, y + h - ry);\n\n ctx.lineTo(x, y + ry);\n isRounded && ctx.bezierCurveTo(x, y + k * ry, x + k * rx, y, x + rx, y);\n\n ctx.closePath();\n\n this._renderPaintInOrder(ctx);\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n return this.callSuper('toObject', ['rx', 'ry'].concat(propertiesToInclude));\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n var x = -this.width / 2, y = -this.height / 2;\n return [\n '\\n'\n ];\n },\n /* _TO_SVG_END_ */\n });\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by `fabric.Rect.fromElement`)\n * @static\n * @memberOf fabric.Rect\n * @see: http://www.w3.org/TR/SVG/shapes.html#RectElement\n */\n fabric.Rect.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat('x y rx ry width height'.split(' '));\n\n /**\n * Returns {@link fabric.Rect} instance from an SVG element\n * @static\n * @memberOf fabric.Rect\n * @param {SVGElement} element Element to parse\n * @param {Function} callback callback function invoked after parsing\n * @param {Object} [options] Options object\n */\n fabric.Rect.fromElement = function(element, callback, options) {\n if (!element) {\n return callback(null);\n }\n options = options || { };\n\n var parsedAttributes = fabric.parseAttributes(element, fabric.Rect.ATTRIBUTE_NAMES);\n parsedAttributes.left = parsedAttributes.left || 0;\n parsedAttributes.top = parsedAttributes.top || 0;\n parsedAttributes.height = parsedAttributes.height || 0;\n parsedAttributes.width = parsedAttributes.width || 0;\n var rect = new fabric.Rect(extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n rect.visible = rect.visible && rect.width > 0 && rect.height > 0;\n callback(rect);\n };\n /* _FROM_SVG_END_ */\n\n /**\n * Returns {@link fabric.Rect} instance from an object representation\n * @static\n * @memberOf fabric.Rect\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] Callback to invoke when an fabric.Rect instance is created\n */\n fabric.Rect.fromObject = function(object, callback) {\n return fabric.Object._fromObject('Rect', object, callback);\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend,\n min = fabric.util.array.min,\n max = fabric.util.array.max,\n toFixed = fabric.util.toFixed,\n projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;\n\n if (fabric.Polyline) {\n fabric.warn('fabric.Polyline is already defined');\n return;\n }\n\n /**\n * Polyline class\n * @class fabric.Polyline\n * @extends fabric.Object\n * @see {@link fabric.Polyline#initialize} for constructor definition\n */\n fabric.Polyline = fabric.util.createClass(fabric.Object, /** @lends fabric.Polyline.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'polyline',\n\n /**\n * Points array\n * @type Array\n * @default\n */\n points: null,\n\n /**\n * WARNING: Feature in progress\n * Calculate the exact bounding box taking in account strokeWidth on acute angles\n * this will be turned to true by default on fabric 6.0\n * maybe will be left in as an optimization since calculations may be slow\n * @deprecated\n * @type Boolean\n * @default false\n */\n exactBoundingBox: false,\n\n cacheProperties: fabric.Object.prototype.cacheProperties.concat('points'),\n\n /**\n * Constructor\n * @param {Array} points Array of points (where each point is an object with x and y)\n * @param {Object} [options] Options object\n * @return {fabric.Polyline} thisArg\n * @example\n * var poly = new fabric.Polyline([\n * { x: 10, y: 10 },\n * { x: 50, y: 30 },\n * { x: 40, y: 70 },\n * { x: 60, y: 50 },\n * { x: 100, y: 150 },\n * { x: 40, y: 100 }\n * ], {\n * stroke: 'red',\n * left: 100,\n * top: 100\n * });\n */\n initialize: function(points, options) {\n options = options || {};\n this.points = points || [];\n this.callSuper('initialize', options);\n this._setPositionDimensions(options);\n },\n\n /**\n * @private\n */\n _projectStrokeOnPoints: function () {\n return projectStrokeOnPoints(this.points, this, true);\n },\n\n _setPositionDimensions: function(options) {\n var calcDim = this._calcDimensions(options), correctLeftTop,\n correctSize = this.exactBoundingBox ? this.strokeWidth : 0;\n this.width = calcDim.width - correctSize;\n this.height = calcDim.height - correctSize;\n if (!options.fromSVG) {\n correctLeftTop = this.translateToGivenOrigin(\n {\n // this looks bad, but is one way to keep it optional for now.\n x: calcDim.left - this.strokeWidth / 2 + correctSize / 2,\n y: calcDim.top - this.strokeWidth / 2 + correctSize / 2\n },\n 'left',\n 'top',\n this.originX,\n this.originY\n );\n }\n if (typeof options.left === 'undefined') {\n this.left = options.fromSVG ? calcDim.left : correctLeftTop.x;\n }\n if (typeof options.top === 'undefined') {\n this.top = options.fromSVG ? calcDim.top : correctLeftTop.y;\n }\n this.pathOffset = {\n x: calcDim.left + this.width / 2 + correctSize / 2,\n y: calcDim.top + this.height / 2 + correctSize / 2\n };\n },\n\n /**\n * Calculate the polygon min and max point from points array,\n * returning an object with left, top, width, height to measure the\n * polygon size\n * @return {Object} object.left X coordinate of the polygon leftmost point\n * @return {Object} object.top Y coordinate of the polygon topmost point\n * @return {Object} object.width distance between X coordinates of the polygon leftmost and rightmost point\n * @return {Object} object.height distance between Y coordinates of the polygon topmost and bottommost point\n * @private\n */\n _calcDimensions: function() {\n\n var points = this.exactBoundingBox ? this._projectStrokeOnPoints() : this.points,\n minX = min(points, 'x') || 0,\n minY = min(points, 'y') || 0,\n maxX = max(points, 'x') || 0,\n maxY = max(points, 'y') || 0,\n width = (maxX - minX),\n height = (maxY - minY);\n\n return {\n left: minX,\n top: minY,\n width: width,\n height: height,\n };\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} Object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n return extend(this.callSuper('toObject', propertiesToInclude), {\n points: this.points.concat()\n });\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n var points = [], diffX = this.pathOffset.x, diffY = this.pathOffset.y,\n NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n\n for (var i = 0, len = this.points.length; i < len; i++) {\n points.push(\n toFixed(this.points[i].x - diffX, NUM_FRACTION_DIGITS), ',',\n toFixed(this.points[i].y - diffY, NUM_FRACTION_DIGITS), ' '\n );\n }\n return [\n '<' + this.type + ' ', 'COMMON_PARTS',\n 'points=\"', points.join(''),\n '\" />\\n'\n ];\n },\n /* _TO_SVG_END_ */\n\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n commonRender: function(ctx) {\n var point, len = this.points.length,\n x = this.pathOffset.x,\n y = this.pathOffset.y;\n\n if (!len || isNaN(this.points[len - 1].y)) {\n // do not draw if no points or odd points\n // NaN comes from parseFloat of a empty string in parser\n return false;\n }\n ctx.beginPath();\n ctx.moveTo(this.points[0].x - x, this.points[0].y - y);\n for (var i = 0; i < len; i++) {\n point = this.points[i];\n ctx.lineTo(point.x - x, point.y - y);\n }\n return true;\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n if (!this.commonRender(ctx)) {\n return;\n }\n this._renderPaintInOrder(ctx);\n },\n\n /**\n * Returns complexity of an instance\n * @return {Number} complexity of this instance\n */\n complexity: function() {\n return this.get('points').length;\n }\n });\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by {@link fabric.Polyline.fromElement})\n * @static\n * @memberOf fabric.Polyline\n * @see: http://www.w3.org/TR/SVG/shapes.html#PolylineElement\n */\n fabric.Polyline.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n /**\n * Returns fabric.Polyline instance from an SVG element\n * @static\n * @memberOf fabric.Polyline\n * @param {SVGElement} element Element to parser\n * @param {Function} callback callback function invoked after parsing\n * @param {Object} [options] Options object\n */\n fabric.Polyline.fromElementGenerator = function(_class) {\n return function(element, callback, options) {\n if (!element) {\n return callback(null);\n }\n options || (options = { });\n\n var points = fabric.parsePointsAttribute(element.getAttribute('points')),\n parsedAttributes = fabric.parseAttributes(element, fabric[_class].ATTRIBUTE_NAMES);\n parsedAttributes.fromSVG = true;\n callback(new fabric[_class](points, extend(parsedAttributes, options)));\n };\n };\n\n fabric.Polyline.fromElement = fabric.Polyline.fromElementGenerator('Polyline');\n\n /* _FROM_SVG_END_ */\n\n /**\n * Returns fabric.Polyline instance from an object representation\n * @static\n * @memberOf fabric.Polyline\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n */\n fabric.Polyline.fromObject = function(object, callback) {\n return fabric.Object._fromObject('Polyline', object, callback, 'points');\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = {}),\n projectStrokeOnPoints = fabric.util.projectStrokeOnPoints;\n\n if (fabric.Polygon) {\n fabric.warn('fabric.Polygon is already defined');\n return;\n }\n\n /**\n * Polygon class\n * @class fabric.Polygon\n * @extends fabric.Polyline\n * @see {@link fabric.Polygon#initialize} for constructor definition\n */\n fabric.Polygon = fabric.util.createClass(fabric.Polyline, /** @lends fabric.Polygon.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'polygon',\n\n /**\n * @private\n */\n _projectStrokeOnPoints: function () {\n return projectStrokeOnPoints(this.points, this);\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n if (!this.commonRender(ctx)) {\n return;\n }\n ctx.closePath();\n this._renderPaintInOrder(ctx);\n },\n\n });\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by `fabric.Polygon.fromElement`)\n * @static\n * @memberOf fabric.Polygon\n * @see: http://www.w3.org/TR/SVG/shapes.html#PolygonElement\n */\n fabric.Polygon.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat();\n\n /**\n * Returns {@link fabric.Polygon} instance from an SVG element\n * @static\n * @memberOf fabric.Polygon\n * @param {SVGElement} element Element to parse\n * @param {Function} callback callback function invoked after parsing\n * @param {Object} [options] Options object\n */\n fabric.Polygon.fromElement = fabric.Polyline.fromElementGenerator('Polygon');\n /* _FROM_SVG_END_ */\n\n /**\n * Returns fabric.Polygon instance from an object representation\n * @static\n * @memberOf fabric.Polygon\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n * @return {void}\n */\n fabric.Polygon.fromObject = function(object, callback) {\n fabric.Object._fromObject('Polygon', object, callback, 'points');\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n min = fabric.util.array.min,\n max = fabric.util.array.max,\n extend = fabric.util.object.extend,\n clone = fabric.util.object.clone,\n toFixed = fabric.util.toFixed;\n\n if (fabric.Path) {\n fabric.warn('fabric.Path is already defined');\n return;\n }\n\n /**\n * Path class\n * @class fabric.Path\n * @extends fabric.Object\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#path_and_pathgroup}\n * @see {@link fabric.Path#initialize} for constructor definition\n */\n fabric.Path = fabric.util.createClass(fabric.Object, /** @lends fabric.Path.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'path',\n\n /**\n * Array of path points\n * @type Array\n * @default\n */\n path: null,\n\n cacheProperties: fabric.Object.prototype.cacheProperties.concat('path', 'fillRule'),\n\n stateProperties: fabric.Object.prototype.stateProperties.concat('path'),\n\n /**\n * Constructor\n * @param {Array|String} path Path data (sequence of coordinates and corresponding \"command\" tokens)\n * @param {Object} [options] Options object\n * @return {fabric.Path} thisArg\n */\n initialize: function (path, options) {\n options = clone(options || {});\n delete options.path;\n this.callSuper('initialize', options);\n this._setPath(path || [], options);\n },\n\n /**\n * @private\n * @param {Array|String} path Path data (sequence of coordinates and corresponding \"command\" tokens)\n * @param {Object} [options] Options object\n */\n _setPath: function (path, options) {\n this.path = fabric.util.makePathSimpler(\n Array.isArray(path) ? path : fabric.util.parsePath(path)\n );\n\n fabric.Polyline.prototype._setPositionDimensions.call(this, options || {});\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx context to render path on\n */\n _renderPathCommands: function(ctx) {\n var current, // current instruction\n subpathStartX = 0,\n subpathStartY = 0,\n x = 0, // current x\n y = 0, // current y\n controlX = 0, // current control point x\n controlY = 0, // current control point y\n l = -this.pathOffset.x,\n t = -this.pathOffset.y;\n\n ctx.beginPath();\n\n for (var i = 0, len = this.path.length; i < len; ++i) {\n\n current = this.path[i];\n\n switch (current[0]) { // first letter\n\n case 'L': // lineto, absolute\n x = current[1];\n y = current[2];\n ctx.lineTo(x + l, y + t);\n break;\n\n case 'M': // moveTo, absolute\n x = current[1];\n y = current[2];\n subpathStartX = x;\n subpathStartY = y;\n ctx.moveTo(x + l, y + t);\n break;\n\n case 'C': // bezierCurveTo, absolute\n x = current[5];\n y = current[6];\n controlX = current[3];\n controlY = current[4];\n ctx.bezierCurveTo(\n current[1] + l,\n current[2] + t,\n controlX + l,\n controlY + t,\n x + l,\n y + t\n );\n break;\n\n case 'Q': // quadraticCurveTo, absolute\n ctx.quadraticCurveTo(\n current[1] + l,\n current[2] + t,\n current[3] + l,\n current[4] + t\n );\n x = current[3];\n y = current[4];\n controlX = current[1];\n controlY = current[2];\n break;\n\n case 'z':\n case 'Z':\n x = subpathStartX;\n y = subpathStartY;\n ctx.closePath();\n break;\n }\n }\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx context to render path on\n */\n _render: function(ctx) {\n this._renderPathCommands(ctx);\n this._renderPaintInOrder(ctx);\n },\n\n /**\n * Returns string representation of an instance\n * @return {String} string representation of an instance\n */\n toString: function() {\n return '#';\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n return extend(this.callSuper('toObject', propertiesToInclude), {\n path: this.path.map(function(item) { return item.slice(); }),\n });\n },\n\n /**\n * Returns dataless object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toDatalessObject: function(propertiesToInclude) {\n var o = this.toObject(['sourcePath'].concat(propertiesToInclude));\n if (o.sourcePath) {\n delete o.path;\n }\n return o;\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n var path = fabric.util.joinPath(this.path);\n return [\n '\\n'\n ];\n },\n\n _getOffsetTransform: function() {\n var digits = fabric.Object.NUM_FRACTION_DIGITS;\n return ' translate(' + toFixed(-this.pathOffset.x, digits) + ', ' +\n toFixed(-this.pathOffset.y, digits) + ')';\n },\n\n /**\n * Returns svg clipPath representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n toClipPathSVG: function(reviver) {\n var additionalTransform = this._getOffsetTransform();\n return '\\t' + this._createBaseClipPathSVGMarkup(\n this._toSVG(), { reviver: reviver, additionalTransform: additionalTransform }\n );\n },\n\n /**\n * Returns svg representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n toSVG: function(reviver) {\n var additionalTransform = this._getOffsetTransform();\n return this._createBaseSVGMarkup(this._toSVG(), { reviver: reviver, additionalTransform: additionalTransform });\n },\n /* _TO_SVG_END_ */\n\n /**\n * Returns number representation of an instance complexity\n * @return {Number} complexity of this instance\n */\n complexity: function() {\n return this.path.length;\n },\n\n /**\n * @private\n */\n _calcDimensions: function() {\n\n var aX = [],\n aY = [],\n current, // current instruction\n subpathStartX = 0,\n subpathStartY = 0,\n x = 0, // current x\n y = 0, // current y\n bounds;\n\n for (var i = 0, len = this.path.length; i < len; ++i) {\n\n current = this.path[i];\n\n switch (current[0]) { // first letter\n\n case 'L': // lineto, absolute\n x = current[1];\n y = current[2];\n bounds = [];\n break;\n\n case 'M': // moveTo, absolute\n x = current[1];\n y = current[2];\n subpathStartX = x;\n subpathStartY = y;\n bounds = [];\n break;\n\n case 'C': // bezierCurveTo, absolute\n bounds = fabric.util.getBoundsOfCurve(x, y,\n current[1],\n current[2],\n current[3],\n current[4],\n current[5],\n current[6]\n );\n x = current[5];\n y = current[6];\n break;\n\n case 'Q': // quadraticCurveTo, absolute\n bounds = fabric.util.getBoundsOfCurve(x, y,\n current[1],\n current[2],\n current[1],\n current[2],\n current[3],\n current[4]\n );\n x = current[3];\n y = current[4];\n break;\n\n case 'z':\n case 'Z':\n x = subpathStartX;\n y = subpathStartY;\n break;\n }\n bounds.forEach(function (point) {\n aX.push(point.x);\n aY.push(point.y);\n });\n aX.push(x);\n aY.push(y);\n }\n\n var minX = min(aX) || 0,\n minY = min(aY) || 0,\n maxX = max(aX) || 0,\n maxY = max(aY) || 0,\n deltaX = maxX - minX,\n deltaY = maxY - minY;\n\n return {\n left: minX,\n top: minY,\n width: deltaX,\n height: deltaY\n };\n }\n });\n\n /**\n * Creates an instance of fabric.Path from an object\n * @static\n * @memberOf fabric.Path\n * @param {Object} object\n * @param {Function} [callback] Callback to invoke when an fabric.Path instance is created\n */\n fabric.Path.fromObject = function(object, callback) {\n if (typeof object.sourcePath === 'string') {\n var pathUrl = object.sourcePath;\n fabric.loadSVGFromURL(pathUrl, function (elements) {\n var path = elements[0];\n path.setOptions(object);\n callback && callback(path);\n });\n }\n else {\n fabric.Object._fromObject('Path', object, callback, 'path');\n }\n };\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by `fabric.Path.fromElement`)\n * @static\n * @memberOf fabric.Path\n * @see http://www.w3.org/TR/SVG/paths.html#PathElement\n */\n fabric.Path.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(['d']);\n\n /**\n * Creates an instance of fabric.Path from an SVG element\n * @static\n * @memberOf fabric.Path\n * @param {SVGElement} element to parse\n * @param {Function} callback Callback to invoke when an fabric.Path instance is created\n * @param {Object} [options] Options object\n * @param {Function} [callback] Options callback invoked after parsing is finished\n */\n fabric.Path.fromElement = function(element, callback, options) {\n var parsedAttributes = fabric.parseAttributes(element, fabric.Path.ATTRIBUTE_NAMES);\n parsedAttributes.fromSVG = true;\n callback(new fabric.Path(parsedAttributes.d, extend(parsedAttributes, options)));\n };\n /* _FROM_SVG_END_ */\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n min = fabric.util.array.min,\n max = fabric.util.array.max;\n\n if (fabric.Group) {\n return;\n }\n\n /**\n * Group class\n * @class fabric.Group\n * @extends fabric.Object\n * @mixes fabric.Collection\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#groups}\n * @see {@link fabric.Group#initialize} for constructor definition\n */\n fabric.Group = fabric.util.createClass(fabric.Object, fabric.Collection, /** @lends fabric.Group.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'group',\n\n /**\n * Width of stroke\n * @type Number\n * @default\n */\n strokeWidth: 0,\n\n /**\n * Indicates if click, mouseover, mouseout events & hoverCursor should also check for subtargets\n * @type Boolean\n * @default\n */\n subTargetCheck: false,\n\n /**\n * Groups are container, do not render anything on theyr own, ence no cache properties\n * @type Array\n * @default\n */\n cacheProperties: [],\n\n /**\n * setOnGroup is a method used for TextBox that is no more used since 2.0.0 The behavior is still\n * available setting this boolean to true.\n * @type Boolean\n * @since 2.0.0\n * @default\n */\n useSetOnGroup: false,\n\n /**\n * Constructor\n * @param {Object} objects Group objects\n * @param {Object} [options] Options object\n * @param {Boolean} [isAlreadyGrouped] if true, objects have been grouped already.\n * @return {Object} thisArg\n */\n initialize: function(objects, options, isAlreadyGrouped) {\n options = options || {};\n this._objects = [];\n // if objects enclosed in a group have been grouped already,\n // we cannot change properties of objects.\n // Thus we need to set options to group without objects,\n isAlreadyGrouped && this.callSuper('initialize', options);\n this._objects = objects || [];\n for (var i = this._objects.length; i--; ) {\n this._objects[i].group = this;\n }\n\n if (!isAlreadyGrouped) {\n var center = options && options.centerPoint;\n // we want to set origins before calculating the bounding box.\n // so that the topleft can be set with that in mind.\n // if specific top and left are passed, are overwritten later\n // with the callSuper('initialize', options)\n if (options.originX !== undefined) {\n this.originX = options.originX;\n }\n if (options.originY !== undefined) {\n this.originY = options.originY;\n }\n // if coming from svg i do not want to calc bounds.\n // i assume width and height are passed along options\n center || this._calcBounds();\n this._updateObjectsCoords(center);\n delete options.centerPoint;\n this.callSuper('initialize', options);\n }\n else {\n this._updateObjectsACoords();\n }\n\n this.setCoords();\n },\n\n /**\n * @private\n */\n _updateObjectsACoords: function() {\n var skipControls = true;\n for (var i = this._objects.length; i--; ){\n this._objects[i].setCoords(skipControls);\n }\n },\n\n /**\n * @private\n * @param {Boolean} [skipCoordsChange] if true, coordinates of objects enclosed in a group do not change\n */\n _updateObjectsCoords: function(center) {\n var center = center || this.getCenterPoint();\n for (var i = this._objects.length; i--; ){\n this._updateObjectCoords(this._objects[i], center);\n }\n },\n\n /**\n * @private\n * @param {Object} object\n * @param {fabric.Point} center, current center of group.\n */\n _updateObjectCoords: function(object, center) {\n var objectLeft = object.left,\n objectTop = object.top,\n skipControls = true;\n\n object.set({\n left: objectLeft - center.x,\n top: objectTop - center.y\n });\n object.group = this;\n object.setCoords(skipControls);\n },\n\n /**\n * Returns string represenation of a group\n * @return {String}\n */\n toString: function() {\n return '#';\n },\n\n /**\n * Adds an object to a group; Then recalculates group's dimension, position.\n * @param {Object} object\n * @return {fabric.Group} thisArg\n * @chainable\n */\n addWithUpdate: function(object) {\n var nested = !!this.group;\n this._restoreObjectsState();\n fabric.util.resetObjectTransform(this);\n if (object) {\n if (nested) {\n // if this group is inside another group, we need to pre transform the object\n fabric.util.removeTransformFromObject(object, this.group.calcTransformMatrix());\n }\n this._objects.push(object);\n object.group = this;\n object._set('canvas', this.canvas);\n }\n this._calcBounds();\n this._updateObjectsCoords();\n this.dirty = true;\n if (nested) {\n this.group.addWithUpdate();\n }\n else {\n this.setCoords();\n }\n return this;\n },\n\n /**\n * Removes an object from a group; Then recalculates group's dimension, position.\n * @param {Object} object\n * @return {fabric.Group} thisArg\n * @chainable\n */\n removeWithUpdate: function(object) {\n this._restoreObjectsState();\n fabric.util.resetObjectTransform(this);\n\n this.remove(object);\n this._calcBounds();\n this._updateObjectsCoords();\n this.setCoords();\n this.dirty = true;\n return this;\n },\n\n /**\n * @private\n */\n _onObjectAdded: function(object) {\n this.dirty = true;\n object.group = this;\n object._set('canvas', this.canvas);\n },\n\n /**\n * @private\n */\n _onObjectRemoved: function(object) {\n this.dirty = true;\n delete object.group;\n },\n\n /**\n * @private\n */\n _set: function(key, value) {\n var i = this._objects.length;\n if (this.useSetOnGroup) {\n while (i--) {\n this._objects[i].setOnGroup(key, value);\n }\n }\n if (key === 'canvas') {\n while (i--) {\n this._objects[i]._set(key, value);\n }\n }\n fabric.Object.prototype._set.call(this, key, value);\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n var _includeDefaultValues = this.includeDefaultValues;\n var objsToObject = this._objects\n .filter(function (obj) {\n return !obj.excludeFromExport;\n })\n .map(function (obj) {\n var originalDefaults = obj.includeDefaultValues;\n obj.includeDefaultValues = _includeDefaultValues;\n var _obj = obj.toObject(propertiesToInclude);\n obj.includeDefaultValues = originalDefaults;\n return _obj;\n });\n var obj = fabric.Object.prototype.toObject.call(this, propertiesToInclude);\n obj.objects = objsToObject;\n return obj;\n },\n\n /**\n * Returns object representation of an instance, in dataless mode.\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toDatalessObject: function(propertiesToInclude) {\n var objsToObject, sourcePath = this.sourcePath;\n if (sourcePath) {\n objsToObject = sourcePath;\n }\n else {\n var _includeDefaultValues = this.includeDefaultValues;\n objsToObject = this._objects.map(function(obj) {\n var originalDefaults = obj.includeDefaultValues;\n obj.includeDefaultValues = _includeDefaultValues;\n var _obj = obj.toDatalessObject(propertiesToInclude);\n obj.includeDefaultValues = originalDefaults;\n return _obj;\n });\n }\n var obj = fabric.Object.prototype.toDatalessObject.call(this, propertiesToInclude);\n obj.objects = objsToObject;\n return obj;\n },\n\n /**\n * Renders instance on a given context\n * @param {CanvasRenderingContext2D} ctx context to render instance on\n */\n render: function(ctx) {\n this._transformDone = true;\n this.callSuper('render', ctx);\n this._transformDone = false;\n },\n\n /**\n * Decide if the object should cache or not. Create its own cache level\n * needsItsOwnCache should be used when the object drawing method requires\n * a cache step. None of the fabric classes requires it.\n * Generally you do not cache objects in groups because the group is already cached.\n * @return {Boolean}\n */\n shouldCache: function() {\n var ownCache = fabric.Object.prototype.shouldCache.call(this);\n if (ownCache) {\n for (var i = 0, len = this._objects.length; i < len; i++) {\n if (this._objects[i].willDrawShadow()) {\n this.ownCaching = false;\n return false;\n }\n }\n }\n return ownCache;\n },\n\n /**\n * Check if this object or a child object will cast a shadow\n * @return {Boolean}\n */\n willDrawShadow: function() {\n if (fabric.Object.prototype.willDrawShadow.call(this)) {\n return true;\n }\n for (var i = 0, len = this._objects.length; i < len; i++) {\n if (this._objects[i].willDrawShadow()) {\n return true;\n }\n }\n return false;\n },\n\n /**\n * Check if this group or its parent group are caching, recursively up\n * @return {Boolean}\n */\n isOnACache: function() {\n return this.ownCaching || (this.group && this.group.isOnACache());\n },\n\n /**\n * Execute the drawing operation for an object on a specified context\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n drawObject: function(ctx) {\n for (var i = 0, len = this._objects.length; i < len; i++) {\n this._objects[i].render(ctx);\n }\n this._drawClipPath(ctx, this.clipPath);\n },\n\n /**\n * Check if cache is dirty\n */\n isCacheDirty: function(skipCanvas) {\n if (this.callSuper('isCacheDirty', skipCanvas)) {\n return true;\n }\n if (!this.statefullCache) {\n return false;\n }\n for (var i = 0, len = this._objects.length; i < len; i++) {\n if (this._objects[i].isCacheDirty(true)) {\n if (this._cacheCanvas) {\n // if this group has not a cache canvas there is nothing to clean\n var x = this.cacheWidth / this.zoomX, y = this.cacheHeight / this.zoomY;\n this._cacheContext.clearRect(-x / 2, -y / 2, x, y);\n }\n return true;\n }\n }\n return false;\n },\n\n /**\n * Restores original state of each of group objects (original state is that which was before group was created).\n * if the nested boolean is true, the original state will be restored just for the\n * first group and not for all the group chain\n * @private\n * @param {Boolean} nested tell the function to restore object state up to the parent group and not more\n * @return {fabric.Group} thisArg\n * @chainable\n */\n _restoreObjectsState: function() {\n var groupMatrix = this.calcOwnMatrix();\n this._objects.forEach(function(object) {\n // instead of using _this = this;\n fabric.util.addTransformToObject(object, groupMatrix);\n delete object.group;\n object.setCoords();\n });\n return this;\n },\n\n /**\n * Destroys a group (restoring state of its objects)\n * @return {fabric.Group} thisArg\n * @chainable\n */\n destroy: function() {\n // when group is destroyed objects needs to get a repaint to be eventually\n // displayed on canvas.\n this._objects.forEach(function(object) {\n object.set('dirty', true);\n });\n return this._restoreObjectsState();\n },\n\n dispose: function () {\n this.callSuper('dispose');\n this.forEachObject(function (object) {\n object.dispose && object.dispose();\n });\n this._objects = [];\n },\n\n /**\n * make a group an active selection, remove the group from canvas\n * the group has to be on canvas for this to work.\n * @return {fabric.ActiveSelection} thisArg\n * @chainable\n */\n toActiveSelection: function() {\n if (!this.canvas) {\n return;\n }\n var objects = this._objects, canvas = this.canvas;\n this._objects = [];\n var options = this.toObject();\n delete options.objects;\n var activeSelection = new fabric.ActiveSelection([]);\n activeSelection.set(options);\n activeSelection.type = 'activeSelection';\n canvas.remove(this);\n objects.forEach(function(object) {\n object.group = activeSelection;\n object.dirty = true;\n canvas.add(object);\n });\n activeSelection.canvas = canvas;\n activeSelection._objects = objects;\n canvas._activeObject = activeSelection;\n activeSelection.setCoords();\n return activeSelection;\n },\n\n /**\n * Destroys a group (restoring state of its objects)\n * @return {fabric.Group} thisArg\n * @chainable\n */\n ungroupOnCanvas: function() {\n return this._restoreObjectsState();\n },\n\n /**\n * Sets coordinates of all objects inside group\n * @return {fabric.Group} thisArg\n * @chainable\n */\n setObjectsCoords: function() {\n var skipControls = true;\n this.forEachObject(function(object) {\n object.setCoords(skipControls);\n });\n return this;\n },\n\n /**\n * @private\n */\n _calcBounds: function(onlyWidthHeight) {\n var aX = [],\n aY = [],\n o, prop, coords,\n props = ['tr', 'br', 'bl', 'tl'],\n i = 0, iLen = this._objects.length,\n j, jLen = props.length;\n\n for ( ; i < iLen; ++i) {\n o = this._objects[i];\n coords = o.calcACoords();\n for (j = 0; j < jLen; j++) {\n prop = props[j];\n aX.push(coords[prop].x);\n aY.push(coords[prop].y);\n }\n o.aCoords = coords;\n }\n\n this._getBounds(aX, aY, onlyWidthHeight);\n },\n\n /**\n * @private\n */\n _getBounds: function(aX, aY, onlyWidthHeight) {\n var minXY = new fabric.Point(min(aX), min(aY)),\n maxXY = new fabric.Point(max(aX), max(aY)),\n top = minXY.y || 0, left = minXY.x || 0,\n width = (maxXY.x - minXY.x) || 0,\n height = (maxXY.y - minXY.y) || 0;\n this.width = width;\n this.height = height;\n if (!onlyWidthHeight) {\n // the bounding box always finds the topleft most corner.\n // whatever is the group origin, we set up here the left/top position.\n this.setPositionByOrigin({ x: left, y: top }, 'left', 'top');\n }\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n _toSVG: function(reviver) {\n var svgString = ['\\n'];\n\n for (var i = 0, len = this._objects.length; i < len; i++) {\n svgString.push('\\t\\t', this._objects[i].toSVG(reviver));\n }\n svgString.push('\\n');\n return svgString;\n },\n\n /**\n * Returns styles-string for svg-export, specific version for group\n * @return {String}\n */\n getSvgStyles: function() {\n var opacity = typeof this.opacity !== 'undefined' && this.opacity !== 1 ?\n 'opacity: ' + this.opacity + ';' : '',\n visibility = this.visible ? '' : ' visibility: hidden;';\n return [\n opacity,\n this.getSvgFilter(),\n visibility\n ].join('');\n },\n\n /**\n * Returns svg clipPath representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n toClipPathSVG: function(reviver) {\n var svgString = [];\n\n for (var i = 0, len = this._objects.length; i < len; i++) {\n svgString.push('\\t', this._objects[i].toClipPathSVG(reviver));\n }\n\n return this._createBaseClipPathSVGMarkup(svgString, { reviver: reviver });\n },\n /* _TO_SVG_END_ */\n });\n\n /**\n * Returns {@link fabric.Group} instance from an object representation\n * @static\n * @memberOf fabric.Group\n * @param {Object} object Object to create a group from\n * @param {Function} [callback] Callback to invoke when an group instance is created\n */\n fabric.Group.fromObject = function(object, callback) {\n var objects = object.objects,\n options = fabric.util.object.clone(object, true);\n delete options.objects;\n if (typeof objects === 'string') {\n // it has to be an url or something went wrong.\n fabric.loadSVGFromURL(objects, function (elements) {\n var group = fabric.util.groupSVGElements(elements, object, objects);\n group.set(options);\n callback && callback(group);\n });\n return;\n }\n fabric.util.enlivenObjects(objects, function (enlivenedObjects) {\n var options = fabric.util.object.clone(object, true);\n delete options.objects;\n fabric.util.enlivenObjectEnlivables(object, options, function () {\n callback && callback(new fabric.Group(enlivenedObjects, options, true));\n });\n });\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { });\n\n if (fabric.ActiveSelection) {\n return;\n }\n\n /**\n * Group class\n * @class fabric.ActiveSelection\n * @extends fabric.Group\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-3#groups}\n * @see {@link fabric.ActiveSelection#initialize} for constructor definition\n */\n fabric.ActiveSelection = fabric.util.createClass(fabric.Group, /** @lends fabric.ActiveSelection.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'activeSelection',\n\n /**\n * Constructor\n * @param {Object} objects ActiveSelection objects\n * @param {Object} [options] Options object\n * @return {Object} thisArg\n */\n initialize: function(objects, options) {\n options = options || {};\n this._objects = objects || [];\n for (var i = this._objects.length; i--; ) {\n this._objects[i].group = this;\n }\n\n if (options.originX) {\n this.originX = options.originX;\n }\n if (options.originY) {\n this.originY = options.originY;\n }\n this._calcBounds();\n this._updateObjectsCoords();\n fabric.Object.prototype.initialize.call(this, options);\n this.setCoords();\n },\n\n /**\n * Change te activeSelection to a normal group,\n * High level function that automatically adds it to canvas as\n * active object. no events fired.\n * @since 2.0.0\n * @return {fabric.Group}\n */\n toGroup: function() {\n var objects = this._objects.concat();\n this._objects = [];\n var options = fabric.Object.prototype.toObject.call(this);\n var newGroup = new fabric.Group([]);\n delete options.type;\n newGroup.set(options);\n objects.forEach(function(object) {\n object.canvas.remove(object);\n object.group = newGroup;\n });\n newGroup._objects = objects;\n if (!this.canvas) {\n return newGroup;\n }\n var canvas = this.canvas;\n canvas.add(newGroup);\n canvas._activeObject = newGroup;\n newGroup.setCoords();\n return newGroup;\n },\n\n /**\n * If returns true, deselection is cancelled.\n * @since 2.0.0\n * @return {Boolean} [cancel]\n */\n onDeselect: function() {\n this.destroy();\n return false;\n },\n\n /**\n * Returns string representation of a group\n * @return {String}\n */\n toString: function() {\n return '#';\n },\n\n /**\n * Decide if the object should cache or not. Create its own cache level\n * objectCaching is a global flag, wins over everything\n * needsItsOwnCache should be used when the object drawing method requires\n * a cache step. None of the fabric classes requires it.\n * Generally you do not cache objects in groups because the group outside is cached.\n * @return {Boolean}\n */\n shouldCache: function() {\n return false;\n },\n\n /**\n * Check if this group or its parent group are caching, recursively up\n * @return {Boolean}\n */\n isOnACache: function() {\n return false;\n },\n\n /**\n * Renders controls and borders for the object\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {Object} [styleOverride] properties to override the object style\n * @param {Object} [childrenOverride] properties to override the children overrides\n */\n _renderControls: function(ctx, styleOverride, childrenOverride) {\n ctx.save();\n ctx.globalAlpha = this.isMoving ? this.borderOpacityWhenMoving : 1;\n this.callSuper('_renderControls', ctx, styleOverride);\n childrenOverride = childrenOverride || { };\n if (typeof childrenOverride.hasControls === 'undefined') {\n childrenOverride.hasControls = false;\n }\n childrenOverride.forActiveSelection = true;\n for (var i = 0, len = this._objects.length; i < len; i++) {\n this._objects[i]._renderControls(ctx, childrenOverride);\n }\n ctx.restore();\n },\n });\n\n /**\n * Returns {@link fabric.ActiveSelection} instance from an object representation\n * @static\n * @memberOf fabric.ActiveSelection\n * @param {Object} object Object to create a group from\n * @param {Function} [callback] Callback to invoke when an ActiveSelection instance is created\n */\n fabric.ActiveSelection.fromObject = function(object, callback) {\n fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) {\n delete object.objects;\n callback && callback(new fabric.ActiveSelection(enlivenedObjects, object, true));\n });\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var extend = fabric.util.object.extend;\n\n if (!global.fabric) {\n global.fabric = { };\n }\n\n if (global.fabric.Image) {\n fabric.warn('fabric.Image is already defined.');\n return;\n }\n\n /**\n * Image class\n * @class fabric.Image\n * @extends fabric.Object\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-1#images}\n * @see {@link fabric.Image#initialize} for constructor definition\n */\n fabric.Image = fabric.util.createClass(fabric.Object, /** @lends fabric.Image.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'image',\n\n /**\n * Width of a stroke.\n * For image quality a stroke multiple of 2 gives better results.\n * @type Number\n * @default\n */\n strokeWidth: 0,\n\n /**\n * When calling {@link fabric.Image.getSrc}, return value from element src with `element.getAttribute('src')`.\n * This allows for relative urls as image src.\n * @since 2.7.0\n * @type Boolean\n * @default\n */\n srcFromAttribute: false,\n\n /**\n * private\n * contains last value of scaleX to detect\n * if the Image got resized after the last Render\n * @type Number\n */\n _lastScaleX: 1,\n\n /**\n * private\n * contains last value of scaleY to detect\n * if the Image got resized after the last Render\n * @type Number\n */\n _lastScaleY: 1,\n\n /**\n * private\n * contains last value of scaling applied by the apply filter chain\n * @type Number\n */\n _filterScalingX: 1,\n\n /**\n * private\n * contains last value of scaling applied by the apply filter chain\n * @type Number\n */\n _filterScalingY: 1,\n\n /**\n * minimum scale factor under which any resizeFilter is triggered to resize the image\n * 0 will disable the automatic resize. 1 will trigger automatically always.\n * number bigger than 1 are not implemented yet.\n * @type Number\n */\n minimumScaleTrigger: 0.5,\n\n /**\n * List of properties to consider when checking if\n * state of an object is changed ({@link fabric.Object#hasStateChanged})\n * as well as for history (undo/redo) purposes\n * @type Array\n */\n stateProperties: fabric.Object.prototype.stateProperties.concat('cropX', 'cropY'),\n\n /**\n * List of properties to consider when checking if cache needs refresh\n * Those properties are checked by statefullCache ON ( or lazy mode if we want ) or from single\n * calls to Object.set(key, value). If the key is in this list, the object is marked as dirty\n * and refreshed at the next render\n * @type Array\n */\n cacheProperties: fabric.Object.prototype.cacheProperties.concat('cropX', 'cropY'),\n\n /**\n * key used to retrieve the texture representing this image\n * @since 2.0.0\n * @type String\n * @default\n */\n cacheKey: '',\n\n /**\n * Image crop in pixels from original image size.\n * @since 2.0.0\n * @type Number\n * @default\n */\n cropX: 0,\n\n /**\n * Image crop in pixels from original image size.\n * @since 2.0.0\n * @type Number\n * @default\n */\n cropY: 0,\n\n /**\n * Indicates whether this canvas will use image smoothing when painting this image.\n * Also influence if the cacheCanvas for this image uses imageSmoothing\n * @since 4.0.0-beta.11\n * @type Boolean\n * @default\n */\n imageSmoothing: true,\n\n /**\n * Constructor\n * Image can be initialized with any canvas drawable or a string.\n * The string should be a url and will be loaded as an image.\n * Canvas and Image element work out of the box, while videos require extra code to work.\n * Please check video element events for seeking.\n * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | String} element Image element\n * @param {Object} [options] Options object\n * @param {function} [callback] callback function to call after eventual filters applied.\n * @return {fabric.Image} thisArg\n */\n initialize: function(element, options) {\n options || (options = { });\n this.filters = [];\n this.cacheKey = 'texture' + fabric.Object.__uid++;\n this.callSuper('initialize', options);\n this._initElement(element, options);\n },\n\n /**\n * Returns image element which this instance if based on\n * @return {HTMLImageElement} Image element\n */\n getElement: function() {\n return this._element || {};\n },\n\n /**\n * Sets image element for this instance to a specified one.\n * If filters defined they are applied to new image.\n * You might need to call `canvas.renderAll` and `object.setCoords` after replacing, to render new image and update controls area.\n * @param {HTMLImageElement} element\n * @param {Object} [options] Options object\n * @return {fabric.Image} thisArg\n * @chainable\n */\n setElement: function(element, options) {\n this.removeTexture(this.cacheKey);\n this.removeTexture(this.cacheKey + '_filtered');\n this._element = element;\n this._originalElement = element;\n this._initConfig(options);\n if (this.filters.length !== 0) {\n this.applyFilters();\n }\n // resizeFilters work on the already filtered copy.\n // we need to apply resizeFilters AFTER normal filters.\n // applyResizeFilters is run more often than normal filters\n // and is triggered by user interactions rather than dev code\n if (this.resizeFilter) {\n this.applyResizeFilters();\n }\n return this;\n },\n\n /**\n * Delete a single texture if in webgl mode\n */\n removeTexture: function(key) {\n var backend = fabric.filterBackend;\n if (backend && backend.evictCachesForKey) {\n backend.evictCachesForKey(key);\n }\n },\n\n /**\n * Delete textures, reference to elements and eventually JSDOM cleanup\n */\n dispose: function () {\n this.callSuper('dispose');\n this.removeTexture(this.cacheKey);\n this.removeTexture(this.cacheKey + '_filtered');\n this._cacheContext = undefined;\n ['_originalElement', '_element', '_filteredEl', '_cacheCanvas'].forEach((function(element) {\n fabric.util.cleanUpJsdomNode(this[element]);\n this[element] = undefined;\n }).bind(this));\n },\n\n /**\n * Get the crossOrigin value (of the corresponding image element)\n */\n getCrossOrigin: function() {\n return this._originalElement && (this._originalElement.crossOrigin || null);\n },\n\n /**\n * Returns original size of an image\n * @return {Object} Object with \"width\" and \"height\" properties\n */\n getOriginalSize: function() {\n var element = this.getElement();\n return {\n width: element.naturalWidth || element.width,\n height: element.naturalHeight || element.height\n };\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _stroke: function(ctx) {\n if (!this.stroke || this.strokeWidth === 0) {\n return;\n }\n var w = this.width / 2, h = this.height / 2;\n ctx.beginPath();\n ctx.moveTo(-w, -h);\n ctx.lineTo(w, -h);\n ctx.lineTo(w, h);\n ctx.lineTo(-w, h);\n ctx.lineTo(-w, -h);\n ctx.closePath();\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} Object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n var filters = [];\n\n this.filters.forEach(function(filterObj) {\n if (filterObj) {\n filters.push(filterObj.toObject());\n }\n });\n var object = extend(\n this.callSuper(\n 'toObject',\n ['cropX', 'cropY'].concat(propertiesToInclude)\n ), {\n src: this.getSrc(),\n crossOrigin: this.getCrossOrigin(),\n filters: filters,\n });\n if (this.resizeFilter) {\n object.resizeFilter = this.resizeFilter.toObject();\n }\n return object;\n },\n\n /**\n * Returns true if an image has crop applied, inspecting values of cropX,cropY,width,height.\n * @return {Boolean}\n */\n hasCrop: function() {\n return this.cropX || this.cropY || this.width < this._element.width || this.height < this._element.height;\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * @return {Array} an array of strings with the specific svg representation\n * of the instance\n */\n _toSVG: function() {\n var svgString = [], imageMarkup = [], strokeSvg, element = this._element,\n x = -this.width / 2, y = -this.height / 2, clipPath = '', imageRendering = '';\n if (!element) {\n return [];\n }\n if (this.hasCrop()) {\n var clipPathId = fabric.Object.__uid++;\n svgString.push(\n '\\n',\n '\\t\\n',\n '\\n'\n );\n clipPath = ' clip-path=\"url(#imageCrop_' + clipPathId + ')\" ';\n }\n if (!this.imageSmoothing) {\n imageRendering = '\" image-rendering=\"optimizeSpeed';\n }\n imageMarkup.push('\\t element with actual transformation, then offsetting object to the top/left\n // so that object's center aligns with container's left/top\n '\" width=\"', element.width || element.naturalWidth,\n '\" height=\"', element.height || element.height,\n imageRendering,\n '\"', clipPath,\n '>\\n');\n\n if (this.stroke || this.strokeDashArray) {\n var origFill = this.fill;\n this.fill = null;\n strokeSvg = [\n '\\t\\n'\n ];\n this.fill = origFill;\n }\n if (this.paintFirst !== 'fill') {\n svgString = svgString.concat(strokeSvg, imageMarkup);\n }\n else {\n svgString = svgString.concat(imageMarkup, strokeSvg);\n }\n return svgString;\n },\n /* _TO_SVG_END_ */\n\n /**\n * Returns source of an image\n * @param {Boolean} filtered indicates if the src is needed for svg\n * @return {String} Source of an image\n */\n getSrc: function(filtered) {\n var element = filtered ? this._element : this._originalElement;\n if (element) {\n if (element.toDataURL) {\n return element.toDataURL();\n }\n\n if (this.srcFromAttribute) {\n return element.getAttribute('src');\n }\n else {\n return element.src;\n }\n }\n else {\n return this.src || '';\n }\n },\n\n /**\n * Sets source of an image\n * @param {String} src Source string (URL)\n * @param {Function} [callback] Callback is invoked when image has been loaded (and all filters have been applied)\n * @param {Object} [options] Options object\n * @param {String} [options.crossOrigin] crossOrigin value (one of \"\", \"anonymous\", \"use-credentials\")\n * @see https://developer.mozilla.org/en-US/docs/HTML/CORS_settings_attributes\n * @return {fabric.Image} thisArg\n * @chainable\n */\n setSrc: function(src, callback, options) {\n fabric.util.loadImage(src, function(img, isError) {\n this.setElement(img, options);\n this._setWidthHeight();\n callback && callback(this, isError);\n }, this, options && options.crossOrigin);\n return this;\n },\n\n /**\n * Returns string representation of an instance\n * @return {String} String representation of an instance\n */\n toString: function() {\n return '#';\n },\n\n applyResizeFilters: function() {\n var filter = this.resizeFilter,\n minimumScale = this.minimumScaleTrigger,\n objectScale = this.getTotalObjectScaling(),\n scaleX = objectScale.scaleX,\n scaleY = objectScale.scaleY,\n elementToFilter = this._filteredEl || this._originalElement;\n if (this.group) {\n this.set('dirty', true);\n }\n if (!filter || (scaleX > minimumScale && scaleY > minimumScale)) {\n this._element = elementToFilter;\n this._filterScalingX = 1;\n this._filterScalingY = 1;\n this._lastScaleX = scaleX;\n this._lastScaleY = scaleY;\n return;\n }\n if (!fabric.filterBackend) {\n fabric.filterBackend = fabric.initFilterBackend();\n }\n var canvasEl = fabric.util.createCanvasElement(),\n cacheKey = this._filteredEl ? (this.cacheKey + '_filtered') : this.cacheKey,\n sourceWidth = elementToFilter.width, sourceHeight = elementToFilter.height;\n canvasEl.width = sourceWidth;\n canvasEl.height = sourceHeight;\n this._element = canvasEl;\n this._lastScaleX = filter.scaleX = scaleX;\n this._lastScaleY = filter.scaleY = scaleY;\n fabric.filterBackend.applyFilters(\n [filter], elementToFilter, sourceWidth, sourceHeight, this._element, cacheKey);\n this._filterScalingX = canvasEl.width / this._originalElement.width;\n this._filterScalingY = canvasEl.height / this._originalElement.height;\n },\n\n /**\n * Applies filters assigned to this image (from \"filters\" array) or from filter param\n * @method applyFilters\n * @param {Array} filters to be applied\n * @param {Boolean} forResizing specify if the filter operation is a resize operation\n * @return {thisArg} return the fabric.Image object\n * @chainable\n */\n applyFilters: function(filters) {\n\n filters = filters || this.filters || [];\n filters = filters.filter(function(filter) { return filter && !filter.isNeutralState(); });\n this.set('dirty', true);\n\n // needs to clear out or WEBGL will not resize correctly\n this.removeTexture(this.cacheKey + '_filtered');\n\n if (filters.length === 0) {\n this._element = this._originalElement;\n this._filteredEl = null;\n this._filterScalingX = 1;\n this._filterScalingY = 1;\n return this;\n }\n\n var imgElement = this._originalElement,\n sourceWidth = imgElement.naturalWidth || imgElement.width,\n sourceHeight = imgElement.naturalHeight || imgElement.height;\n\n if (this._element === this._originalElement) {\n // if the element is the same we need to create a new element\n var canvasEl = fabric.util.createCanvasElement();\n canvasEl.width = sourceWidth;\n canvasEl.height = sourceHeight;\n this._element = canvasEl;\n this._filteredEl = canvasEl;\n }\n else {\n // clear the existing element to get new filter data\n // also dereference the eventual resized _element\n this._element = this._filteredEl;\n this._filteredEl.getContext('2d').clearRect(0, 0, sourceWidth, sourceHeight);\n // we also need to resize again at next renderAll, so remove saved _lastScaleX/Y\n this._lastScaleX = 1;\n this._lastScaleY = 1;\n }\n if (!fabric.filterBackend) {\n fabric.filterBackend = fabric.initFilterBackend();\n }\n fabric.filterBackend.applyFilters(\n filters, this._originalElement, sourceWidth, sourceHeight, this._element, this.cacheKey);\n if (this._originalElement.width !== this._element.width ||\n this._originalElement.height !== this._element.height) {\n this._filterScalingX = this._element.width / this._originalElement.width;\n this._filterScalingY = this._element.height / this._originalElement.height;\n }\n return this;\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n fabric.util.setImageSmoothing(ctx, this.imageSmoothing);\n if (this.isMoving !== true && this.resizeFilter && this._needsResize()) {\n this.applyResizeFilters();\n }\n this._stroke(ctx);\n this._renderPaintInOrder(ctx);\n },\n\n /**\n * Paint the cached copy of the object on the target context.\n * it will set the imageSmoothing for the draw operation\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n drawCacheOnCanvas: function(ctx) {\n fabric.util.setImageSmoothing(ctx, this.imageSmoothing);\n fabric.Object.prototype.drawCacheOnCanvas.call(this, ctx);\n },\n\n /**\n * Decide if the object should cache or not. Create its own cache level\n * needsItsOwnCache should be used when the object drawing method requires\n * a cache step. None of the fabric classes requires it.\n * Generally you do not cache objects in groups because the group outside is cached.\n * This is the special image version where we would like to avoid caching where possible.\n * Essentially images do not benefit from caching. They may require caching, and in that\n * case we do it. Also caching an image usually ends in a loss of details.\n * A full performance audit should be done.\n * @return {Boolean}\n */\n shouldCache: function() {\n return this.needsItsOwnCache();\n },\n\n _renderFill: function(ctx) {\n var elementToDraw = this._element;\n if (!elementToDraw) {\n return;\n }\n var scaleX = this._filterScalingX, scaleY = this._filterScalingY,\n w = this.width, h = this.height, min = Math.min, max = Math.max,\n // crop values cannot be lesser than 0.\n cropX = max(this.cropX, 0), cropY = max(this.cropY, 0),\n elWidth = elementToDraw.naturalWidth || elementToDraw.width,\n elHeight = elementToDraw.naturalHeight || elementToDraw.height,\n sX = cropX * scaleX,\n sY = cropY * scaleY,\n // the width height cannot exceed element width/height, starting from the crop offset.\n sW = min(w * scaleX, elWidth - sX),\n sH = min(h * scaleY, elHeight - sY),\n x = -w / 2, y = -h / 2,\n maxDestW = min(w, elWidth / scaleX - cropX),\n maxDestH = min(h, elHeight / scaleY - cropY);\n\n elementToDraw && ctx.drawImage(elementToDraw, sX, sY, sW, sH, x, y, maxDestW, maxDestH);\n },\n\n /**\n * needed to check if image needs resize\n * @private\n */\n _needsResize: function() {\n var scale = this.getTotalObjectScaling();\n return (scale.scaleX !== this._lastScaleX || scale.scaleY !== this._lastScaleY);\n },\n\n /**\n * @private\n */\n _resetWidthHeight: function() {\n this.set(this.getOriginalSize());\n },\n\n /**\n * The Image class's initialization method. This method is automatically\n * called by the constructor.\n * @private\n * @param {HTMLImageElement|String} element The element representing the image\n * @param {Object} [options] Options object\n */\n _initElement: function(element, options) {\n this.setElement(fabric.util.getById(element), options);\n fabric.util.addClass(this.getElement(), fabric.Image.CSS_CANVAS);\n },\n\n /**\n * @private\n * @param {Object} [options] Options object\n */\n _initConfig: function(options) {\n options || (options = { });\n this.setOptions(options);\n this._setWidthHeight(options);\n },\n\n /**\n * @private\n * @param {Array} filters to be initialized\n * @param {Function} callback Callback to invoke when all fabric.Image.filters instances are created\n */\n _initFilters: function(filters, callback) {\n if (filters && filters.length) {\n fabric.util.enlivenObjects(filters, function(enlivenedObjects) {\n callback && callback(enlivenedObjects);\n }, 'fabric.Image.filters');\n }\n else {\n callback && callback();\n }\n },\n\n /**\n * @private\n * Set the width and the height of the image object, using the element or the\n * options.\n * @param {Object} [options] Object with width/height properties\n */\n _setWidthHeight: function(options) {\n options || (options = { });\n var el = this.getElement();\n this.width = options.width || el.naturalWidth || el.width || 0;\n this.height = options.height || el.naturalHeight || el.height || 0;\n },\n\n /**\n * Calculate offset for center and scale factor for the image in order to respect\n * the preserveAspectRatio attribute\n * @private\n * @return {Object}\n */\n parsePreserveAspectRatioAttribute: function() {\n var pAR = fabric.util.parsePreserveAspectRatioAttribute(this.preserveAspectRatio || ''),\n rWidth = this._element.width, rHeight = this._element.height,\n scaleX = 1, scaleY = 1, offsetLeft = 0, offsetTop = 0, cropX = 0, cropY = 0,\n offset, pWidth = this.width, pHeight = this.height, parsedAttributes = { width: pWidth, height: pHeight };\n if (pAR && (pAR.alignX !== 'none' || pAR.alignY !== 'none')) {\n if (pAR.meetOrSlice === 'meet') {\n scaleX = scaleY = fabric.util.findScaleToFit(this._element, parsedAttributes);\n offset = (pWidth - rWidth * scaleX) / 2;\n if (pAR.alignX === 'Min') {\n offsetLeft = -offset;\n }\n if (pAR.alignX === 'Max') {\n offsetLeft = offset;\n }\n offset = (pHeight - rHeight * scaleY) / 2;\n if (pAR.alignY === 'Min') {\n offsetTop = -offset;\n }\n if (pAR.alignY === 'Max') {\n offsetTop = offset;\n }\n }\n if (pAR.meetOrSlice === 'slice') {\n scaleX = scaleY = fabric.util.findScaleToCover(this._element, parsedAttributes);\n offset = rWidth - pWidth / scaleX;\n if (pAR.alignX === 'Mid') {\n cropX = offset / 2;\n }\n if (pAR.alignX === 'Max') {\n cropX = offset;\n }\n offset = rHeight - pHeight / scaleY;\n if (pAR.alignY === 'Mid') {\n cropY = offset / 2;\n }\n if (pAR.alignY === 'Max') {\n cropY = offset;\n }\n rWidth = pWidth / scaleX;\n rHeight = pHeight / scaleY;\n }\n }\n else {\n scaleX = pWidth / rWidth;\n scaleY = pHeight / rHeight;\n }\n return {\n width: rWidth,\n height: rHeight,\n scaleX: scaleX,\n scaleY: scaleY,\n offsetLeft: offsetLeft,\n offsetTop: offsetTop,\n cropX: cropX,\n cropY: cropY\n };\n }\n });\n\n /**\n * Default CSS class name for canvas\n * @static\n * @type String\n * @default\n */\n fabric.Image.CSS_CANVAS = 'canvas-img';\n\n /**\n * Alias for getSrc\n * @static\n */\n fabric.Image.prototype.getSvgSrc = fabric.Image.prototype.getSrc;\n\n /**\n * Creates an instance of fabric.Image from its object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {Function} callback Callback to invoke when an image instance is created\n */\n fabric.Image.fromObject = function(_object, callback) {\n var object = fabric.util.object.clone(_object);\n fabric.util.loadImage(object.src, function(img, isError) {\n if (isError) {\n callback && callback(null, true);\n return;\n }\n fabric.Image.prototype._initFilters.call(object, object.filters, function(filters) {\n object.filters = filters || [];\n fabric.Image.prototype._initFilters.call(object, [object.resizeFilter], function(resizeFilters) {\n object.resizeFilter = resizeFilters[0];\n fabric.util.enlivenObjectEnlivables(object, object, function () {\n var image = new fabric.Image(img, object);\n callback(image, false);\n });\n });\n });\n }, null, object.crossOrigin);\n };\n\n /**\n * Creates an instance of fabric.Image from an URL string\n * @static\n * @param {String} url URL to create an image from\n * @param {Function} [callback] Callback to invoke when image is created (newly created image is passed as a first argument). Second argument is a boolean indicating if an error occurred or not.\n * @param {Object} [imgOptions] Options object\n */\n fabric.Image.fromURL = function(url, callback, imgOptions) {\n fabric.util.loadImage(url, function(img, isError) {\n callback && callback(new fabric.Image(img, imgOptions), isError);\n }, null, imgOptions && imgOptions.crossOrigin);\n };\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by {@link fabric.Image.fromElement})\n * @static\n * @see {@link http://www.w3.org/TR/SVG/struct.html#ImageElement}\n */\n fabric.Image.ATTRIBUTE_NAMES =\n fabric.SHARED_ATTRIBUTES.concat(\n 'x y width height preserveAspectRatio xlink:href crossOrigin image-rendering'.split(' ')\n );\n\n /**\n * Returns {@link fabric.Image} instance from an SVG element\n * @static\n * @param {SVGElement} element Element to parse\n * @param {Object} [options] Options object\n * @param {Function} callback Callback to execute when fabric.Image object is created\n * @return {fabric.Image} Instance of fabric.Image\n */\n fabric.Image.fromElement = function(element, callback, options) {\n var parsedAttributes = fabric.parseAttributes(element, fabric.Image.ATTRIBUTE_NAMES);\n fabric.Image.fromURL(parsedAttributes['xlink:href'], callback,\n extend((options ? fabric.util.object.clone(options) : { }), parsedAttributes));\n };\n /* _FROM_SVG_END_ */\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\nfabric.util.object.extend(fabric.Object.prototype, /** @lends fabric.Object.prototype */ {\n\n /**\n * @private\n * @return {Number} angle value\n */\n _getAngleValueForStraighten: function() {\n var angle = this.angle % 360;\n if (angle > 0) {\n return Math.round((angle - 1) / 90) * 90;\n }\n return Math.round(angle / 90) * 90;\n },\n\n /**\n * Straightens an object (rotating it from current angle to one of 0, 90, 180, 270, etc. depending on which is closer)\n * @return {fabric.Object} thisArg\n * @chainable\n */\n straighten: function() {\n return this.rotate(this._getAngleValueForStraighten());\n },\n\n /**\n * Same as {@link fabric.Object.prototype.straighten} but with animation\n * @param {Object} callbacks Object with callback functions\n * @param {Function} [callbacks.onComplete] Invoked on completion\n * @param {Function} [callbacks.onChange] Invoked on every step of animation\n * @return {fabric.Object} thisArg\n */\n fxStraighten: function(callbacks) {\n callbacks = callbacks || { };\n\n var empty = function() { },\n onComplete = callbacks.onComplete || empty,\n onChange = callbacks.onChange || empty,\n _this = this;\n\n return fabric.util.animate({\n target: this,\n startValue: this.get('angle'),\n endValue: this._getAngleValueForStraighten(),\n duration: this.FX_DURATION,\n onChange: function(value) {\n _this.rotate(value);\n onChange();\n },\n onComplete: function() {\n _this.setCoords();\n onComplete();\n },\n });\n }\n});\n\nfabric.util.object.extend(fabric.StaticCanvas.prototype, /** @lends fabric.StaticCanvas.prototype */ {\n\n /**\n * Straightens object, then rerenders canvas\n * @param {fabric.Object} object Object to straighten\n * @return {fabric.Canvas} thisArg\n * @chainable\n */\n straightenObject: function (object) {\n object.straighten();\n this.requestRenderAll();\n return this;\n },\n\n /**\n * Same as {@link fabric.Canvas.prototype.straightenObject}, but animated\n * @param {fabric.Object} object Object to straighten\n * @return {fabric.Canvas} thisArg\n */\n fxStraightenObject: function (object) {\n return object.fxStraighten({\n onChange: this.requestRenderAllBound\n });\n }\n});\n\n\n(function() {\n\n 'use strict';\n\n /**\n * Tests if webgl supports certain precision\n * @param {WebGL} Canvas WebGL context to test on\n * @param {String} Precision to test can be any of following: 'lowp', 'mediump', 'highp'\n * @returns {Boolean} Whether the user's browser WebGL supports given precision.\n */\n function testPrecision(gl, precision){\n var fragmentSource = 'precision ' + precision + ' float;\\nvoid main(){}';\n var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n gl.shaderSource(fragmentShader, fragmentSource);\n gl.compileShader(fragmentShader);\n if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {\n return false;\n }\n return true;\n }\n\n /**\n * Indicate whether this filtering backend is supported by the user's browser.\n * @param {Number} tileSize check if the tileSize is supported\n * @returns {Boolean} Whether the user's browser supports WebGL.\n */\n fabric.isWebglSupported = function(tileSize) {\n if (fabric.isLikelyNode) {\n return false;\n }\n tileSize = tileSize || fabric.WebglFilterBackend.prototype.tileSize;\n var canvas = document.createElement('canvas');\n var gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');\n var isSupported = false;\n // eslint-disable-next-line\n if (gl) {\n fabric.maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);\n isSupported = fabric.maxTextureSize >= tileSize;\n var precisions = ['highp', 'mediump', 'lowp'];\n for (var i = 0; i < 3; i++){\n if (testPrecision(gl, precisions[i])){\n fabric.webGlPrecision = precisions[i];\n break;\n };\n }\n }\n this.isSupported = isSupported;\n return isSupported;\n };\n\n fabric.WebglFilterBackend = WebglFilterBackend;\n\n /**\n * WebGL filter backend.\n */\n function WebglFilterBackend(options) {\n if (options && options.tileSize) {\n this.tileSize = options.tileSize;\n }\n this.setupGLContext(this.tileSize, this.tileSize);\n this.captureGPUInfo();\n };\n\n WebglFilterBackend.prototype = /** @lends fabric.WebglFilterBackend.prototype */ {\n\n tileSize: 2048,\n\n /**\n * Experimental. This object is a sort of repository of help layers used to avoid\n * of recreating them during frequent filtering. If you are previewing a filter with\n * a slider you probably do not want to create help layers every filter step.\n * in this object there will be appended some canvases, created once, resized sometimes\n * cleared never. Clearing is left to the developer.\n **/\n resources: {\n\n },\n\n /**\n * Setup a WebGL context suitable for filtering, and bind any needed event handlers.\n */\n setupGLContext: function(width, height) {\n this.dispose();\n this.createWebGLCanvas(width, height);\n // eslint-disable-next-line\n this.aPosition = new Float32Array([0, 0, 0, 1, 1, 0, 1, 1]);\n this.chooseFastestCopyGLTo2DMethod(width, height);\n },\n\n /**\n * Pick a method to copy data from GL context to 2d canvas. In some browsers using\n * putImageData is faster than drawImage for that specific operation.\n */\n chooseFastestCopyGLTo2DMethod: function(width, height) {\n var canMeasurePerf = typeof window.performance !== 'undefined', canUseImageData;\n try {\n new ImageData(1, 1);\n canUseImageData = true;\n }\n catch (e) {\n canUseImageData = false;\n }\n // eslint-disable-next-line no-undef\n var canUseArrayBuffer = typeof ArrayBuffer !== 'undefined';\n // eslint-disable-next-line no-undef\n var canUseUint8Clamped = typeof Uint8ClampedArray !== 'undefined';\n\n if (!(canMeasurePerf && canUseImageData && canUseArrayBuffer && canUseUint8Clamped)) {\n return;\n }\n\n var targetCanvas = fabric.util.createCanvasElement();\n // eslint-disable-next-line no-undef\n var imageBuffer = new ArrayBuffer(width * height * 4);\n if (fabric.forceGLPutImageData) {\n this.imageBuffer = imageBuffer;\n this.copyGLTo2D = copyGLTo2DPutImageData;\n return;\n }\n var testContext = {\n imageBuffer: imageBuffer,\n destinationWidth: width,\n destinationHeight: height,\n targetCanvas: targetCanvas\n };\n var startTime, drawImageTime, putImageDataTime;\n targetCanvas.width = width;\n targetCanvas.height = height;\n\n startTime = window.performance.now();\n copyGLTo2DDrawImage.call(testContext, this.gl, testContext);\n drawImageTime = window.performance.now() - startTime;\n\n startTime = window.performance.now();\n copyGLTo2DPutImageData.call(testContext, this.gl, testContext);\n putImageDataTime = window.performance.now() - startTime;\n\n if (drawImageTime > putImageDataTime) {\n this.imageBuffer = imageBuffer;\n this.copyGLTo2D = copyGLTo2DPutImageData;\n }\n else {\n this.copyGLTo2D = copyGLTo2DDrawImage;\n }\n },\n\n /**\n * Create a canvas element and associated WebGL context and attaches them as\n * class properties to the GLFilterBackend class.\n */\n createWebGLCanvas: function(width, height) {\n var canvas = fabric.util.createCanvasElement();\n canvas.width = width;\n canvas.height = height;\n var glOptions = {\n alpha: true,\n premultipliedAlpha: false,\n depth: false,\n stencil: false,\n antialias: false\n },\n gl = canvas.getContext('webgl', glOptions);\n if (!gl) {\n gl = canvas.getContext('experimental-webgl', glOptions);\n }\n if (!gl) {\n return;\n }\n gl.clearColor(0, 0, 0, 0);\n // this canvas can fire webglcontextlost and webglcontextrestored\n this.canvas = canvas;\n this.gl = gl;\n },\n\n /**\n * Attempts to apply the requested filters to the source provided, drawing the filtered output\n * to the provided target canvas.\n *\n * @param {Array} filters The filters to apply.\n * @param {HTMLImageElement|HTMLCanvasElement} source The source to be filtered.\n * @param {Number} width The width of the source input.\n * @param {Number} height The height of the source input.\n * @param {HTMLCanvasElement} targetCanvas The destination for filtered output to be drawn.\n * @param {String|undefined} cacheKey A key used to cache resources related to the source. If\n * omitted, caching will be skipped.\n */\n applyFilters: function(filters, source, width, height, targetCanvas, cacheKey) {\n var gl = this.gl;\n var cachedTexture;\n if (cacheKey) {\n cachedTexture = this.getCachedTexture(cacheKey, source);\n }\n var pipelineState = {\n originalWidth: source.width || source.originalWidth,\n originalHeight: source.height || source.originalHeight,\n sourceWidth: width,\n sourceHeight: height,\n destinationWidth: width,\n destinationHeight: height,\n context: gl,\n sourceTexture: this.createTexture(gl, width, height, !cachedTexture && source),\n targetTexture: this.createTexture(gl, width, height),\n originalTexture: cachedTexture ||\n this.createTexture(gl, width, height, !cachedTexture && source),\n passes: filters.length,\n webgl: true,\n aPosition: this.aPosition,\n programCache: this.programCache,\n pass: 0,\n filterBackend: this,\n targetCanvas: targetCanvas\n };\n var tempFbo = gl.createFramebuffer();\n gl.bindFramebuffer(gl.FRAMEBUFFER, tempFbo);\n filters.forEach(function(filter) { filter && filter.applyTo(pipelineState); });\n resizeCanvasIfNeeded(pipelineState);\n this.copyGLTo2D(gl, pipelineState);\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.deleteTexture(pipelineState.sourceTexture);\n gl.deleteTexture(pipelineState.targetTexture);\n gl.deleteFramebuffer(tempFbo);\n targetCanvas.getContext('2d').setTransform(1, 0, 0, 1, 0, 0);\n return pipelineState;\n },\n\n /**\n * Detach event listeners, remove references, and clean up caches.\n */\n dispose: function() {\n if (this.canvas) {\n this.canvas = null;\n this.gl = null;\n }\n this.clearWebGLCaches();\n },\n\n /**\n * Wipe out WebGL-related caches.\n */\n clearWebGLCaches: function() {\n this.programCache = {};\n this.textureCache = {};\n },\n\n /**\n * Create a WebGL texture object.\n *\n * Accepts specific dimensions to initialize the texture to or a source image.\n *\n * @param {WebGLRenderingContext} gl The GL context to use for creating the texture.\n * @param {Number} width The width to initialize the texture at.\n * @param {Number} height The height to initialize the texture.\n * @param {HTMLImageElement|HTMLCanvasElement} textureImageSource A source for the texture data.\n * @returns {WebGLTexture}\n */\n createTexture: function(gl, width, height, textureImageSource) {\n var texture = gl.createTexture();\n gl.bindTexture(gl.TEXTURE_2D, texture);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);\n gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);\n if (textureImageSource) {\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureImageSource);\n }\n else {\n gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);\n }\n return texture;\n },\n\n /**\n * Can be optionally used to get a texture from the cache array\n *\n * If an existing texture is not found, a new texture is created and cached.\n *\n * @param {String} uniqueId A cache key to use to find an existing texture.\n * @param {HTMLImageElement|HTMLCanvasElement} textureImageSource A source to use to create the\n * texture cache entry if one does not already exist.\n */\n getCachedTexture: function(uniqueId, textureImageSource) {\n if (this.textureCache[uniqueId]) {\n return this.textureCache[uniqueId];\n }\n else {\n var texture = this.createTexture(\n this.gl, textureImageSource.width, textureImageSource.height, textureImageSource);\n this.textureCache[uniqueId] = texture;\n return texture;\n }\n },\n\n /**\n * Clear out cached resources related to a source image that has been\n * filtered previously.\n *\n * @param {String} cacheKey The cache key provided when the source image was filtered.\n */\n evictCachesForKey: function(cacheKey) {\n if (this.textureCache[cacheKey]) {\n this.gl.deleteTexture(this.textureCache[cacheKey]);\n delete this.textureCache[cacheKey];\n }\n },\n\n copyGLTo2D: copyGLTo2DDrawImage,\n\n /**\n * Attempt to extract GPU information strings from a WebGL context.\n *\n * Useful information when debugging or blacklisting specific GPUs.\n *\n * @returns {Object} A GPU info object with renderer and vendor strings.\n */\n captureGPUInfo: function() {\n if (this.gpuInfo) {\n return this.gpuInfo;\n }\n var gl = this.gl, gpuInfo = { renderer: '', vendor: '' };\n if (!gl) {\n return gpuInfo;\n }\n var ext = gl.getExtension('WEBGL_debug_renderer_info');\n if (ext) {\n var renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);\n var vendor = gl.getParameter(ext.UNMASKED_VENDOR_WEBGL);\n if (renderer) {\n gpuInfo.renderer = renderer.toLowerCase();\n }\n if (vendor) {\n gpuInfo.vendor = vendor.toLowerCase();\n }\n }\n this.gpuInfo = gpuInfo;\n return gpuInfo;\n },\n };\n})();\n\nfunction resizeCanvasIfNeeded(pipelineState) {\n var targetCanvas = pipelineState.targetCanvas,\n width = targetCanvas.width, height = targetCanvas.height,\n dWidth = pipelineState.destinationWidth,\n dHeight = pipelineState.destinationHeight;\n\n if (width !== dWidth || height !== dHeight) {\n targetCanvas.width = dWidth;\n targetCanvas.height = dHeight;\n }\n}\n\n/**\n * Copy an input WebGL canvas on to an output 2D canvas.\n *\n * The WebGL canvas is assumed to be upside down, with the top-left pixel of the\n * desired output image appearing in the bottom-left corner of the WebGL canvas.\n *\n * @param {WebGLRenderingContext} sourceContext The WebGL context to copy from.\n * @param {HTMLCanvasElement} targetCanvas The 2D target canvas to copy on to.\n * @param {Object} pipelineState The 2D target canvas to copy on to.\n */\nfunction copyGLTo2DDrawImage(gl, pipelineState) {\n var glCanvas = gl.canvas, targetCanvas = pipelineState.targetCanvas,\n ctx = targetCanvas.getContext('2d');\n ctx.translate(0, targetCanvas.height); // move it down again\n ctx.scale(1, -1); // vertical flip\n // where is my image on the big glcanvas?\n var sourceY = glCanvas.height - targetCanvas.height;\n ctx.drawImage(glCanvas, 0, sourceY, targetCanvas.width, targetCanvas.height, 0, 0,\n targetCanvas.width, targetCanvas.height);\n}\n\n/**\n * Copy an input WebGL canvas on to an output 2D canvas using 2d canvas' putImageData\n * API. Measurably faster than using ctx.drawImage in Firefox (version 54 on OSX Sierra).\n *\n * @param {WebGLRenderingContext} sourceContext The WebGL context to copy from.\n * @param {HTMLCanvasElement} targetCanvas The 2D target canvas to copy on to.\n * @param {Object} pipelineState The 2D target canvas to copy on to.\n */\nfunction copyGLTo2DPutImageData(gl, pipelineState) {\n var targetCanvas = pipelineState.targetCanvas, ctx = targetCanvas.getContext('2d'),\n dWidth = pipelineState.destinationWidth,\n dHeight = pipelineState.destinationHeight,\n numBytes = dWidth * dHeight * 4;\n\n // eslint-disable-next-line no-undef\n var u8 = new Uint8Array(this.imageBuffer, 0, numBytes);\n // eslint-disable-next-line no-undef\n var u8Clamped = new Uint8ClampedArray(this.imageBuffer, 0, numBytes);\n\n gl.readPixels(0, 0, dWidth, dHeight, gl.RGBA, gl.UNSIGNED_BYTE, u8);\n var imgData = new ImageData(u8Clamped, dWidth, dHeight);\n ctx.putImageData(imgData, 0, 0);\n}\n\n\n(function() {\n\n 'use strict';\n\n var noop = function() {};\n\n fabric.Canvas2dFilterBackend = Canvas2dFilterBackend;\n\n /**\n * Canvas 2D filter backend.\n */\n function Canvas2dFilterBackend() {};\n\n Canvas2dFilterBackend.prototype = /** @lends fabric.Canvas2dFilterBackend.prototype */ {\n evictCachesForKey: noop,\n dispose: noop,\n clearWebGLCaches: noop,\n\n /**\n * Experimental. This object is a sort of repository of help layers used to avoid\n * of recreating them during frequent filtering. If you are previewing a filter with\n * a slider you probably do not want to create help layers every filter step.\n * in this object there will be appended some canvases, created once, resized sometimes\n * cleared never. Clearing is left to the developer.\n **/\n resources: {\n\n },\n\n /**\n * Apply a set of filters against a source image and draw the filtered output\n * to the provided destination canvas.\n *\n * @param {EnhancedFilter} filters The filter to apply.\n * @param {HTMLImageElement|HTMLCanvasElement} sourceElement The source to be filtered.\n * @param {Number} sourceWidth The width of the source input.\n * @param {Number} sourceHeight The height of the source input.\n * @param {HTMLCanvasElement} targetCanvas The destination for filtered output to be drawn.\n */\n applyFilters: function(filters, sourceElement, sourceWidth, sourceHeight, targetCanvas) {\n var ctx = targetCanvas.getContext('2d');\n ctx.drawImage(sourceElement, 0, 0, sourceWidth, sourceHeight);\n var imageData = ctx.getImageData(0, 0, sourceWidth, sourceHeight);\n var originalImageData = ctx.getImageData(0, 0, sourceWidth, sourceHeight);\n var pipelineState = {\n sourceWidth: sourceWidth,\n sourceHeight: sourceHeight,\n imageData: imageData,\n originalEl: sourceElement,\n originalImageData: originalImageData,\n canvasEl: targetCanvas,\n ctx: ctx,\n filterBackend: this,\n };\n filters.forEach(function(filter) { filter.applyTo(pipelineState); });\n if (pipelineState.imageData.width !== sourceWidth || pipelineState.imageData.height !== sourceHeight) {\n targetCanvas.width = pipelineState.imageData.width;\n targetCanvas.height = pipelineState.imageData.height;\n }\n ctx.putImageData(pipelineState.imageData, 0, 0);\n return pipelineState;\n },\n\n };\n})();\n\n\n/**\n * @namespace fabric.Image.filters\n * @memberOf fabric.Image\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#image_filters}\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n */\nfabric.Image = fabric.Image || { };\nfabric.Image.filters = fabric.Image.filters || { };\n\n/**\n * Root filter class from which all filter classes inherit from\n * @class fabric.Image.filters.BaseFilter\n * @memberOf fabric.Image.filters\n */\nfabric.Image.filters.BaseFilter = fabric.util.createClass(/** @lends fabric.Image.filters.BaseFilter.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'BaseFilter',\n\n /**\n * Array of attributes to send with buffers. do not modify\n * @private\n */\n\n vertexSource: 'attribute vec2 aPosition;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vTexCoord = aPosition;\\n' +\n 'gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);\\n' +\n '}',\n\n fragmentSource: 'precision highp float;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'void main() {\\n' +\n 'gl_FragColor = texture2D(uTexture, vTexCoord);\\n' +\n '}',\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n */\n initialize: function(options) {\n if (options) {\n this.setOptions(options);\n }\n },\n\n /**\n * Sets filter's properties from options\n * @param {Object} [options] Options object\n */\n setOptions: function(options) {\n for (var prop in options) {\n this[prop] = options[prop];\n }\n },\n\n /**\n * Compile this filter's shader program.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context to use for shader compilation.\n * @param {String} fragmentSource fragmentShader source for compilation\n * @param {String} vertexSource vertexShader source for compilation\n */\n createProgram: function(gl, fragmentSource, vertexSource) {\n fragmentSource = fragmentSource || this.fragmentSource;\n vertexSource = vertexSource || this.vertexSource;\n if (fabric.webGlPrecision !== 'highp'){\n fragmentSource = fragmentSource.replace(\n /precision highp float/g,\n 'precision ' + fabric.webGlPrecision + ' float'\n );\n }\n var vertexShader = gl.createShader(gl.VERTEX_SHADER);\n gl.shaderSource(vertexShader, vertexSource);\n gl.compileShader(vertexShader);\n if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {\n throw new Error(\n // eslint-disable-next-line prefer-template\n 'Vertex shader compile error for ' + this.type + ': ' +\n gl.getShaderInfoLog(vertexShader)\n );\n }\n\n var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);\n gl.shaderSource(fragmentShader, fragmentSource);\n gl.compileShader(fragmentShader);\n if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {\n throw new Error(\n // eslint-disable-next-line prefer-template\n 'Fragment shader compile error for ' + this.type + ': ' +\n gl.getShaderInfoLog(fragmentShader)\n );\n }\n\n var program = gl.createProgram();\n gl.attachShader(program, vertexShader);\n gl.attachShader(program, fragmentShader);\n gl.linkProgram(program);\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n throw new Error(\n // eslint-disable-next-line prefer-template\n 'Shader link error for \"${this.type}\" ' +\n gl.getProgramInfoLog(program)\n );\n }\n\n var attributeLocations = this.getAttributeLocations(gl, program);\n var uniformLocations = this.getUniformLocations(gl, program) || { };\n uniformLocations.uStepW = gl.getUniformLocation(program, 'uStepW');\n uniformLocations.uStepH = gl.getUniformLocation(program, 'uStepH');\n return {\n program: program,\n attributeLocations: attributeLocations,\n uniformLocations: uniformLocations\n };\n },\n\n /**\n * Return a map of attribute names to WebGLAttributeLocation objects.\n *\n * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n * @param {WebGLShaderProgram} program The shader program from which to take attribute locations.\n * @returns {Object} A map of attribute names to attribute locations.\n */\n getAttributeLocations: function(gl, program) {\n return {\n aPosition: gl.getAttribLocation(program, 'aPosition'),\n };\n },\n\n /**\n * Return a map of uniform names to WebGLUniformLocation objects.\n *\n * Intended to be overridden by subclasses.\n *\n * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n * @param {WebGLShaderProgram} program The shader program from which to take uniform locations.\n * @returns {Object} A map of uniform names to uniform locations.\n */\n getUniformLocations: function (/* gl, program */) {\n // in case i do not need any special uniform i need to return an empty object\n return { };\n },\n\n /**\n * Send attribute data from this filter to its shader program on the GPU.\n *\n * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n * @param {Object} attributeLocations A map of shader attribute names to their locations.\n */\n sendAttributeData: function(gl, attributeLocations, aPositionData) {\n var attributeLocation = attributeLocations.aPosition;\n var buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.enableVertexAttribArray(attributeLocation);\n gl.vertexAttribPointer(attributeLocation, 2, gl.FLOAT, false, 0, 0);\n gl.bufferData(gl.ARRAY_BUFFER, aPositionData, gl.STATIC_DRAW);\n },\n\n _setupFrameBuffer: function(options) {\n var gl = options.context, width, height;\n if (options.passes > 1) {\n width = options.destinationWidth;\n height = options.destinationHeight;\n if (options.sourceWidth !== width || options.sourceHeight !== height) {\n gl.deleteTexture(options.targetTexture);\n options.targetTexture = options.filterBackend.createTexture(gl, width, height);\n }\n gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D,\n options.targetTexture, 0);\n }\n else {\n // draw last filter on canvas and not to framebuffer.\n gl.bindFramebuffer(gl.FRAMEBUFFER, null);\n gl.finish();\n }\n },\n\n _swapTextures: function(options) {\n options.passes--;\n options.pass++;\n var temp = options.targetTexture;\n options.targetTexture = options.sourceTexture;\n options.sourceTexture = temp;\n },\n\n /**\n * Generic isNeutral implementation for one parameter based filters.\n * Used only in image applyFilters to discard filters that will not have an effect\n * on the image\n * Other filters may need their own version ( ColorMatrix, HueRotation, gamma, ComposedFilter )\n * @param {Object} options\n **/\n isNeutralState: function(/* options */) {\n var main = this.mainParameter,\n _class = fabric.Image.filters[this.type].prototype;\n if (main) {\n if (Array.isArray(_class[main])) {\n for (var i = _class[main].length; i--;) {\n if (this[main][i] !== _class[main][i]) {\n return false;\n }\n }\n return true;\n }\n else {\n return _class[main] === this[main];\n }\n }\n else {\n return false;\n }\n },\n\n /**\n * Apply this filter to the input image data provided.\n *\n * Determines whether to use WebGL or Canvas2D based on the options.webgl flag.\n *\n * @param {Object} options\n * @param {Number} options.passes The number of filters remaining to be executed\n * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n applyTo: function(options) {\n if (options.webgl) {\n this._setupFrameBuffer(options);\n this.applyToWebGL(options);\n this._swapTextures(options);\n }\n else {\n this.applyTo2d(options);\n }\n },\n\n /**\n * Retrieves the cached shader.\n * @param {Object} options\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n retrieveShader: function(options) {\n if (!options.programCache.hasOwnProperty(this.type)) {\n options.programCache[this.type] = this.createProgram(options.context);\n }\n return options.programCache[this.type];\n },\n\n /**\n * Apply this filter using webgl.\n *\n * @param {Object} options\n * @param {Number} options.passes The number of filters remaining to be executed\n * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n * @param {WebGLTexture} options.originalTexture The texture of the original input image.\n * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n applyToWebGL: function(options) {\n var gl = options.context;\n var shader = this.retrieveShader(options);\n if (options.pass === 0 && options.originalTexture) {\n gl.bindTexture(gl.TEXTURE_2D, options.originalTexture);\n }\n else {\n gl.bindTexture(gl.TEXTURE_2D, options.sourceTexture);\n }\n gl.useProgram(shader.program);\n this.sendAttributeData(gl, shader.attributeLocations, options.aPosition);\n\n gl.uniform1f(shader.uniformLocations.uStepW, 1 / options.sourceWidth);\n gl.uniform1f(shader.uniformLocations.uStepH, 1 / options.sourceHeight);\n\n this.sendUniformData(gl, shader.uniformLocations);\n gl.viewport(0, 0, options.destinationWidth, options.destinationHeight);\n gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n },\n\n bindAdditionalTexture: function(gl, texture, textureUnit) {\n gl.activeTexture(textureUnit);\n gl.bindTexture(gl.TEXTURE_2D, texture);\n // reset active texture to 0 as usual\n gl.activeTexture(gl.TEXTURE0);\n },\n\n unbindAdditionalTexture: function(gl, textureUnit) {\n gl.activeTexture(textureUnit);\n gl.bindTexture(gl.TEXTURE_2D, null);\n gl.activeTexture(gl.TEXTURE0);\n },\n\n getMainParameter: function() {\n return this[this.mainParameter];\n },\n\n setMainParameter: function(value) {\n this[this.mainParameter] = value;\n },\n\n /**\n * Send uniform data from this filter to its shader program on the GPU.\n *\n * Intended to be overridden by subclasses.\n *\n * @param {WebGLRenderingContext} gl The canvas context used to compile the shader program.\n * @param {Object} uniformLocations A map of shader uniform names to their locations.\n */\n sendUniformData: function(/* gl, uniformLocations */) {\n // Intentionally left blank. Override me in subclasses.\n },\n\n /**\n * If needed by a 2d filter, this functions can create an helper canvas to be used\n * remember that options.targetCanvas is available for use till end of chain.\n */\n createHelpLayer: function(options) {\n if (!options.helpLayer) {\n var helpLayer = document.createElement('canvas');\n helpLayer.width = options.sourceWidth;\n helpLayer.height = options.sourceHeight;\n options.helpLayer = helpLayer;\n }\n },\n\n /**\n * Returns object representation of an instance\n * @return {Object} Object representation of an instance\n */\n toObject: function() {\n var object = { type: this.type }, mainP = this.mainParameter;\n if (mainP) {\n object[mainP] = this[mainP];\n }\n return object;\n },\n\n /**\n * Returns a JSON representation of an instance\n * @return {Object} JSON\n */\n toJSON: function() {\n // delegate, not alias\n return this.toObject();\n }\n});\n\nfabric.Image.filters.BaseFilter.fromObject = function(object, callback) {\n var filter = new fabric.Image.filters[object.type](object);\n callback && callback(filter);\n return filter;\n};\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Color Matrix filter class\n * @class fabric.Image.filters.ColorMatrix\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.ColorMatrix#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @see {@Link http://www.webwasp.co.uk/tutorials/219/Color_Matrix_Filter.php}\n * @see {@Link http://phoboslab.org/log/2013/11/fast-image-filters-with-webgl}\n * @example Kodachrome filter\n * var filter = new fabric.Image.filters.ColorMatrix({\n * matrix: [\n 1.1285582396593525, -0.3967382283601348, -0.03992559172921793, 0, 63.72958762196502,\n -0.16404339962244616, 1.0835251566291304, -0.05498805115633132, 0, 24.732407896706203,\n -0.16786010706155763, -0.5603416277695248, 1.6014850761964943, 0, 35.62982807460946,\n 0, 0, 0, 1, 0\n ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.ColorMatrix = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.ColorMatrix.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'ColorMatrix',\n\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'uniform mat4 uColorMatrix;\\n' +\n 'uniform vec4 uConstants;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'color *= uColorMatrix;\\n' +\n 'color += uConstants;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n\n /**\n * Colormatrix for pixels.\n * array of 20 floats. Numbers in positions 4, 9, 14, 19 loose meaning\n * outside the -1, 1 range.\n * 0.0039215686 is the part of 1 that get translated to 1 in 2d\n * @param {Array} matrix array of 20 numbers.\n * @default\n */\n matrix: [\n 1, 0, 0, 0, 0,\n 0, 1, 0, 0, 0,\n 0, 0, 1, 0, 0,\n 0, 0, 0, 1, 0\n ],\n\n mainParameter: 'matrix',\n\n /**\n * Lock the colormatrix on the color part, skipping alpha, mainly for non webgl scenario\n * to save some calculation\n * @type Boolean\n * @default true\n */\n colorsOnly: true,\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n */\n initialize: function(options) {\n this.callSuper('initialize', options);\n // create a new array instead mutating the prototype with push\n this.matrix = this.matrix.slice(0);\n },\n\n /**\n * Apply the ColorMatrix operation to a Uint8Array representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8Array to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n data = imageData.data,\n iLen = data.length,\n m = this.matrix,\n r, g, b, a, i, colorsOnly = this.colorsOnly;\n\n for (i = 0; i < iLen; i += 4) {\n r = data[i];\n g = data[i + 1];\n b = data[i + 2];\n if (colorsOnly) {\n data[i] = r * m[0] + g * m[1] + b * m[2] + m[4] * 255;\n data[i + 1] = r * m[5] + g * m[6] + b * m[7] + m[9] * 255;\n data[i + 2] = r * m[10] + g * m[11] + b * m[12] + m[14] * 255;\n }\n else {\n a = data[i + 3];\n data[i] = r * m[0] + g * m[1] + b * m[2] + a * m[3] + m[4] * 255;\n data[i + 1] = r * m[5] + g * m[6] + b * m[7] + a * m[8] + m[9] * 255;\n data[i + 2] = r * m[10] + g * m[11] + b * m[12] + a * m[13] + m[14] * 255;\n data[i + 3] = r * m[15] + g * m[16] + b * m[17] + a * m[18] + m[19] * 255;\n }\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uColorMatrix: gl.getUniformLocation(program, 'uColorMatrix'),\n uConstants: gl.getUniformLocation(program, 'uConstants'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n var m = this.matrix,\n matrix = [\n m[0], m[1], m[2], m[3],\n m[5], m[6], m[7], m[8],\n m[10], m[11], m[12], m[13],\n m[15], m[16], m[17], m[18]\n ],\n constants = [m[4], m[9], m[14], m[19]];\n gl.uniformMatrix4fv(uniformLocations.uColorMatrix, false, matrix);\n gl.uniform4fv(uniformLocations.uConstants, constants);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] function to invoke after filter creation\n * @return {fabric.Image.filters.ColorMatrix} Instance of fabric.Image.filters.ColorMatrix\n */\n fabric.Image.filters.ColorMatrix.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Brightness filter class\n * @class fabric.Image.filters.Brightness\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Brightness#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Brightness({\n * brightness: 0.05\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.Brightness = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Brightness.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Brightness',\n\n /**\n * Fragment source for the brightness program\n */\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uBrightness;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'color.rgb += uBrightness;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n\n /**\n * Brightness value, from -1 to 1.\n * translated to -255 to 255 for 2d\n * 0.0039215686 is the part of 1 that get translated to 1 in 2d\n * @param {Number} brightness\n * @default\n */\n brightness: 0,\n\n /**\n * Describe the property that is the filter parameter\n * @param {String} m\n * @default\n */\n mainParameter: 'brightness',\n\n /**\n * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n if (this.brightness === 0) {\n return;\n }\n var imageData = options.imageData,\n data = imageData.data, i, len = data.length,\n brightness = Math.round(this.brightness * 255);\n for (i = 0; i < len; i += 4) {\n data[i] = data[i] + brightness;\n data[i + 1] = data[i + 1] + brightness;\n data[i + 2] = data[i + 2] + brightness;\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uBrightness: gl.getUniformLocation(program, 'uBrightness'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1f(uniformLocations.uBrightness, this.brightness);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Brightness} Instance of fabric.Image.filters.Brightness\n */\n fabric.Image.filters.Brightness.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend,\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Adapted from html5rocks article\n * @class fabric.Image.filters.Convolute\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Convolute#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example Sharpen filter\n * var filter = new fabric.Image.filters.Convolute({\n * matrix: [ 0, -1, 0,\n * -1, 5, -1,\n * 0, -1, 0 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n * @example Blur filter\n * var filter = new fabric.Image.filters.Convolute({\n * matrix: [ 1/9, 1/9, 1/9,\n * 1/9, 1/9, 1/9,\n * 1/9, 1/9, 1/9 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n * @example Emboss filter\n * var filter = new fabric.Image.filters.Convolute({\n * matrix: [ 1, 1, 1,\n * 1, 0.7, -1,\n * -1, -1, -1 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n * @example Emboss filter with opaqueness\n * var filter = new fabric.Image.filters.Convolute({\n * opaque: true,\n * matrix: [ 1, 1, 1,\n * 1, 0.7, -1,\n * -1, -1, -1 ]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\n filters.Convolute = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Convolute.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Convolute',\n\n /*\n * Opaque value (true/false)\n */\n opaque: false,\n\n /*\n * matrix for the filter, max 9x9\n */\n matrix: [0, 0, 0, 0, 1, 0, 0, 0, 0],\n\n /**\n * Fragment source for the brightness program\n */\n fragmentSource: {\n Convolute_3_1: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[9];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 0);\\n' +\n 'for (float h = 0.0; h < 3.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 3.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 1), uStepH * (h - 1));\\n' +\n 'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 3.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n Convolute_3_0: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[9];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 1);\\n' +\n 'for (float h = 0.0; h < 3.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 3.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 1.0), uStepH * (h - 1.0));\\n' +\n 'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 3.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n 'gl_FragColor = color;\\n' +\n 'gl_FragColor.a = alpha;\\n' +\n '}',\n Convolute_5_1: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[25];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 0);\\n' +\n 'for (float h = 0.0; h < 5.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 5.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 2.0), uStepH * (h - 2.0));\\n' +\n 'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 5.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n Convolute_5_0: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[25];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 1);\\n' +\n 'for (float h = 0.0; h < 5.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 5.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 2.0), uStepH * (h - 2.0));\\n' +\n 'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 5.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n 'gl_FragColor = color;\\n' +\n 'gl_FragColor.a = alpha;\\n' +\n '}',\n Convolute_7_1: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[49];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 0);\\n' +\n 'for (float h = 0.0; h < 7.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 7.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 3.0), uStepH * (h - 3.0));\\n' +\n 'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 7.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n Convolute_7_0: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[49];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 1);\\n' +\n 'for (float h = 0.0; h < 7.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 7.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 3.0), uStepH * (h - 3.0));\\n' +\n 'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 7.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n 'gl_FragColor = color;\\n' +\n 'gl_FragColor.a = alpha;\\n' +\n '}',\n Convolute_9_1: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[81];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 0);\\n' +\n 'for (float h = 0.0; h < 9.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 9.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 4.0), uStepH * (h - 4.0));\\n' +\n 'color += texture2D(uTexture, vTexCoord + matrixPos) * uMatrix[int(h * 9.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n Convolute_9_0: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uMatrix[81];\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0, 0, 0, 1);\\n' +\n 'for (float h = 0.0; h < 9.0; h+=1.0) {\\n' +\n 'for (float w = 0.0; w < 9.0; w+=1.0) {\\n' +\n 'vec2 matrixPos = vec2(uStepW * (w - 4.0), uStepH * (h - 4.0));\\n' +\n 'color.rgb += texture2D(uTexture, vTexCoord + matrixPos).rgb * uMatrix[int(h * 9.0 + w)];\\n' +\n '}\\n' +\n '}\\n' +\n 'float alpha = texture2D(uTexture, vTexCoord).a;\\n' +\n 'gl_FragColor = color;\\n' +\n 'gl_FragColor.a = alpha;\\n' +\n '}',\n },\n\n /**\n * Constructor\n * @memberOf fabric.Image.filters.Convolute.prototype\n * @param {Object} [options] Options object\n * @param {Boolean} [options.opaque=false] Opaque value (true/false)\n * @param {Array} [options.matrix] Filter matrix\n */\n\n\n /**\n * Retrieves the cached shader.\n * @param {Object} options\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n retrieveShader: function(options) {\n var size = Math.sqrt(this.matrix.length);\n var cacheKey = this.type + '_' + size + '_' + (this.opaque ? 1 : 0);\n var shaderSource = this.fragmentSource[cacheKey];\n if (!options.programCache.hasOwnProperty(cacheKey)) {\n options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n }\n return options.programCache[cacheKey];\n },\n\n /**\n * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n data = imageData.data,\n weights = this.matrix,\n side = Math.round(Math.sqrt(weights.length)),\n halfSide = Math.floor(side / 2),\n sw = imageData.width,\n sh = imageData.height,\n output = options.ctx.createImageData(sw, sh),\n dst = output.data,\n // go through the destination image pixels\n alphaFac = this.opaque ? 1 : 0,\n r, g, b, a, dstOff,\n scx, scy, srcOff, wt,\n x, y, cx, cy;\n\n for (y = 0; y < sh; y++) {\n for (x = 0; x < sw; x++) {\n dstOff = (y * sw + x) * 4;\n // calculate the weighed sum of the source image pixels that\n // fall under the convolution matrix\n r = 0; g = 0; b = 0; a = 0;\n\n for (cy = 0; cy < side; cy++) {\n for (cx = 0; cx < side; cx++) {\n scy = y + cy - halfSide;\n scx = x + cx - halfSide;\n\n // eslint-disable-next-line max-depth\n if (scy < 0 || scy >= sh || scx < 0 || scx >= sw) {\n continue;\n }\n\n srcOff = (scy * sw + scx) * 4;\n wt = weights[cy * side + cx];\n\n r += data[srcOff] * wt;\n g += data[srcOff + 1] * wt;\n b += data[srcOff + 2] * wt;\n // eslint-disable-next-line max-depth\n if (!alphaFac) {\n a += data[srcOff + 3] * wt;\n }\n }\n }\n dst[dstOff] = r;\n dst[dstOff + 1] = g;\n dst[dstOff + 2] = b;\n if (!alphaFac) {\n dst[dstOff + 3] = a;\n }\n else {\n dst[dstOff + 3] = data[dstOff + 3];\n }\n }\n }\n options.imageData = output;\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uMatrix: gl.getUniformLocation(program, 'uMatrix'),\n uOpaque: gl.getUniformLocation(program, 'uOpaque'),\n uHalfSize: gl.getUniformLocation(program, 'uHalfSize'),\n uSize: gl.getUniformLocation(program, 'uSize'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1fv(uniformLocations.uMatrix, this.matrix);\n },\n\n /**\n * Returns object representation of an instance\n * @return {Object} Object representation of an instance\n */\n toObject: function() {\n return extend(this.callSuper('toObject'), {\n opaque: this.opaque,\n matrix: this.matrix\n });\n }\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Convolute} Instance of fabric.Image.filters.Convolute\n */\n fabric.Image.filters.Convolute.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Grayscale image filter class\n * @class fabric.Image.filters.Grayscale\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Grayscale();\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.Grayscale = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Grayscale.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Grayscale',\n\n fragmentSource: {\n average: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'float average = (color.r + color.b + color.g) / 3.0;\\n' +\n 'gl_FragColor = vec4(average, average, average, color.a);\\n' +\n '}',\n lightness: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform int uMode;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 col = texture2D(uTexture, vTexCoord);\\n' +\n 'float average = (max(max(col.r, col.g),col.b) + min(min(col.r, col.g),col.b)) / 2.0;\\n' +\n 'gl_FragColor = vec4(average, average, average, col.a);\\n' +\n '}',\n luminosity: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform int uMode;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 col = texture2D(uTexture, vTexCoord);\\n' +\n 'float average = 0.21 * col.r + 0.72 * col.g + 0.07 * col.b;\\n' +\n 'gl_FragColor = vec4(average, average, average, col.a);\\n' +\n '}',\n },\n\n\n /**\n * Grayscale mode, between 'average', 'lightness', 'luminosity'\n * @param {String} type\n * @default\n */\n mode: 'average',\n\n mainParameter: 'mode',\n\n /**\n * Apply the Grayscale operation to a Uint8Array representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8Array to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n data = imageData.data, i,\n len = data.length, value,\n mode = this.mode;\n for (i = 0; i < len; i += 4) {\n if (mode === 'average') {\n value = (data[i] + data[i + 1] + data[i + 2]) / 3;\n }\n else if (mode === 'lightness') {\n value = (Math.min(data[i], data[i + 1], data[i + 2]) +\n Math.max(data[i], data[i + 1], data[i + 2])) / 2;\n }\n else if (mode === 'luminosity') {\n value = 0.21 * data[i] + 0.72 * data[i + 1] + 0.07 * data[i + 2];\n }\n data[i] = value;\n data[i + 1] = value;\n data[i + 2] = value;\n }\n },\n\n /**\n * Retrieves the cached shader.\n * @param {Object} options\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n retrieveShader: function(options) {\n var cacheKey = this.type + '_' + this.mode;\n if (!options.programCache.hasOwnProperty(cacheKey)) {\n var shaderSource = this.fragmentSource[this.mode];\n options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n }\n return options.programCache[cacheKey];\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uMode: gl.getUniformLocation(program, 'uMode'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n // default average mode.\n var mode = 1;\n gl.uniform1i(uniformLocations.uMode, mode);\n },\n\n /**\n * Grayscale filter isNeutralState implementation\n * The filter is never neutral\n * on the image\n **/\n isNeutralState: function() {\n return false;\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Grayscale} Instance of fabric.Image.filters.Grayscale\n */\n fabric.Image.filters.Grayscale.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Invert filter class\n * @class fabric.Image.filters.Invert\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Invert();\n * object.filters.push(filter);\n * object.applyFilters(canvas.renderAll.bind(canvas));\n */\n filters.Invert = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Invert.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Invert',\n\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform int uInvert;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'if (uInvert == 1) {\\n' +\n 'gl_FragColor = vec4(1.0 - color.r,1.0 -color.g,1.0 -color.b,color.a);\\n' +\n '} else {\\n' +\n 'gl_FragColor = color;\\n' +\n '}\\n' +\n '}',\n\n /**\n * Filter invert. if false, does nothing\n * @param {Boolean} invert\n * @default\n */\n invert: true,\n\n mainParameter: 'invert',\n\n /**\n * Apply the Invert operation to a Uint8Array representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8Array to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n data = imageData.data, i,\n len = data.length;\n for (i = 0; i < len; i += 4) {\n data[i] = 255 - data[i];\n data[i + 1] = 255 - data[i + 1];\n data[i + 2] = 255 - data[i + 2];\n }\n },\n\n /**\n * Invert filter isNeutralState implementation\n * Used only in image applyFilters to discard filters that will not have an effect\n * on the image\n * @param {Object} options\n **/\n isNeutralState: function() {\n return !this.invert;\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uInvert: gl.getUniformLocation(program, 'uInvert'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1i(uniformLocations.uInvert, this.invert);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Invert} Instance of fabric.Image.filters.Invert\n */\n fabric.Image.filters.Invert.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend,\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Noise filter class\n * @class fabric.Image.filters.Noise\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Noise#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Noise({\n * noise: 700\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\n filters.Noise = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Noise.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Noise',\n\n /**\n * Fragment source for the noise program\n */\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uStepH;\\n' +\n 'uniform float uNoise;\\n' +\n 'uniform float uSeed;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'float rand(vec2 co, float seed, float vScale) {\\n' +\n 'return fract(sin(dot(co.xy * vScale ,vec2(12.9898 , 78.233))) * 43758.5453 * (seed + 0.01) / 2.0);\\n' +\n '}\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'color.rgb += (0.5 - rand(vTexCoord, uSeed, 0.1 / uStepH)) * uNoise;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n\n /**\n * Describe the property that is the filter parameter\n * @param {String} m\n * @default\n */\n mainParameter: 'noise',\n\n /**\n * Noise value, from\n * @param {Number} noise\n * @default\n */\n noise: 0,\n\n /**\n * Apply the Brightness operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n if (this.noise === 0) {\n return;\n }\n var imageData = options.imageData,\n data = imageData.data, i, len = data.length,\n noise = this.noise, rand;\n\n for (i = 0, len = data.length; i < len; i += 4) {\n\n rand = (0.5 - Math.random()) * noise;\n\n data[i] += rand;\n data[i + 1] += rand;\n data[i + 2] += rand;\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uNoise: gl.getUniformLocation(program, 'uNoise'),\n uSeed: gl.getUniformLocation(program, 'uSeed'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1f(uniformLocations.uNoise, this.noise / 255);\n gl.uniform1f(uniformLocations.uSeed, Math.random());\n },\n\n /**\n * Returns object representation of an instance\n * @return {Object} Object representation of an instance\n */\n toObject: function() {\n return extend(this.callSuper('toObject'), {\n noise: this.noise\n });\n }\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Noise} Instance of fabric.Image.filters.Noise\n */\n fabric.Image.filters.Noise.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Pixelate filter class\n * @class fabric.Image.filters.Pixelate\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Pixelate#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Pixelate({\n * blocksize: 8\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.Pixelate = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Pixelate.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Pixelate',\n\n blocksize: 4,\n\n mainParameter: 'blocksize',\n\n /**\n * Fragment source for the Pixelate program\n */\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uBlocksize;\\n' +\n 'uniform float uStepW;\\n' +\n 'uniform float uStepH;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'float blockW = uBlocksize * uStepW;\\n' +\n 'float blockH = uBlocksize * uStepW;\\n' +\n 'int posX = int(vTexCoord.x / blockW);\\n' +\n 'int posY = int(vTexCoord.y / blockH);\\n' +\n 'float fposX = float(posX);\\n' +\n 'float fposY = float(posY);\\n' +\n 'vec2 squareCoords = vec2(fposX * blockW, fposY * blockH);\\n' +\n 'vec4 color = texture2D(uTexture, squareCoords);\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n\n /**\n * Apply the Pixelate operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n data = imageData.data,\n iLen = imageData.height,\n jLen = imageData.width,\n index, i, j, r, g, b, a,\n _i, _j, _iLen, _jLen;\n\n for (i = 0; i < iLen; i += this.blocksize) {\n for (j = 0; j < jLen; j += this.blocksize) {\n\n index = (i * 4) * jLen + (j * 4);\n\n r = data[index];\n g = data[index + 1];\n b = data[index + 2];\n a = data[index + 3];\n\n _iLen = Math.min(i + this.blocksize, iLen);\n _jLen = Math.min(j + this.blocksize, jLen);\n for (_i = i; _i < _iLen; _i++) {\n for (_j = j; _j < _jLen; _j++) {\n index = (_i * 4) * jLen + (_j * 4);\n data[index] = r;\n data[index + 1] = g;\n data[index + 2] = b;\n data[index + 3] = a;\n }\n }\n }\n }\n },\n\n /**\n * Indicate when the filter is not gonna apply changes to the image\n **/\n isNeutralState: function() {\n return this.blocksize === 1;\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uBlocksize: gl.getUniformLocation(program, 'uBlocksize'),\n uStepW: gl.getUniformLocation(program, 'uStepW'),\n uStepH: gl.getUniformLocation(program, 'uStepH'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1f(uniformLocations.uBlocksize, this.blocksize);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Pixelate} Instance of fabric.Image.filters.Pixelate\n */\n fabric.Image.filters.Pixelate.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n extend = fabric.util.object.extend,\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Remove white filter class\n * @class fabric.Image.filters.RemoveColor\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.RemoveColor#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.RemoveColor({\n * threshold: 0.2,\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\n filters.RemoveColor = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.RemoveColor.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'RemoveColor',\n\n /**\n * Color to remove, in any format understood by fabric.Color.\n * @param {String} type\n * @default\n */\n color: '#FFFFFF',\n\n /**\n * Fragment source for the brightness program\n */\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform vec4 uLow;\\n' +\n 'uniform vec4 uHigh;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'gl_FragColor = texture2D(uTexture, vTexCoord);\\n' +\n 'if(all(greaterThan(gl_FragColor.rgb,uLow.rgb)) && all(greaterThan(uHigh.rgb,gl_FragColor.rgb))) {\\n' +\n 'gl_FragColor.a = 0.0;\\n' +\n '}\\n' +\n '}',\n\n /**\n * distance to actual color, as value up or down from each r,g,b\n * between 0 and 1\n **/\n distance: 0.02,\n\n /**\n * For color to remove inside distance, use alpha channel for a smoother deletion\n * NOT IMPLEMENTED YET\n **/\n useAlpha: false,\n\n /**\n * Constructor\n * @memberOf fabric.Image.filters.RemoveWhite.prototype\n * @param {Object} [options] Options object\n * @param {Number} [options.color=#RRGGBB] Threshold value\n * @param {Number} [options.distance=10] Distance value\n */\n\n /**\n * Applies filter to canvas element\n * @param {Object} canvasEl Canvas element to apply filter to\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n data = imageData.data, i,\n distance = this.distance * 255,\n r, g, b,\n source = new fabric.Color(this.color).getSource(),\n lowC = [\n source[0] - distance,\n source[1] - distance,\n source[2] - distance,\n ],\n highC = [\n source[0] + distance,\n source[1] + distance,\n source[2] + distance,\n ];\n\n\n for (i = 0; i < data.length; i += 4) {\n r = data[i];\n g = data[i + 1];\n b = data[i + 2];\n\n if (r > lowC[0] &&\n g > lowC[1] &&\n b > lowC[2] &&\n r < highC[0] &&\n g < highC[1] &&\n b < highC[2]) {\n data[i + 3] = 0;\n }\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uLow: gl.getUniformLocation(program, 'uLow'),\n uHigh: gl.getUniformLocation(program, 'uHigh'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n var source = new fabric.Color(this.color).getSource(),\n distance = parseFloat(this.distance),\n lowC = [\n 0 + source[0] / 255 - distance,\n 0 + source[1] / 255 - distance,\n 0 + source[2] / 255 - distance,\n 1\n ],\n highC = [\n source[0] / 255 + distance,\n source[1] / 255 + distance,\n source[2] / 255 + distance,\n 1\n ];\n gl.uniform4fv(uniformLocations.uLow, lowC);\n gl.uniform4fv(uniformLocations.uHigh, highC);\n },\n\n /**\n * Returns object representation of an instance\n * @return {Object} Object representation of an instance\n */\n toObject: function() {\n return extend(this.callSuper('toObject'), {\n color: this.color,\n distance: this.distance\n });\n }\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.RemoveColor} Instance of fabric.Image.filters.RemoveWhite\n */\n fabric.Image.filters.RemoveColor.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n var matrices = {\n Brownie: [\n 0.59970,0.34553,-0.27082,0,0.186,\n -0.03770,0.86095,0.15059,0,-0.1449,\n 0.24113,-0.07441,0.44972,0,-0.02965,\n 0,0,0,1,0\n ],\n Vintage: [\n 0.62793,0.32021,-0.03965,0,0.03784,\n 0.02578,0.64411,0.03259,0,0.02926,\n 0.04660,-0.08512,0.52416,0,0.02023,\n 0,0,0,1,0\n ],\n Kodachrome: [\n 1.12855,-0.39673,-0.03992,0,0.24991,\n -0.16404,1.08352,-0.05498,0,0.09698,\n -0.16786,-0.56034,1.60148,0,0.13972,\n 0,0,0,1,0\n ],\n Technicolor: [\n 1.91252,-0.85453,-0.09155,0,0.04624,\n -0.30878,1.76589,-0.10601,0,-0.27589,\n -0.23110,-0.75018,1.84759,0,0.12137,\n 0,0,0,1,0\n ],\n Polaroid: [\n 1.438,-0.062,-0.062,0,0,\n -0.122,1.378,-0.122,0,0,\n -0.016,-0.016,1.483,0,0,\n 0,0,0,1,0\n ],\n Sepia: [\n 0.393, 0.769, 0.189, 0, 0,\n 0.349, 0.686, 0.168, 0, 0,\n 0.272, 0.534, 0.131, 0, 0,\n 0, 0, 0, 1, 0\n ],\n BlackWhite: [\n 1.5, 1.5, 1.5, 0, -1,\n 1.5, 1.5, 1.5, 0, -1,\n 1.5, 1.5, 1.5, 0, -1,\n 0, 0, 0, 1, 0,\n ]\n };\n\n for (var key in matrices) {\n filters[key] = createClass(filters.ColorMatrix, /** @lends fabric.Image.filters.Sepia.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: key,\n\n /**\n * Colormatrix for the effect\n * array of 20 floats. Numbers in positions 4, 9, 14, 19 loose meaning\n * outside the -1, 1 range.\n * @param {Array} matrix array of 20 numbers.\n * @default\n */\n matrix: matrices[key],\n\n /**\n * Lock the matrix export for this kind of static, parameter less filters.\n */\n mainParameter: false,\n /**\n * Lock the colormatrix on the color part, skipping alpha\n */\n colorsOnly: true,\n\n });\n fabric.Image.filters[key].fromObject = fabric.Image.filters.BaseFilter.fromObject;\n }\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n 'use strict';\n\n var fabric = global.fabric,\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Color Blend filter class\n * @class fabric.Image.filter.BlendColor\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @example\n * var filter = new fabric.Image.filters.BlendColor({\n * color: '#000',\n * mode: 'multiply'\n * });\n *\n * var filter = new fabric.Image.filters.BlendImage({\n * image: fabricImageObject,\n * mode: 'multiply',\n * alpha: 0.5\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\n\n filters.BlendColor = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blend.prototype */ {\n type: 'BlendColor',\n\n /**\n * Color to make the blend operation with. default to a reddish color since black or white\n * gives always strong result.\n * @type String\n * @default\n **/\n color: '#F95C63',\n\n /**\n * Blend mode for the filter: one of multiply, add, diff, screen, subtract,\n * darken, lighten, overlay, exclusion, tint.\n * @type String\n * @default\n **/\n mode: 'multiply',\n\n /**\n * alpha value. represent the strength of the blend color operation.\n * @type Number\n * @default\n **/\n alpha: 1,\n\n /**\n * Fragment source for the Multiply program\n */\n fragmentSource: {\n multiply: 'gl_FragColor.rgb *= uColor.rgb;\\n',\n screen: 'gl_FragColor.rgb = 1.0 - (1.0 - gl_FragColor.rgb) * (1.0 - uColor.rgb);\\n',\n add: 'gl_FragColor.rgb += uColor.rgb;\\n',\n diff: 'gl_FragColor.rgb = abs(gl_FragColor.rgb - uColor.rgb);\\n',\n subtract: 'gl_FragColor.rgb -= uColor.rgb;\\n',\n lighten: 'gl_FragColor.rgb = max(gl_FragColor.rgb, uColor.rgb);\\n',\n darken: 'gl_FragColor.rgb = min(gl_FragColor.rgb, uColor.rgb);\\n',\n exclusion: 'gl_FragColor.rgb += uColor.rgb - 2.0 * (uColor.rgb * gl_FragColor.rgb);\\n',\n overlay: 'if (uColor.r < 0.5) {\\n' +\n 'gl_FragColor.r *= 2.0 * uColor.r;\\n' +\n '} else {\\n' +\n 'gl_FragColor.r = 1.0 - 2.0 * (1.0 - gl_FragColor.r) * (1.0 - uColor.r);\\n' +\n '}\\n' +\n 'if (uColor.g < 0.5) {\\n' +\n 'gl_FragColor.g *= 2.0 * uColor.g;\\n' +\n '} else {\\n' +\n 'gl_FragColor.g = 1.0 - 2.0 * (1.0 - gl_FragColor.g) * (1.0 - uColor.g);\\n' +\n '}\\n' +\n 'if (uColor.b < 0.5) {\\n' +\n 'gl_FragColor.b *= 2.0 * uColor.b;\\n' +\n '} else {\\n' +\n 'gl_FragColor.b = 1.0 - 2.0 * (1.0 - gl_FragColor.b) * (1.0 - uColor.b);\\n' +\n '}\\n',\n tint: 'gl_FragColor.rgb *= (1.0 - uColor.a);\\n' +\n 'gl_FragColor.rgb += uColor.rgb;\\n',\n },\n\n /**\n * build the fragment source for the filters, joining the common part with\n * the specific one.\n * @param {String} mode the mode of the filter, a key of this.fragmentSource\n * @return {String} the source to be compiled\n * @private\n */\n buildSource: function(mode) {\n return 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform vec4 uColor;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'gl_FragColor = color;\\n' +\n 'if (color.a > 0.0) {\\n' +\n this.fragmentSource[mode] +\n '}\\n' +\n '}';\n },\n\n /**\n * Retrieves the cached shader.\n * @param {Object} options\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n retrieveShader: function(options) {\n var cacheKey = this.type + '_' + this.mode, shaderSource;\n if (!options.programCache.hasOwnProperty(cacheKey)) {\n shaderSource = this.buildSource(this.mode);\n options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n }\n return options.programCache[cacheKey];\n },\n\n /**\n * Apply the Blend operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n data = imageData.data, iLen = data.length,\n tr, tg, tb,\n r, g, b,\n source, alpha1 = 1 - this.alpha;\n\n source = new fabric.Color(this.color).getSource();\n tr = source[0] * this.alpha;\n tg = source[1] * this.alpha;\n tb = source[2] * this.alpha;\n\n for (var i = 0; i < iLen; i += 4) {\n\n r = data[i];\n g = data[i + 1];\n b = data[i + 2];\n\n switch (this.mode) {\n case 'multiply':\n data[i] = r * tr / 255;\n data[i + 1] = g * tg / 255;\n data[i + 2] = b * tb / 255;\n break;\n case 'screen':\n data[i] = 255 - (255 - r) * (255 - tr) / 255;\n data[i + 1] = 255 - (255 - g) * (255 - tg) / 255;\n data[i + 2] = 255 - (255 - b) * (255 - tb) / 255;\n break;\n case 'add':\n data[i] = r + tr;\n data[i + 1] = g + tg;\n data[i + 2] = b + tb;\n break;\n case 'diff':\n case 'difference':\n data[i] = Math.abs(r - tr);\n data[i + 1] = Math.abs(g - tg);\n data[i + 2] = Math.abs(b - tb);\n break;\n case 'subtract':\n data[i] = r - tr;\n data[i + 1] = g - tg;\n data[i + 2] = b - tb;\n break;\n case 'darken':\n data[i] = Math.min(r, tr);\n data[i + 1] = Math.min(g, tg);\n data[i + 2] = Math.min(b, tb);\n break;\n case 'lighten':\n data[i] = Math.max(r, tr);\n data[i + 1] = Math.max(g, tg);\n data[i + 2] = Math.max(b, tb);\n break;\n case 'overlay':\n data[i] = tr < 128 ? (2 * r * tr / 255) : (255 - 2 * (255 - r) * (255 - tr) / 255);\n data[i + 1] = tg < 128 ? (2 * g * tg / 255) : (255 - 2 * (255 - g) * (255 - tg) / 255);\n data[i + 2] = tb < 128 ? (2 * b * tb / 255) : (255 - 2 * (255 - b) * (255 - tb) / 255);\n break;\n case 'exclusion':\n data[i] = tr + r - ((2 * tr * r) / 255);\n data[i + 1] = tg + g - ((2 * tg * g) / 255);\n data[i + 2] = tb + b - ((2 * tb * b) / 255);\n break;\n case 'tint':\n data[i] = tr + r * alpha1;\n data[i + 1] = tg + g * alpha1;\n data[i + 2] = tb + b * alpha1;\n }\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uColor: gl.getUniformLocation(program, 'uColor'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n var source = new fabric.Color(this.color).getSource();\n source[0] = this.alpha * source[0] / 255;\n source[1] = this.alpha * source[1] / 255;\n source[2] = this.alpha * source[2] / 255;\n source[3] = this.alpha;\n gl.uniform4fv(uniformLocations.uColor, source);\n },\n\n /**\n * Returns object representation of an instance\n * @return {Object} Object representation of an instance\n */\n toObject: function() {\n return {\n type: this.type,\n color: this.color,\n mode: this.mode,\n alpha: this.alpha\n };\n }\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.BlendColor} Instance of fabric.Image.filters.BlendColor\n */\n fabric.Image.filters.BlendColor.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n 'use strict';\n\n var fabric = global.fabric,\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Image Blend filter class\n * @class fabric.Image.filter.BlendImage\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @example\n * var filter = new fabric.Image.filters.BlendColor({\n * color: '#000',\n * mode: 'multiply'\n * });\n *\n * var filter = new fabric.Image.filters.BlendImage({\n * image: fabricImageObject,\n * mode: 'multiply',\n * alpha: 0.5\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\n\n filters.BlendImage = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.BlendImage.prototype */ {\n type: 'BlendImage',\n\n /**\n * Color to make the blend operation with. default to a reddish color since black or white\n * gives always strong result.\n **/\n image: null,\n\n /**\n * Blend mode for the filter (one of \"multiply\", \"mask\")\n * @type String\n * @default\n **/\n mode: 'multiply',\n\n /**\n * alpha value. represent the strength of the blend image operation.\n * not implemented.\n **/\n alpha: 1,\n\n vertexSource: 'attribute vec2 aPosition;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'varying vec2 vTexCoord2;\\n' +\n 'uniform mat3 uTransformMatrix;\\n' +\n 'void main() {\\n' +\n 'vTexCoord = aPosition;\\n' +\n 'vTexCoord2 = (uTransformMatrix * vec3(aPosition, 1.0)).xy;\\n' +\n 'gl_Position = vec4(aPosition * 2.0 - 1.0, 0.0, 1.0);\\n' +\n '}',\n\n /**\n * Fragment source for the Multiply program\n */\n fragmentSource: {\n multiply: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform sampler2D uImage;\\n' +\n 'uniform vec4 uColor;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'varying vec2 vTexCoord2;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'vec4 color2 = texture2D(uImage, vTexCoord2);\\n' +\n 'color.rgba *= color2.rgba;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n mask: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform sampler2D uImage;\\n' +\n 'uniform vec4 uColor;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'varying vec2 vTexCoord2;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'vec4 color2 = texture2D(uImage, vTexCoord2);\\n' +\n 'color.a = color2.a;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n },\n\n /**\n * Retrieves the cached shader.\n * @param {Object} options\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n retrieveShader: function(options) {\n var cacheKey = this.type + '_' + this.mode;\n var shaderSource = this.fragmentSource[this.mode];\n if (!options.programCache.hasOwnProperty(cacheKey)) {\n options.programCache[cacheKey] = this.createProgram(options.context, shaderSource);\n }\n return options.programCache[cacheKey];\n },\n\n applyToWebGL: function(options) {\n // load texture to blend.\n var gl = options.context,\n texture = this.createTexture(options.filterBackend, this.image);\n this.bindAdditionalTexture(gl, texture, gl.TEXTURE1);\n this.callSuper('applyToWebGL', options);\n this.unbindAdditionalTexture(gl, gl.TEXTURE1);\n },\n\n createTexture: function(backend, image) {\n return backend.getCachedTexture(image.cacheKey, image._element);\n },\n\n /**\n * Calculate a transformMatrix to adapt the image to blend over\n * @param {Object} options\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n calculateMatrix: function() {\n var image = this.image,\n width = image._element.width,\n height = image._element.height;\n return [\n 1 / image.scaleX, 0, 0,\n 0, 1 / image.scaleY, 0,\n -image.left / width, -image.top / height, 1\n ];\n },\n\n /**\n * Apply the Blend operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n resources = options.filterBackend.resources,\n data = imageData.data, iLen = data.length,\n width = imageData.width,\n height = imageData.height,\n tr, tg, tb, ta,\n r, g, b, a,\n canvas1, context, image = this.image, blendData;\n\n if (!resources.blendImage) {\n resources.blendImage = fabric.util.createCanvasElement();\n }\n canvas1 = resources.blendImage;\n context = canvas1.getContext('2d');\n if (canvas1.width !== width || canvas1.height !== height) {\n canvas1.width = width;\n canvas1.height = height;\n }\n else {\n context.clearRect(0, 0, width, height);\n }\n context.setTransform(image.scaleX, 0, 0, image.scaleY, image.left, image.top);\n context.drawImage(image._element, 0, 0, width, height);\n blendData = context.getImageData(0, 0, width, height).data;\n for (var i = 0; i < iLen; i += 4) {\n\n r = data[i];\n g = data[i + 1];\n b = data[i + 2];\n a = data[i + 3];\n\n tr = blendData[i];\n tg = blendData[i + 1];\n tb = blendData[i + 2];\n ta = blendData[i + 3];\n\n switch (this.mode) {\n case 'multiply':\n data[i] = r * tr / 255;\n data[i + 1] = g * tg / 255;\n data[i + 2] = b * tb / 255;\n data[i + 3] = a * ta / 255;\n break;\n case 'mask':\n data[i + 3] = ta;\n break;\n }\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uTransformMatrix: gl.getUniformLocation(program, 'uTransformMatrix'),\n uImage: gl.getUniformLocation(program, 'uImage'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n var matrix = this.calculateMatrix();\n gl.uniform1i(uniformLocations.uImage, 1); // texture unit 1.\n gl.uniformMatrix3fv(uniformLocations.uTransformMatrix, false, matrix);\n },\n\n /**\n * Returns object representation of an instance\n * @return {Object} Object representation of an instance\n */\n toObject: function() {\n return {\n type: this.type,\n image: this.image && this.image.toObject(),\n mode: this.mode,\n alpha: this.alpha\n };\n }\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} callback to be invoked after filter creation\n * @return {fabric.Image.filters.BlendImage} Instance of fabric.Image.filters.BlendImage\n */\n fabric.Image.filters.BlendImage.fromObject = function(object, callback) {\n fabric.Image.fromObject(object.image, function(image) {\n var options = fabric.util.object.clone(object);\n options.image = image;\n callback(new fabric.Image.filters.BlendImage(options));\n });\n };\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }), pow = Math.pow, floor = Math.floor,\n sqrt = Math.sqrt, abs = Math.abs, round = Math.round, sin = Math.sin,\n ceil = Math.ceil,\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Resize image filter class\n * @class fabric.Image.filters.Resize\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Resize();\n * object.filters.push(filter);\n * object.applyFilters(canvas.renderAll.bind(canvas));\n */\n filters.Resize = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Resize.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Resize',\n\n /**\n * Resize type\n * for webgl resizeType is just lanczos, for canvas2d can be:\n * bilinear, hermite, sliceHack, lanczos.\n * @param {String} resizeType\n * @default\n */\n resizeType: 'hermite',\n\n /**\n * Scale factor for resizing, x axis\n * @param {Number} scaleX\n * @default\n */\n scaleX: 1,\n\n /**\n * Scale factor for resizing, y axis\n * @param {Number} scaleY\n * @default\n */\n scaleY: 1,\n\n /**\n * LanczosLobes parameter for lanczos filter, valid for resizeType lanczos\n * @param {Number} lanczosLobes\n * @default\n */\n lanczosLobes: 3,\n\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uDelta: gl.getUniformLocation(program, 'uDelta'),\n uTaps: gl.getUniformLocation(program, 'uTaps'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform2fv(uniformLocations.uDelta, this.horizontal ? [1 / this.width, 0] : [0, 1 / this.height]);\n gl.uniform1fv(uniformLocations.uTaps, this.taps);\n },\n\n /**\n * Retrieves the cached shader.\n * @param {Object} options\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n retrieveShader: function(options) {\n var filterWindow = this.getFilterWindow(), cacheKey = this.type + '_' + filterWindow;\n if (!options.programCache.hasOwnProperty(cacheKey)) {\n var fragmentShader = this.generateShader(filterWindow);\n options.programCache[cacheKey] = this.createProgram(options.context, fragmentShader);\n }\n return options.programCache[cacheKey];\n },\n\n getFilterWindow: function() {\n var scale = this.tempScale;\n return Math.ceil(this.lanczosLobes / scale);\n },\n\n getTaps: function() {\n var lobeFunction = this.lanczosCreate(this.lanczosLobes), scale = this.tempScale,\n filterWindow = this.getFilterWindow(), taps = new Array(filterWindow);\n for (var i = 1; i <= filterWindow; i++) {\n taps[i - 1] = lobeFunction(i * scale);\n }\n return taps;\n },\n\n /**\n * Generate vertex and shader sources from the necessary steps numbers\n * @param {Number} filterWindow\n */\n generateShader: function(filterWindow) {\n var offsets = new Array(filterWindow),\n fragmentShader = this.fragmentSourceTOP, filterWindow;\n\n for (var i = 1; i <= filterWindow; i++) {\n offsets[i - 1] = i + '.0 * uDelta';\n }\n\n fragmentShader += 'uniform float uTaps[' + filterWindow + '];\\n';\n fragmentShader += 'void main() {\\n';\n fragmentShader += ' vec4 color = texture2D(uTexture, vTexCoord);\\n';\n fragmentShader += ' float sum = 1.0;\\n';\n\n offsets.forEach(function(offset, i) {\n fragmentShader += ' color += texture2D(uTexture, vTexCoord + ' + offset + ') * uTaps[' + i + '];\\n';\n fragmentShader += ' color += texture2D(uTexture, vTexCoord - ' + offset + ') * uTaps[' + i + '];\\n';\n fragmentShader += ' sum += 2.0 * uTaps[' + i + '];\\n';\n });\n fragmentShader += ' gl_FragColor = color / sum;\\n';\n fragmentShader += '}';\n return fragmentShader;\n },\n\n fragmentSourceTOP: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform vec2 uDelta;\\n' +\n 'varying vec2 vTexCoord;\\n',\n\n /**\n * Apply the resize filter to the image\n * Determines whether to use WebGL or Canvas2D based on the options.webgl flag.\n *\n * @param {Object} options\n * @param {Number} options.passes The number of filters remaining to be executed\n * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n applyTo: function(options) {\n if (options.webgl) {\n options.passes++;\n this.width = options.sourceWidth;\n this.horizontal = true;\n this.dW = Math.round(this.width * this.scaleX);\n this.dH = options.sourceHeight;\n this.tempScale = this.dW / this.width;\n this.taps = this.getTaps();\n options.destinationWidth = this.dW;\n this._setupFrameBuffer(options);\n this.applyToWebGL(options);\n this._swapTextures(options);\n options.sourceWidth = options.destinationWidth;\n\n this.height = options.sourceHeight;\n this.horizontal = false;\n this.dH = Math.round(this.height * this.scaleY);\n this.tempScale = this.dH / this.height;\n this.taps = this.getTaps();\n options.destinationHeight = this.dH;\n this._setupFrameBuffer(options);\n this.applyToWebGL(options);\n this._swapTextures(options);\n options.sourceHeight = options.destinationHeight;\n }\n else {\n this.applyTo2d(options);\n }\n },\n\n isNeutralState: function() {\n return this.scaleX === 1 && this.scaleY === 1;\n },\n\n lanczosCreate: function(lobes) {\n return function(x) {\n if (x >= lobes || x <= -lobes) {\n return 0.0;\n }\n if (x < 1.19209290E-07 && x > -1.19209290E-07) {\n return 1.0;\n }\n x *= Math.PI;\n var xx = x / lobes;\n return (sin(x) / x) * sin(xx) / xx;\n };\n },\n\n /**\n * Applies filter to canvas element\n * @memberOf fabric.Image.filters.Resize.prototype\n * @param {Object} canvasEl Canvas element to apply filter to\n * @param {Number} scaleX\n * @param {Number} scaleY\n */\n applyTo2d: function(options) {\n var imageData = options.imageData,\n scaleX = this.scaleX,\n scaleY = this.scaleY;\n\n this.rcpScaleX = 1 / scaleX;\n this.rcpScaleY = 1 / scaleY;\n\n var oW = imageData.width, oH = imageData.height,\n dW = round(oW * scaleX), dH = round(oH * scaleY),\n newData;\n\n if (this.resizeType === 'sliceHack') {\n newData = this.sliceByTwo(options, oW, oH, dW, dH);\n }\n else if (this.resizeType === 'hermite') {\n newData = this.hermiteFastResize(options, oW, oH, dW, dH);\n }\n else if (this.resizeType === 'bilinear') {\n newData = this.bilinearFiltering(options, oW, oH, dW, dH);\n }\n else if (this.resizeType === 'lanczos') {\n newData = this.lanczosResize(options, oW, oH, dW, dH);\n }\n options.imageData = newData;\n },\n\n /**\n * Filter sliceByTwo\n * @param {Object} canvasEl Canvas element to apply filter to\n * @param {Number} oW Original Width\n * @param {Number} oH Original Height\n * @param {Number} dW Destination Width\n * @param {Number} dH Destination Height\n * @returns {ImageData}\n */\n sliceByTwo: function(options, oW, oH, dW, dH) {\n var imageData = options.imageData,\n mult = 0.5, doneW = false, doneH = false, stepW = oW * mult,\n stepH = oH * mult, resources = fabric.filterBackend.resources,\n tmpCanvas, ctx, sX = 0, sY = 0, dX = oW, dY = 0;\n if (!resources.sliceByTwo) {\n resources.sliceByTwo = document.createElement('canvas');\n }\n tmpCanvas = resources.sliceByTwo;\n if (tmpCanvas.width < oW * 1.5 || tmpCanvas.height < oH) {\n tmpCanvas.width = oW * 1.5;\n tmpCanvas.height = oH;\n }\n ctx = tmpCanvas.getContext('2d');\n ctx.clearRect(0, 0, oW * 1.5, oH);\n ctx.putImageData(imageData, 0, 0);\n\n dW = floor(dW);\n dH = floor(dH);\n\n while (!doneW || !doneH) {\n oW = stepW;\n oH = stepH;\n if (dW < floor(stepW * mult)) {\n stepW = floor(stepW * mult);\n }\n else {\n stepW = dW;\n doneW = true;\n }\n if (dH < floor(stepH * mult)) {\n stepH = floor(stepH * mult);\n }\n else {\n stepH = dH;\n doneH = true;\n }\n ctx.drawImage(tmpCanvas, sX, sY, oW, oH, dX, dY, stepW, stepH);\n sX = dX;\n sY = dY;\n dY += stepH;\n }\n return ctx.getImageData(sX, sY, dW, dH);\n },\n\n /**\n * Filter lanczosResize\n * @param {Object} canvasEl Canvas element to apply filter to\n * @param {Number} oW Original Width\n * @param {Number} oH Original Height\n * @param {Number} dW Destination Width\n * @param {Number} dH Destination Height\n * @returns {ImageData}\n */\n lanczosResize: function(options, oW, oH, dW, dH) {\n\n function process(u) {\n var v, i, weight, idx, a, red, green,\n blue, alpha, fX, fY;\n center.x = (u + 0.5) * ratioX;\n icenter.x = floor(center.x);\n for (v = 0; v < dH; v++) {\n center.y = (v + 0.5) * ratioY;\n icenter.y = floor(center.y);\n a = 0; red = 0; green = 0; blue = 0; alpha = 0;\n for (i = icenter.x - range2X; i <= icenter.x + range2X; i++) {\n if (i < 0 || i >= oW) {\n continue;\n }\n fX = floor(1000 * abs(i - center.x));\n if (!cacheLanc[fX]) {\n cacheLanc[fX] = { };\n }\n for (var j = icenter.y - range2Y; j <= icenter.y + range2Y; j++) {\n if (j < 0 || j >= oH) {\n continue;\n }\n fY = floor(1000 * abs(j - center.y));\n if (!cacheLanc[fX][fY]) {\n cacheLanc[fX][fY] = lanczos(sqrt(pow(fX * rcpRatioX, 2) + pow(fY * rcpRatioY, 2)) / 1000);\n }\n weight = cacheLanc[fX][fY];\n if (weight > 0) {\n idx = (j * oW + i) * 4;\n a += weight;\n red += weight * srcData[idx];\n green += weight * srcData[idx + 1];\n blue += weight * srcData[idx + 2];\n alpha += weight * srcData[idx + 3];\n }\n }\n }\n idx = (v * dW + u) * 4;\n destData[idx] = red / a;\n destData[idx + 1] = green / a;\n destData[idx + 2] = blue / a;\n destData[idx + 3] = alpha / a;\n }\n\n if (++u < dW) {\n return process(u);\n }\n else {\n return destImg;\n }\n }\n\n var srcData = options.imageData.data,\n destImg = options.ctx.createImageData(dW, dH),\n destData = destImg.data,\n lanczos = this.lanczosCreate(this.lanczosLobes),\n ratioX = this.rcpScaleX, ratioY = this.rcpScaleY,\n rcpRatioX = 2 / this.rcpScaleX, rcpRatioY = 2 / this.rcpScaleY,\n range2X = ceil(ratioX * this.lanczosLobes / 2),\n range2Y = ceil(ratioY * this.lanczosLobes / 2),\n cacheLanc = { }, center = { }, icenter = { };\n\n return process(0);\n },\n\n /**\n * bilinearFiltering\n * @param {Object} canvasEl Canvas element to apply filter to\n * @param {Number} oW Original Width\n * @param {Number} oH Original Height\n * @param {Number} dW Destination Width\n * @param {Number} dH Destination Height\n * @returns {ImageData}\n */\n bilinearFiltering: function(options, oW, oH, dW, dH) {\n var a, b, c, d, x, y, i, j, xDiff, yDiff, chnl,\n color, offset = 0, origPix, ratioX = this.rcpScaleX,\n ratioY = this.rcpScaleY,\n w4 = 4 * (oW - 1), img = options.imageData,\n pixels = img.data, destImage = options.ctx.createImageData(dW, dH),\n destPixels = destImage.data;\n for (i = 0; i < dH; i++) {\n for (j = 0; j < dW; j++) {\n x = floor(ratioX * j);\n y = floor(ratioY * i);\n xDiff = ratioX * j - x;\n yDiff = ratioY * i - y;\n origPix = 4 * (y * oW + x);\n\n for (chnl = 0; chnl < 4; chnl++) {\n a = pixels[origPix + chnl];\n b = pixels[origPix + 4 + chnl];\n c = pixels[origPix + w4 + chnl];\n d = pixels[origPix + w4 + 4 + chnl];\n color = a * (1 - xDiff) * (1 - yDiff) + b * xDiff * (1 - yDiff) +\n c * yDiff * (1 - xDiff) + d * xDiff * yDiff;\n destPixels[offset++] = color;\n }\n }\n }\n return destImage;\n },\n\n /**\n * hermiteFastResize\n * @param {Object} canvasEl Canvas element to apply filter to\n * @param {Number} oW Original Width\n * @param {Number} oH Original Height\n * @param {Number} dW Destination Width\n * @param {Number} dH Destination Height\n * @returns {ImageData}\n */\n hermiteFastResize: function(options, oW, oH, dW, dH) {\n var ratioW = this.rcpScaleX, ratioH = this.rcpScaleY,\n ratioWHalf = ceil(ratioW / 2),\n ratioHHalf = ceil(ratioH / 2),\n img = options.imageData, data = img.data,\n img2 = options.ctx.createImageData(dW, dH), data2 = img2.data;\n for (var j = 0; j < dH; j++) {\n for (var i = 0; i < dW; i++) {\n var x2 = (i + j * dW) * 4, weight = 0, weights = 0, weightsAlpha = 0,\n gxR = 0, gxG = 0, gxB = 0, gxA = 0, centerY = (j + 0.5) * ratioH;\n for (var yy = floor(j * ratioH); yy < (j + 1) * ratioH; yy++) {\n var dy = abs(centerY - (yy + 0.5)) / ratioHHalf,\n centerX = (i + 0.5) * ratioW, w0 = dy * dy;\n for (var xx = floor(i * ratioW); xx < (i + 1) * ratioW; xx++) {\n var dx = abs(centerX - (xx + 0.5)) / ratioWHalf,\n w = sqrt(w0 + dx * dx);\n /* eslint-disable max-depth */\n if (w > 1 && w < -1) {\n continue;\n }\n //hermite filter\n weight = 2 * w * w * w - 3 * w * w + 1;\n if (weight > 0) {\n dx = 4 * (xx + yy * oW);\n //alpha\n gxA += weight * data[dx + 3];\n weightsAlpha += weight;\n //colors\n if (data[dx + 3] < 255) {\n weight = weight * data[dx + 3] / 250;\n }\n gxR += weight * data[dx];\n gxG += weight * data[dx + 1];\n gxB += weight * data[dx + 2];\n weights += weight;\n }\n /* eslint-enable max-depth */\n }\n }\n data2[x2] = gxR / weights;\n data2[x2 + 1] = gxG / weights;\n data2[x2 + 2] = gxB / weights;\n data2[x2 + 3] = gxA / weightsAlpha;\n }\n }\n return img2;\n },\n\n /**\n * Returns object representation of an instance\n * @return {Object} Object representation of an instance\n */\n toObject: function() {\n return {\n type: this.type,\n scaleX: this.scaleX,\n scaleY: this.scaleY,\n resizeType: this.resizeType,\n lanczosLobes: this.lanczosLobes\n };\n }\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Resize} Instance of fabric.Image.filters.Resize\n */\n fabric.Image.filters.Resize.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Contrast filter class\n * @class fabric.Image.filters.Contrast\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Contrast#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Contrast({\n * contrast: 0.25\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.Contrast = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Contrast.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Contrast',\n\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uContrast;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'float contrastF = 1.015 * (uContrast + 1.0) / (1.0 * (1.015 - uContrast));\\n' +\n 'color.rgb = contrastF * (color.rgb - 0.5) + 0.5;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n\n /**\n * contrast value, range from -1 to 1.\n * @param {Number} contrast\n * @default 0\n */\n contrast: 0,\n\n mainParameter: 'contrast',\n\n /**\n * Constructor\n * @memberOf fabric.Image.filters.Contrast.prototype\n * @param {Object} [options] Options object\n * @param {Number} [options.contrast=0] Value to contrast the image up (-1...1)\n */\n\n /**\n * Apply the Contrast operation to a Uint8Array representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8Array to be filtered.\n */\n applyTo2d: function(options) {\n if (this.contrast === 0) {\n return;\n }\n var imageData = options.imageData, i, len,\n data = imageData.data, len = data.length,\n contrast = Math.floor(this.contrast * 255),\n contrastF = 259 * (contrast + 255) / (255 * (259 - contrast));\n\n for (i = 0; i < len; i += 4) {\n data[i] = contrastF * (data[i] - 128) + 128;\n data[i + 1] = contrastF * (data[i + 1] - 128) + 128;\n data[i + 2] = contrastF * (data[i + 2] - 128) + 128;\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uContrast: gl.getUniformLocation(program, 'uContrast'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1f(uniformLocations.uContrast, this.contrast);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Contrast} Instance of fabric.Image.filters.Contrast\n */\n fabric.Image.filters.Contrast.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Saturate filter class\n * @class fabric.Image.filters.Saturation\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Saturation#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Saturation({\n * saturation: 1\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.Saturation = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Saturation.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Saturation',\n\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uSaturation;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'float rgMax = max(color.r, color.g);\\n' +\n 'float rgbMax = max(rgMax, color.b);\\n' +\n 'color.r += rgbMax != color.r ? (rgbMax - color.r) * uSaturation : 0.00;\\n' +\n 'color.g += rgbMax != color.g ? (rgbMax - color.g) * uSaturation : 0.00;\\n' +\n 'color.b += rgbMax != color.b ? (rgbMax - color.b) * uSaturation : 0.00;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n\n /**\n * Saturation value, from -1 to 1.\n * Increases/decreases the color saturation.\n * A value of 0 has no effect.\n * \n * @param {Number} saturation\n * @default\n */\n saturation: 0,\n\n mainParameter: 'saturation',\n\n /**\n * Constructor\n * @memberOf fabric.Image.filters.Saturate.prototype\n * @param {Object} [options] Options object\n * @param {Number} [options.saturate=0] Value to saturate the image (-1...1)\n */\n\n /**\n * Apply the Saturation operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n if (this.saturation === 0) {\n return;\n }\n var imageData = options.imageData,\n data = imageData.data, len = data.length,\n adjust = -this.saturation, i, max;\n\n for (i = 0; i < len; i += 4) {\n max = Math.max(data[i], data[i + 1], data[i + 2]);\n data[i] += max !== data[i] ? (max - data[i]) * adjust : 0;\n data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * adjust : 0;\n data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * adjust : 0;\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uSaturation: gl.getUniformLocation(program, 'uSaturation'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1f(uniformLocations.uSaturation, -this.saturation);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Saturation} Instance of fabric.Image.filters.Saturate\n */\n fabric.Image.filters.Saturation.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Vibrance filter class\n * @class fabric.Image.filters.Vibrance\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Vibrance#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Vibrance({\n * vibrance: 1\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.Vibrance = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Vibrance.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Vibrance',\n\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform float uVibrance;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'float max = max(color.r, max(color.g, color.b));\\n' +\n 'float avg = (color.r + color.g + color.b) / 3.0;\\n' +\n 'float amt = (abs(max - avg) * 2.0) * uVibrance;\\n' +\n 'color.r += max != color.r ? (max - color.r) * amt : 0.00;\\n' +\n 'color.g += max != color.g ? (max - color.g) * amt : 0.00;\\n' +\n 'color.b += max != color.b ? (max - color.b) * amt : 0.00;\\n' +\n 'gl_FragColor = color;\\n' +\n '}',\n\n /**\n * Vibrance value, from -1 to 1.\n * Increases/decreases the saturation of more muted colors with less effect on saturated colors.\n * A value of 0 has no effect.\n * \n * @param {Number} vibrance\n * @default\n */\n vibrance: 0,\n\n mainParameter: 'vibrance',\n\n /**\n * Constructor\n * @memberOf fabric.Image.filters.Vibrance.prototype\n * @param {Object} [options] Options object\n * @param {Number} [options.vibrance=0] Vibrance value for the image (between -1 and 1)\n */\n\n /**\n * Apply the Vibrance operation to a Uint8ClampedArray representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8ClampedArray to be filtered.\n */\n applyTo2d: function(options) {\n if (this.vibrance === 0) {\n return;\n }\n var imageData = options.imageData,\n data = imageData.data, len = data.length,\n adjust = -this.vibrance, i, max, avg, amt;\n\n for (i = 0; i < len; i += 4) {\n max = Math.max(data[i], data[i + 1], data[i + 2]);\n avg = (data[i] + data[i + 1] + data[i + 2]) / 3;\n amt = ((Math.abs(max - avg) * 2 / 255) * adjust);\n data[i] += max !== data[i] ? (max - data[i]) * amt : 0;\n data[i + 1] += max !== data[i + 1] ? (max - data[i + 1]) * amt : 0;\n data[i + 2] += max !== data[i + 2] ? (max - data[i + 2]) * amt : 0;\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uVibrance: gl.getUniformLocation(program, 'uVibrance'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform1f(uniformLocations.uVibrance, -this.vibrance);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Vibrance} Instance of fabric.Image.filters.Vibrance\n */\n fabric.Image.filters.Vibrance.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Blur filter class\n * @class fabric.Image.filters.Blur\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Blur#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Blur({\n * blur: 0.5\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n * canvas.renderAll();\n */\n filters.Blur = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Blur.prototype */ {\n\n type: 'Blur',\n\n /*\n'gl_FragColor = vec4(0.0);',\n'gl_FragColor += texture2D(texture, vTexCoord + -7 * uDelta)*0.0044299121055113265;',\n'gl_FragColor += texture2D(texture, vTexCoord + -6 * uDelta)*0.00895781211794;',\n'gl_FragColor += texture2D(texture, vTexCoord + -5 * uDelta)*0.0215963866053;',\n'gl_FragColor += texture2D(texture, vTexCoord + -4 * uDelta)*0.0443683338718;',\n'gl_FragColor += texture2D(texture, vTexCoord + -3 * uDelta)*0.0776744219933;',\n'gl_FragColor += texture2D(texture, vTexCoord + -2 * uDelta)*0.115876621105;',\n'gl_FragColor += texture2D(texture, vTexCoord + -1 * uDelta)*0.147308056121;',\n'gl_FragColor += texture2D(texture, vTexCoord )*0.159576912161;',\n'gl_FragColor += texture2D(texture, vTexCoord + 1 * uDelta)*0.147308056121;',\n'gl_FragColor += texture2D(texture, vTexCoord + 2 * uDelta)*0.115876621105;',\n'gl_FragColor += texture2D(texture, vTexCoord + 3 * uDelta)*0.0776744219933;',\n'gl_FragColor += texture2D(texture, vTexCoord + 4 * uDelta)*0.0443683338718;',\n'gl_FragColor += texture2D(texture, vTexCoord + 5 * uDelta)*0.0215963866053;',\n'gl_FragColor += texture2D(texture, vTexCoord + 6 * uDelta)*0.00895781211794;',\n'gl_FragColor += texture2D(texture, vTexCoord + 7 * uDelta)*0.0044299121055113265;',\n*/\n\n /* eslint-disable max-len */\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform vec2 uDelta;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'const float nSamples = 15.0;\\n' +\n 'vec3 v3offset = vec3(12.9898, 78.233, 151.7182);\\n' +\n 'float random(vec3 scale) {\\n' +\n /* use the fragment position for a different seed per-pixel */\n 'return fract(sin(dot(gl_FragCoord.xyz, scale)) * 43758.5453);\\n' +\n '}\\n' +\n 'void main() {\\n' +\n 'vec4 color = vec4(0.0);\\n' +\n 'float total = 0.0;\\n' +\n 'float offset = random(v3offset);\\n' +\n 'for (float t = -nSamples; t <= nSamples; t++) {\\n' +\n 'float percent = (t + offset - 0.5) / nSamples;\\n' +\n 'float weight = 1.0 - abs(percent);\\n' +\n 'color += texture2D(uTexture, vTexCoord + uDelta * percent) * weight;\\n' +\n 'total += weight;\\n' +\n '}\\n' +\n 'gl_FragColor = color / total;\\n' +\n '}',\n /* eslint-enable max-len */\n\n /**\n * blur value, in percentage of image dimensions.\n * specific to keep the image blur constant at different resolutions\n * range between 0 and 1.\n * @type Number\n * @default\n */\n blur: 0,\n\n mainParameter: 'blur',\n\n applyTo: function(options) {\n if (options.webgl) {\n // this aspectRatio is used to give the same blur to vertical and horizontal\n this.aspectRatio = options.sourceWidth / options.sourceHeight;\n options.passes++;\n this._setupFrameBuffer(options);\n this.horizontal = true;\n this.applyToWebGL(options);\n this._swapTextures(options);\n this._setupFrameBuffer(options);\n this.horizontal = false;\n this.applyToWebGL(options);\n this._swapTextures(options);\n }\n else {\n this.applyTo2d(options);\n }\n },\n\n applyTo2d: function(options) {\n // paint canvasEl with current image data.\n //options.ctx.putImageData(options.imageData, 0, 0);\n options.imageData = this.simpleBlur(options);\n },\n\n simpleBlur: function(options) {\n var resources = options.filterBackend.resources, canvas1, canvas2,\n width = options.imageData.width,\n height = options.imageData.height;\n\n if (!resources.blurLayer1) {\n resources.blurLayer1 = fabric.util.createCanvasElement();\n resources.blurLayer2 = fabric.util.createCanvasElement();\n }\n canvas1 = resources.blurLayer1;\n canvas2 = resources.blurLayer2;\n if (canvas1.width !== width || canvas1.height !== height) {\n canvas2.width = canvas1.width = width;\n canvas2.height = canvas1.height = height;\n }\n var ctx1 = canvas1.getContext('2d'),\n ctx2 = canvas2.getContext('2d'),\n nSamples = 15,\n random, percent, j, i,\n blur = this.blur * 0.06 * 0.5;\n\n // load first canvas\n ctx1.putImageData(options.imageData, 0, 0);\n ctx2.clearRect(0, 0, width, height);\n\n for (i = -nSamples; i <= nSamples; i++) {\n random = (Math.random() - 0.5) / 4;\n percent = i / nSamples;\n j = blur * percent * width + random;\n ctx2.globalAlpha = 1 - Math.abs(percent);\n ctx2.drawImage(canvas1, j, random);\n ctx1.drawImage(canvas2, 0, 0);\n ctx2.globalAlpha = 1;\n ctx2.clearRect(0, 0, canvas2.width, canvas2.height);\n }\n for (i = -nSamples; i <= nSamples; i++) {\n random = (Math.random() - 0.5) / 4;\n percent = i / nSamples;\n j = blur * percent * height + random;\n ctx2.globalAlpha = 1 - Math.abs(percent);\n ctx2.drawImage(canvas1, random, j);\n ctx1.drawImage(canvas2, 0, 0);\n ctx2.globalAlpha = 1;\n ctx2.clearRect(0, 0, canvas2.width, canvas2.height);\n }\n options.ctx.drawImage(canvas1, 0, 0);\n var newImageData = options.ctx.getImageData(0, 0, canvas1.width, canvas1.height);\n ctx1.globalAlpha = 1;\n ctx1.clearRect(0, 0, canvas1.width, canvas1.height);\n return newImageData;\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n delta: gl.getUniformLocation(program, 'uDelta'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n var delta = this.chooseRightDelta();\n gl.uniform2fv(uniformLocations.delta, delta);\n },\n\n /**\n * choose right value of image percentage to blur with\n * @returns {Array} a numeric array with delta values\n */\n chooseRightDelta: function() {\n var blurScale = 1, delta = [0, 0], blur;\n if (this.horizontal) {\n if (this.aspectRatio > 1) {\n // image is wide, i want to shrink radius horizontal\n blurScale = 1 / this.aspectRatio;\n }\n }\n else {\n if (this.aspectRatio < 1) {\n // image is tall, i want to shrink radius vertical\n blurScale = this.aspectRatio;\n }\n }\n blur = blurScale * this.blur * 0.12;\n if (this.horizontal) {\n delta[0] = blur;\n }\n else {\n delta[1] = blur;\n }\n return delta;\n },\n });\n\n /**\n * Deserialize a JSON definition of a BlurFilter into a concrete instance.\n */\n filters.Blur.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * Gamma filter class\n * @class fabric.Image.filters.Gamma\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.Gamma#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.Gamma({\n * gamma: [1, 0.5, 2.1]\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.Gamma = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Gamma.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'Gamma',\n\n fragmentSource: 'precision highp float;\\n' +\n 'uniform sampler2D uTexture;\\n' +\n 'uniform vec3 uGamma;\\n' +\n 'varying vec2 vTexCoord;\\n' +\n 'void main() {\\n' +\n 'vec4 color = texture2D(uTexture, vTexCoord);\\n' +\n 'vec3 correction = (1.0 / uGamma);\\n' +\n 'color.r = pow(color.r, correction.r);\\n' +\n 'color.g = pow(color.g, correction.g);\\n' +\n 'color.b = pow(color.b, correction.b);\\n' +\n 'gl_FragColor = color;\\n' +\n 'gl_FragColor.rgb *= color.a;\\n' +\n '}',\n\n /**\n * Gamma array value, from 0.01 to 2.2.\n * @param {Array} gamma\n * @default\n */\n gamma: [1, 1, 1],\n\n /**\n * Describe the property that is the filter parameter\n * @param {String} m\n * @default\n */\n mainParameter: 'gamma',\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n */\n initialize: function(options) {\n this.gamma = [1, 1, 1];\n filters.BaseFilter.prototype.initialize.call(this, options);\n },\n\n /**\n * Apply the Gamma operation to a Uint8Array representing the pixels of an image.\n *\n * @param {Object} options\n * @param {ImageData} options.imageData The Uint8Array to be filtered.\n */\n applyTo2d: function(options) {\n var imageData = options.imageData, data = imageData.data,\n gamma = this.gamma, len = data.length,\n rInv = 1 / gamma[0], gInv = 1 / gamma[1],\n bInv = 1 / gamma[2], i;\n\n if (!this.rVals) {\n // eslint-disable-next-line\n this.rVals = new Uint8Array(256);\n // eslint-disable-next-line\n this.gVals = new Uint8Array(256);\n // eslint-disable-next-line\n this.bVals = new Uint8Array(256);\n }\n\n // This is an optimization - pre-compute a look-up table for each color channel\n // instead of performing these pow calls for each pixel in the image.\n for (i = 0, len = 256; i < len; i++) {\n this.rVals[i] = Math.pow(i / 255, rInv) * 255;\n this.gVals[i] = Math.pow(i / 255, gInv) * 255;\n this.bVals[i] = Math.pow(i / 255, bInv) * 255;\n }\n for (i = 0, len = data.length; i < len; i += 4) {\n data[i] = this.rVals[data[i]];\n data[i + 1] = this.gVals[data[i + 1]];\n data[i + 2] = this.bVals[data[i + 2]];\n }\n },\n\n /**\n * Return WebGL uniform locations for this filter's shader.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {WebGLShaderProgram} program This filter's compiled shader program.\n */\n getUniformLocations: function(gl, program) {\n return {\n uGamma: gl.getUniformLocation(program, 'uGamma'),\n };\n },\n\n /**\n * Send data from this filter to its shader program's uniforms.\n *\n * @param {WebGLRenderingContext} gl The GL canvas context used to compile this filter's shader.\n * @param {Object} uniformLocations A map of string uniform names to WebGLUniformLocation objects\n */\n sendUniformData: function(gl, uniformLocations) {\n gl.uniform3fv(uniformLocations.uGamma, this.gamma);\n },\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.Gamma} Instance of fabric.Image.filters.Gamma\n */\n fabric.Image.filters.Gamma.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * A container class that knows how to apply a sequence of filters to an input image.\n */\n filters.Composed = createClass(filters.BaseFilter, /** @lends fabric.Image.filters.Composed.prototype */ {\n\n type: 'Composed',\n\n /**\n * A non sparse array of filters to apply\n */\n subFilters: [],\n\n /**\n * Constructor\n * @param {Object} [options] Options object\n */\n initialize: function(options) {\n this.callSuper('initialize', options);\n // create a new array instead mutating the prototype with push\n this.subFilters = this.subFilters.slice(0);\n },\n\n /**\n * Apply this container's filters to the input image provided.\n *\n * @param {Object} options\n * @param {Number} options.passes The number of filters remaining to be applied.\n */\n applyTo: function(options) {\n options.passes += this.subFilters.length - 1;\n this.subFilters.forEach(function(filter) {\n filter.applyTo(options);\n });\n },\n\n /**\n * Serialize this filter into JSON.\n *\n * @returns {Object} A JSON representation of this filter.\n */\n toObject: function() {\n return fabric.util.object.extend(this.callSuper('toObject'), {\n subFilters: this.subFilters.map(function(filter) { return filter.toObject(); }),\n });\n },\n\n isNeutralState: function() {\n return !this.subFilters.some(function(filter) { return !filter.isNeutralState(); });\n }\n });\n\n /**\n * Deserialize a JSON definition of a ComposedFilter into a concrete instance.\n */\n fabric.Image.filters.Composed.fromObject = function(object, callback) {\n var filters = object.subFilters || [],\n subFilters = filters.map(function(filter) {\n return new fabric.Image.filters[filter.type](filter);\n }),\n instance = new fabric.Image.filters.Composed({ subFilters: subFilters });\n callback && callback(instance);\n return instance;\n };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n filters = fabric.Image.filters,\n createClass = fabric.util.createClass;\n\n /**\n * HueRotation filter class\n * @class fabric.Image.filters.HueRotation\n * @memberOf fabric.Image.filters\n * @extends fabric.Image.filters.BaseFilter\n * @see {@link fabric.Image.filters.HueRotation#initialize} for constructor definition\n * @see {@link http://fabricjs.com/image-filters|ImageFilters demo}\n * @example\n * var filter = new fabric.Image.filters.HueRotation({\n * rotation: -0.5\n * });\n * object.filters.push(filter);\n * object.applyFilters();\n */\n filters.HueRotation = createClass(filters.ColorMatrix, /** @lends fabric.Image.filters.HueRotation.prototype */ {\n\n /**\n * Filter type\n * @param {String} type\n * @default\n */\n type: 'HueRotation',\n\n /**\n * HueRotation value, from -1 to 1.\n * the unit is radians\n * @param {Number} myParameter\n * @default\n */\n rotation: 0,\n\n /**\n * Describe the property that is the filter parameter\n * @param {String} m\n * @default\n */\n mainParameter: 'rotation',\n\n calculateMatrix: function() {\n var rad = this.rotation * Math.PI, cos = fabric.util.cos(rad), sin = fabric.util.sin(rad),\n aThird = 1 / 3, aThirdSqtSin = Math.sqrt(aThird) * sin, OneMinusCos = 1 - cos;\n this.matrix = [\n 1, 0, 0, 0, 0,\n 0, 1, 0, 0, 0,\n 0, 0, 1, 0, 0,\n 0, 0, 0, 1, 0\n ];\n this.matrix[0] = cos + OneMinusCos / 3;\n this.matrix[1] = aThird * OneMinusCos - aThirdSqtSin;\n this.matrix[2] = aThird * OneMinusCos + aThirdSqtSin;\n this.matrix[5] = aThird * OneMinusCos + aThirdSqtSin;\n this.matrix[6] = cos + aThird * OneMinusCos;\n this.matrix[7] = aThird * OneMinusCos - aThirdSqtSin;\n this.matrix[10] = aThird * OneMinusCos - aThirdSqtSin;\n this.matrix[11] = aThird * OneMinusCos + aThirdSqtSin;\n this.matrix[12] = cos + aThird * OneMinusCos;\n },\n\n /**\n * HueRotation isNeutralState implementation\n * Used only in image applyFilters to discard filters that will not have an effect\n * on the image\n * @param {Object} options\n **/\n isNeutralState: function(options) {\n this.calculateMatrix();\n return filters.BaseFilter.prototype.isNeutralState.call(this, options);\n },\n\n /**\n * Apply this filter to the input image data provided.\n *\n * Determines whether to use WebGL or Canvas2D based on the options.webgl flag.\n *\n * @param {Object} options\n * @param {Number} options.passes The number of filters remaining to be executed\n * @param {Boolean} options.webgl Whether to use webgl to render the filter.\n * @param {WebGLTexture} options.sourceTexture The texture setup as the source to be filtered.\n * @param {WebGLTexture} options.targetTexture The texture where filtered output should be drawn.\n * @param {WebGLRenderingContext} options.context The GL context used for rendering.\n * @param {Object} options.programCache A map of compiled shader programs, keyed by filter type.\n */\n applyTo: function(options) {\n this.calculateMatrix();\n filters.BaseFilter.prototype.applyTo.call(this, options);\n },\n\n });\n\n /**\n * Returns filter instance from an object representation\n * @static\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] to be invoked after filter creation\n * @return {fabric.Image.filters.HueRotation} Instance of fabric.Image.filters.HueRotation\n */\n fabric.Image.filters.HueRotation.fromObject = fabric.Image.filters.BaseFilter.fromObject;\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = { }),\n clone = fabric.util.object.clone;\n\n if (fabric.Text) {\n fabric.warn('fabric.Text is already defined');\n return;\n }\n\n var additionalProps =\n ('fontFamily fontWeight fontSize text underline overline linethrough' +\n ' textAlign fontStyle lineHeight textBackgroundColor charSpacing styles' +\n ' direction path pathStartOffset pathSide pathAlign').split(' ');\n\n /**\n * Text class\n * @class fabric.Text\n * @extends fabric.Object\n * @return {fabric.Text} thisArg\n * @tutorial {@link http://fabricjs.com/fabric-intro-part-2#text}\n * @see {@link fabric.Text#initialize} for constructor definition\n */\n fabric.Text = fabric.util.createClass(fabric.Object, /** @lends fabric.Text.prototype */ {\n\n /**\n * Properties which when set cause object to change dimensions\n * @type Array\n * @private\n */\n _dimensionAffectingProps: [\n 'fontSize',\n 'fontWeight',\n 'fontFamily',\n 'fontStyle',\n 'lineHeight',\n 'text',\n 'charSpacing',\n 'textAlign',\n 'styles',\n 'path',\n 'pathStartOffset',\n 'pathSide',\n 'pathAlign'\n ],\n\n /**\n * @private\n */\n _reNewline: /\\r?\\n/,\n\n /**\n * Use this regular expression to filter for whitespaces that is not a new line.\n * Mostly used when text is 'justify' aligned.\n * @private\n */\n _reSpacesAndTabs: /[ \\t\\r]/g,\n\n /**\n * Use this regular expression to filter for whitespace that is not a new line.\n * Mostly used when text is 'justify' aligned.\n * @private\n */\n _reSpaceAndTab: /[ \\t\\r]/,\n\n /**\n * Use this regular expression to filter consecutive groups of non spaces.\n * Mostly used when text is 'justify' aligned.\n * @private\n */\n _reWords: /\\S+/g,\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'text',\n\n /**\n * Font size (in pixels)\n * @type Number\n * @default\n */\n fontSize: 40,\n\n /**\n * Font weight (e.g. bold, normal, 400, 600, 800)\n * @type {(Number|String)}\n * @default\n */\n fontWeight: 'normal',\n\n /**\n * Font family\n * @type String\n * @default\n */\n fontFamily: 'Times New Roman',\n\n /**\n * Text decoration underline.\n * @type Boolean\n * @default\n */\n underline: false,\n\n /**\n * Text decoration overline.\n * @type Boolean\n * @default\n */\n overline: false,\n\n /**\n * Text decoration linethrough.\n * @type Boolean\n * @default\n */\n linethrough: false,\n\n /**\n * Text alignment. Possible values: \"left\", \"center\", \"right\", \"justify\",\n * \"justify-left\", \"justify-center\" or \"justify-right\".\n * @type String\n * @default\n */\n textAlign: 'left',\n\n /**\n * Font style . Possible values: \"\", \"normal\", \"italic\" or \"oblique\".\n * @type String\n * @default\n */\n fontStyle: 'normal',\n\n /**\n * Line height\n * @type Number\n * @default\n */\n lineHeight: 1.16,\n\n /**\n * Superscript schema object (minimum overlap)\n * @type {Object}\n * @default\n */\n superscript: {\n size: 0.60, // fontSize factor\n baseline: -0.35 // baseline-shift factor (upwards)\n },\n\n /**\n * Subscript schema object (minimum overlap)\n * @type {Object}\n * @default\n */\n subscript: {\n size: 0.60, // fontSize factor\n baseline: 0.11 // baseline-shift factor (downwards)\n },\n\n /**\n * Background color of text lines\n * @type String\n * @default\n */\n textBackgroundColor: '',\n\n /**\n * List of properties to consider when checking if\n * state of an object is changed ({@link fabric.Object#hasStateChanged})\n * as well as for history (undo/redo) purposes\n * @type Array\n */\n stateProperties: fabric.Object.prototype.stateProperties.concat(additionalProps),\n\n /**\n * List of properties to consider when checking if cache needs refresh\n * @type Array\n */\n cacheProperties: fabric.Object.prototype.cacheProperties.concat(additionalProps),\n\n /**\n * When defined, an object is rendered via stroke and this property specifies its color.\n * Backwards incompatibility note: This property was named \"strokeStyle\" until v1.1.6\n * @type String\n * @default\n */\n stroke: null,\n\n /**\n * Shadow object representing shadow of this shape.\n * Backwards incompatibility note: This property was named \"textShadow\" (String) until v1.2.11\n * @type fabric.Shadow\n * @default\n */\n shadow: null,\n\n /**\n * fabric.Path that the text should follow.\n * since 4.6.0 the path will be drawn automatically.\n * if you want to make the path visible, give it a stroke and strokeWidth or fill value\n * if you want it to be hidden, assign visible = false to the path.\n * This feature is in BETA, and SVG import/export is not yet supported.\n * @type fabric.Path\n * @example\n * var textPath = new fabric.Text('Text on a path', {\n * top: 150,\n * left: 150,\n * textAlign: 'center',\n * charSpacing: -50,\n * path: new fabric.Path('M 0 0 C 50 -100 150 -100 200 0', {\n * strokeWidth: 1,\n * visible: false\n * }),\n * pathSide: 'left',\n * pathStartOffset: 0\n * });\n * @default\n */\n path: null,\n\n /**\n * Offset amount for text path starting position\n * Only used when text has a path\n * @type Number\n * @default\n */\n pathStartOffset: 0,\n\n /**\n * Which side of the path the text should be drawn on.\n * Only used when text has a path\n * @type {String} 'left|right'\n * @default\n */\n pathSide: 'left',\n\n /**\n * How text is aligned to the path. This property determines\n * the perpendicular position of each character relative to the path.\n * (one of \"baseline\", \"center\", \"ascender\", \"descender\")\n * This feature is in BETA, and its behavior may change\n * @type String\n * @default\n */\n pathAlign: 'baseline',\n\n /**\n * @private\n */\n _fontSizeFraction: 0.222,\n\n /**\n * @private\n */\n offsets: {\n underline: 0.10,\n linethrough: -0.315,\n overline: -0.88\n },\n\n /**\n * Text Line proportion to font Size (in pixels)\n * @type Number\n * @default\n */\n _fontSizeMult: 1.13,\n\n /**\n * additional space between characters\n * expressed in thousands of em unit\n * @type Number\n * @default\n */\n charSpacing: 0,\n\n /**\n * Object containing character styles - top-level properties -> line numbers,\n * 2nd-level properties - character numbers\n * @type Object\n * @default\n */\n styles: null,\n\n /**\n * Reference to a context to measure text char or couple of chars\n * the cacheContext of the canvas will be used or a freshly created one if the object is not on canvas\n * once created it will be referenced on fabric._measuringContext to avoid creating a canvas for every\n * text object created.\n * @type {CanvasRenderingContext2D}\n * @default\n */\n _measuringContext: null,\n\n /**\n * Baseline shift, styles only, keep at 0 for the main text object\n * @type {Number}\n * @default\n */\n deltaY: 0,\n\n /**\n * WARNING: EXPERIMENTAL. NOT SUPPORTED YET\n * determine the direction of the text.\n * This has to be set manually together with textAlign and originX for proper\n * experience.\n * some interesting link for the future\n * https://www.w3.org/International/questions/qa-bidi-unicode-controls\n * @since 4.5.0\n * @type {String} 'ltr|rtl'\n * @default\n */\n direction: 'ltr',\n\n /**\n * Array of properties that define a style unit (of 'styles').\n * @type {Array}\n * @default\n */\n _styleProperties: [\n 'stroke',\n 'strokeWidth',\n 'fill',\n 'fontFamily',\n 'fontSize',\n 'fontWeight',\n 'fontStyle',\n 'underline',\n 'overline',\n 'linethrough',\n 'deltaY',\n 'textBackgroundColor',\n ],\n\n /**\n * contains characters bounding boxes\n */\n __charBounds: [],\n\n /**\n * use this size when measuring text. To avoid IE11 rounding errors\n * @type {Number}\n * @default\n * @readonly\n * @private\n */\n CACHE_FONT_SIZE: 400,\n\n /**\n * contains the min text width to avoid getting 0\n * @type {Number}\n * @default\n */\n MIN_TEXT_WIDTH: 2,\n\n /**\n * Constructor\n * @param {String} text Text string\n * @param {Object} [options] Options object\n * @return {fabric.Text} thisArg\n */\n initialize: function(text, options) {\n this.styles = options ? (options.styles || { }) : { };\n this.text = text;\n this.__skipDimension = true;\n this.callSuper('initialize', options);\n if (this.path) {\n this.setPathInfo();\n }\n this.__skipDimension = false;\n this.initDimensions();\n this.setCoords();\n this.setupState({ propertySet: '_dimensionAffectingProps' });\n },\n\n /**\n * If text has a path, it will add the extra information needed\n * for path and text calculations\n * @return {fabric.Text} thisArg\n */\n setPathInfo: function() {\n var path = this.path;\n if (path) {\n path.segmentsInfo = fabric.util.getPathSegmentsInfo(path.path);\n }\n },\n\n /**\n * Return a context for measurement of text string.\n * if created it gets stored for reuse\n * this is for internal use, please do not use it\n * @private\n * @param {String} text Text string\n * @param {Object} [options] Options object\n * @return {fabric.Text} thisArg\n */\n getMeasuringContext: function() {\n // if we did not return we have to measure something.\n if (!fabric._measuringContext) {\n fabric._measuringContext = this.canvas && this.canvas.contextCache ||\n fabric.util.createCanvasElement().getContext('2d');\n }\n return fabric._measuringContext;\n },\n\n /**\n * @private\n * Divides text into lines of text and lines of graphemes.\n */\n _splitText: function() {\n var newLines = this._splitTextIntoLines(this.text);\n this.textLines = newLines.lines;\n this._textLines = newLines.graphemeLines;\n this._unwrappedTextLines = newLines._unwrappedLines;\n this._text = newLines.graphemeText;\n return newLines;\n },\n\n /**\n * Initialize or update text dimensions.\n * Updates this.width and this.height with the proper values.\n * Does not return dimensions.\n */\n initDimensions: function() {\n if (this.__skipDimension) {\n return;\n }\n this._splitText();\n this._clearCache();\n if (this.path) {\n this.width = this.path.width;\n this.height = this.path.height;\n }\n else {\n this.width = this.calcTextWidth() || this.cursorWidth || this.MIN_TEXT_WIDTH;\n this.height = this.calcTextHeight();\n }\n if (this.textAlign.indexOf('justify') !== -1) {\n // once text is measured we need to make space fatter to make justified text.\n this.enlargeSpaces();\n }\n this.saveState({ propertySet: '_dimensionAffectingProps' });\n },\n\n /**\n * Enlarge space boxes and shift the others\n */\n enlargeSpaces: function() {\n var diffSpace, currentLineWidth, numberOfSpaces, accumulatedSpace, line, charBound, spaces;\n for (var i = 0, len = this._textLines.length; i < len; i++) {\n if (this.textAlign !== 'justify' && (i === len - 1 || this.isEndOfWrapping(i))) {\n continue;\n }\n accumulatedSpace = 0;\n line = this._textLines[i];\n currentLineWidth = this.getLineWidth(i);\n if (currentLineWidth < this.width && (spaces = this.textLines[i].match(this._reSpacesAndTabs))) {\n numberOfSpaces = spaces.length;\n diffSpace = (this.width - currentLineWidth) / numberOfSpaces;\n for (var j = 0, jlen = line.length; j <= jlen; j++) {\n charBound = this.__charBounds[i][j];\n if (this._reSpaceAndTab.test(line[j])) {\n charBound.width += diffSpace;\n charBound.kernedWidth += diffSpace;\n charBound.left += accumulatedSpace;\n accumulatedSpace += diffSpace;\n }\n else {\n charBound.left += accumulatedSpace;\n }\n }\n }\n }\n },\n\n /**\n * Detect if the text line is ended with an hard break\n * text and itext do not have wrapping, return false\n * @return {Boolean}\n */\n isEndOfWrapping: function(lineIndex) {\n return lineIndex === this._textLines.length - 1;\n },\n\n /**\n * Detect if a line has a linebreak and so we need to account for it when moving\n * and counting style.\n * It return always for text and Itext.\n * @return Number\n */\n missingNewlineOffset: function() {\n return 1;\n },\n\n /**\n * Returns string representation of an instance\n * @return {String} String representation of text object\n */\n toString: function() {\n return '#';\n },\n\n /**\n * Return the dimension and the zoom level needed to create a cache canvas\n * big enough to host the object to be cached.\n * @private\n * @param {Object} dim.x width of object to be cached\n * @param {Object} dim.y height of object to be cached\n * @return {Object}.width width of canvas\n * @return {Object}.height height of canvas\n * @return {Object}.zoomX zoomX zoom value to unscale the canvas before drawing cache\n * @return {Object}.zoomY zoomY zoom value to unscale the canvas before drawing cache\n */\n _getCacheCanvasDimensions: function() {\n var dims = this.callSuper('_getCacheCanvasDimensions');\n var fontSize = this.fontSize;\n dims.width += fontSize * dims.zoomX;\n dims.height += fontSize * dims.zoomY;\n return dims;\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n var path = this.path;\n path && !path.isNotVisible() && path._render(ctx);\n this._setTextStyles(ctx);\n this._renderTextLinesBackground(ctx);\n this._renderTextDecoration(ctx, 'underline');\n this._renderText(ctx);\n this._renderTextDecoration(ctx, 'overline');\n this._renderTextDecoration(ctx, 'linethrough');\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderText: function(ctx) {\n if (this.paintFirst === 'stroke') {\n this._renderTextStroke(ctx);\n this._renderTextFill(ctx);\n }\n else {\n this._renderTextFill(ctx);\n this._renderTextStroke(ctx);\n }\n },\n\n /**\n * Set the font parameter of the context with the object properties or with charStyle\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {Object} [charStyle] object with font style properties\n * @param {String} [charStyle.fontFamily] Font Family\n * @param {Number} [charStyle.fontSize] Font size in pixels. ( without px suffix )\n * @param {String} [charStyle.fontWeight] Font weight\n * @param {String} [charStyle.fontStyle] Font style (italic|normal)\n */\n _setTextStyles: function(ctx, charStyle, forMeasuring) {\n ctx.textBaseline = 'alphabetical';\n if (this.path) {\n switch (this.pathAlign) {\n case 'center':\n ctx.textBaseline = 'middle';\n break;\n case 'ascender':\n ctx.textBaseline = 'top';\n break;\n case 'descender':\n ctx.textBaseline = 'bottom';\n break;\n }\n }\n ctx.font = this._getFontDeclaration(charStyle, forMeasuring);\n },\n\n /**\n * calculate and return the text Width measuring each line.\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @return {Number} Maximum width of fabric.Text object\n */\n calcTextWidth: function() {\n var maxWidth = this.getLineWidth(0);\n\n for (var i = 1, len = this._textLines.length; i < len; i++) {\n var currentLineWidth = this.getLineWidth(i);\n if (currentLineWidth > maxWidth) {\n maxWidth = currentLineWidth;\n }\n }\n return maxWidth;\n },\n\n /**\n * @private\n * @param {String} method Method name (\"fillText\" or \"strokeText\")\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {String} line Text to render\n * @param {Number} left Left position of text\n * @param {Number} top Top position of text\n * @param {Number} lineIndex Index of a line in a text\n */\n _renderTextLine: function(method, ctx, line, left, top, lineIndex) {\n this._renderChars(method, ctx, line, left, top, lineIndex);\n },\n\n /**\n * Renders the text background for lines, taking care of style\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderTextLinesBackground: function(ctx) {\n if (!this.textBackgroundColor && !this.styleHas('textBackgroundColor')) {\n return;\n }\n var heightOfLine,\n lineLeftOffset, originalFill = ctx.fillStyle,\n line, lastColor,\n leftOffset = this._getLeftOffset(),\n lineTopOffset = this._getTopOffset(),\n boxStart = 0, boxWidth = 0, charBox, currentColor, path = this.path,\n drawStart;\n\n for (var i = 0, len = this._textLines.length; i < len; i++) {\n heightOfLine = this.getHeightOfLine(i);\n if (!this.textBackgroundColor && !this.styleHas('textBackgroundColor', i)) {\n lineTopOffset += heightOfLine;\n continue;\n }\n line = this._textLines[i];\n lineLeftOffset = this._getLineLeftOffset(i);\n boxWidth = 0;\n boxStart = 0;\n lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor');\n for (var j = 0, jlen = line.length; j < jlen; j++) {\n charBox = this.__charBounds[i][j];\n currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');\n if (path) {\n ctx.save();\n ctx.translate(charBox.renderLeft, charBox.renderTop);\n ctx.rotate(charBox.angle);\n ctx.fillStyle = currentColor;\n currentColor && ctx.fillRect(\n -charBox.width / 2,\n -heightOfLine / this.lineHeight * (1 - this._fontSizeFraction),\n charBox.width,\n heightOfLine / this.lineHeight\n );\n ctx.restore();\n }\n else if (currentColor !== lastColor) {\n drawStart = leftOffset + lineLeftOffset + boxStart;\n if (this.direction === 'rtl') {\n drawStart = this.width - drawStart - boxWidth;\n }\n ctx.fillStyle = lastColor;\n lastColor && ctx.fillRect(\n drawStart,\n lineTopOffset,\n boxWidth,\n heightOfLine / this.lineHeight\n );\n boxStart = charBox.left;\n boxWidth = charBox.width;\n lastColor = currentColor;\n }\n else {\n boxWidth += charBox.kernedWidth;\n }\n }\n if (currentColor && !path) {\n drawStart = leftOffset + lineLeftOffset + boxStart;\n if (this.direction === 'rtl') {\n drawStart = this.width - drawStart - boxWidth;\n }\n ctx.fillStyle = currentColor;\n ctx.fillRect(\n drawStart,\n lineTopOffset,\n boxWidth,\n heightOfLine / this.lineHeight\n );\n }\n lineTopOffset += heightOfLine;\n }\n ctx.fillStyle = originalFill;\n // if there is text background color no\n // other shadows should be casted\n this._removeShadow(ctx);\n },\n\n /**\n * @private\n * @param {Object} decl style declaration for cache\n * @param {String} decl.fontFamily fontFamily\n * @param {String} decl.fontStyle fontStyle\n * @param {String} decl.fontWeight fontWeight\n * @return {Object} reference to cache\n */\n getFontCache: function(decl) {\n var fontFamily = decl.fontFamily.toLowerCase();\n if (!fabric.charWidthsCache[fontFamily]) {\n fabric.charWidthsCache[fontFamily] = { };\n }\n var cache = fabric.charWidthsCache[fontFamily],\n cacheProp = decl.fontStyle.toLowerCase() + '_' + (decl.fontWeight + '').toLowerCase();\n if (!cache[cacheProp]) {\n cache[cacheProp] = { };\n }\n return cache[cacheProp];\n },\n\n /**\n * measure and return the width of a single character.\n * possibly overridden to accommodate different measure logic or\n * to hook some external lib for character measurement\n * @private\n * @param {String} _char, char to be measured\n * @param {Object} charStyle style of char to be measured\n * @param {String} [previousChar] previous char\n * @param {Object} [prevCharStyle] style of previous char\n */\n _measureChar: function(_char, charStyle, previousChar, prevCharStyle) {\n // first i try to return from cache\n var fontCache = this.getFontCache(charStyle), fontDeclaration = this._getFontDeclaration(charStyle),\n previousFontDeclaration = this._getFontDeclaration(prevCharStyle), couple = previousChar + _char,\n stylesAreEqual = fontDeclaration === previousFontDeclaration, width, coupleWidth, previousWidth,\n fontMultiplier = charStyle.fontSize / this.CACHE_FONT_SIZE, kernedWidth;\n\n if (previousChar && fontCache[previousChar] !== undefined) {\n previousWidth = fontCache[previousChar];\n }\n if (fontCache[_char] !== undefined) {\n kernedWidth = width = fontCache[_char];\n }\n if (stylesAreEqual && fontCache[couple] !== undefined) {\n coupleWidth = fontCache[couple];\n kernedWidth = coupleWidth - previousWidth;\n }\n if (width === undefined || previousWidth === undefined || coupleWidth === undefined) {\n var ctx = this.getMeasuringContext();\n // send a TRUE to specify measuring font size CACHE_FONT_SIZE\n this._setTextStyles(ctx, charStyle, true);\n }\n if (width === undefined) {\n kernedWidth = width = ctx.measureText(_char).width;\n fontCache[_char] = width;\n }\n if (previousWidth === undefined && stylesAreEqual && previousChar) {\n previousWidth = ctx.measureText(previousChar).width;\n fontCache[previousChar] = previousWidth;\n }\n if (stylesAreEqual && coupleWidth === undefined) {\n // we can measure the kerning couple and subtract the width of the previous character\n coupleWidth = ctx.measureText(couple).width;\n fontCache[couple] = coupleWidth;\n kernedWidth = coupleWidth - previousWidth;\n }\n return { width: width * fontMultiplier, kernedWidth: kernedWidth * fontMultiplier };\n },\n\n /**\n * Computes height of character at given position\n * @param {Number} line the line index number\n * @param {Number} _char the character index number\n * @return {Number} fontSize of the character\n */\n getHeightOfChar: function(line, _char) {\n return this.getValueOfPropertyAt(line, _char, 'fontSize');\n },\n\n /**\n * measure a text line measuring all characters.\n * @param {Number} lineIndex line number\n * @return {Number} Line width\n */\n measureLine: function(lineIndex) {\n var lineInfo = this._measureLine(lineIndex);\n if (this.charSpacing !== 0) {\n lineInfo.width -= this._getWidthOfCharSpacing();\n }\n if (lineInfo.width < 0) {\n lineInfo.width = 0;\n }\n return lineInfo;\n },\n\n /**\n * measure every grapheme of a line, populating __charBounds\n * @param {Number} lineIndex\n * @return {Object} object.width total width of characters\n * @return {Object} object.widthOfSpaces length of chars that match this._reSpacesAndTabs\n */\n _measureLine: function(lineIndex) {\n var width = 0, i, grapheme, line = this._textLines[lineIndex], prevGrapheme,\n graphemeInfo, numOfSpaces = 0, lineBounds = new Array(line.length),\n positionInPath = 0, startingPoint, totalPathLength, path = this.path,\n reverse = this.pathSide === 'right';\n\n this.__charBounds[lineIndex] = lineBounds;\n for (i = 0; i < line.length; i++) {\n grapheme = line[i];\n graphemeInfo = this._getGraphemeBox(grapheme, lineIndex, i, prevGrapheme);\n lineBounds[i] = graphemeInfo;\n width += graphemeInfo.kernedWidth;\n prevGrapheme = grapheme;\n }\n // this latest bound box represent the last character of the line\n // to simplify cursor handling in interactive mode.\n lineBounds[i] = {\n left: graphemeInfo ? graphemeInfo.left + graphemeInfo.width : 0,\n width: 0,\n kernedWidth: 0,\n height: this.fontSize\n };\n if (path) {\n totalPathLength = path.segmentsInfo[path.segmentsInfo.length - 1].length;\n startingPoint = fabric.util.getPointOnPath(path.path, 0, path.segmentsInfo);\n startingPoint.x += path.pathOffset.x;\n startingPoint.y += path.pathOffset.y;\n switch (this.textAlign) {\n case 'left':\n positionInPath = reverse ? (totalPathLength - width) : 0;\n break;\n case 'center':\n positionInPath = (totalPathLength - width) / 2;\n break;\n case 'right':\n positionInPath = reverse ? 0 : (totalPathLength - width);\n break;\n //todo - add support for justify\n }\n positionInPath += this.pathStartOffset * (reverse ? -1 : 1);\n for (i = reverse ? line.length - 1 : 0;\n reverse ? i >= 0 : i < line.length;\n reverse ? i-- : i++) {\n graphemeInfo = lineBounds[i];\n if (positionInPath > totalPathLength) {\n positionInPath %= totalPathLength;\n }\n else if (positionInPath < 0) {\n positionInPath += totalPathLength;\n }\n // it would probably much faster to send all the grapheme position for a line\n // and calculate path position/angle at once.\n this._setGraphemeOnPath(positionInPath, graphemeInfo, startingPoint);\n positionInPath += graphemeInfo.kernedWidth;\n }\n }\n return { width: width, numOfSpaces: numOfSpaces };\n },\n\n /**\n * Calculate the angle and the left,top position of the char that follow a path.\n * It appends it to graphemeInfo to be reused later at rendering\n * @private\n * @param {Number} positionInPath to be measured\n * @param {Object} graphemeInfo current grapheme box information\n * @param {Object} startingPoint position of the point\n */\n _setGraphemeOnPath: function(positionInPath, graphemeInfo, startingPoint) {\n var centerPosition = positionInPath + graphemeInfo.kernedWidth / 2,\n path = this.path;\n\n // we are at currentPositionOnPath. we want to know what point on the path is.\n var info = fabric.util.getPointOnPath(path.path, centerPosition, path.segmentsInfo);\n graphemeInfo.renderLeft = info.x - startingPoint.x;\n graphemeInfo.renderTop = info.y - startingPoint.y;\n graphemeInfo.angle = info.angle + (this.pathSide === 'right' ? Math.PI : 0);\n },\n\n /**\n * Measure and return the info of a single grapheme.\n * needs the the info of previous graphemes already filled\n * @private\n * @param {String} grapheme to be measured\n * @param {Number} lineIndex index of the line where the char is\n * @param {Number} charIndex position in the line\n * @param {String} [prevGrapheme] character preceding the one to be measured\n */\n _getGraphemeBox: function(grapheme, lineIndex, charIndex, prevGrapheme, skipLeft) {\n var style = this.getCompleteStyleDeclaration(lineIndex, charIndex),\n prevStyle = prevGrapheme ? this.getCompleteStyleDeclaration(lineIndex, charIndex - 1) : { },\n info = this._measureChar(grapheme, style, prevGrapheme, prevStyle),\n kernedWidth = info.kernedWidth,\n width = info.width, charSpacing;\n\n if (this.charSpacing !== 0) {\n charSpacing = this._getWidthOfCharSpacing();\n width += charSpacing;\n kernedWidth += charSpacing;\n }\n\n var box = {\n width: width,\n left: 0,\n height: style.fontSize,\n kernedWidth: kernedWidth,\n deltaY: style.deltaY,\n };\n if (charIndex > 0 && !skipLeft) {\n var previousBox = this.__charBounds[lineIndex][charIndex - 1];\n box.left = previousBox.left + previousBox.width + info.kernedWidth - info.width;\n }\n return box;\n },\n\n /**\n * Calculate height of line at 'lineIndex'\n * @param {Number} lineIndex index of line to calculate\n * @return {Number}\n */\n getHeightOfLine: function(lineIndex) {\n if (this.__lineHeights[lineIndex]) {\n return this.__lineHeights[lineIndex];\n }\n\n var line = this._textLines[lineIndex],\n // char 0 is measured before the line cycle because it nneds to char\n // emptylines\n maxHeight = this.getHeightOfChar(lineIndex, 0);\n for (var i = 1, len = line.length; i < len; i++) {\n maxHeight = Math.max(this.getHeightOfChar(lineIndex, i), maxHeight);\n }\n\n return this.__lineHeights[lineIndex] = maxHeight * this.lineHeight * this._fontSizeMult;\n },\n\n /**\n * Calculate text box height\n */\n calcTextHeight: function() {\n var lineHeight, height = 0;\n for (var i = 0, len = this._textLines.length; i < len; i++) {\n lineHeight = this.getHeightOfLine(i);\n height += (i === len - 1 ? lineHeight / this.lineHeight : lineHeight);\n }\n return height;\n },\n\n /**\n * @private\n * @return {Number} Left offset\n */\n _getLeftOffset: function() {\n return this.direction === 'ltr' ? -this.width / 2 : this.width / 2;\n },\n\n /**\n * @private\n * @return {Number} Top offset\n */\n _getTopOffset: function() {\n return -this.height / 2;\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {String} method Method name (\"fillText\" or \"strokeText\")\n */\n _renderTextCommon: function(ctx, method) {\n ctx.save();\n var lineHeights = 0, left = this._getLeftOffset(), top = this._getTopOffset();\n for (var i = 0, len = this._textLines.length; i < len; i++) {\n var heightOfLine = this.getHeightOfLine(i),\n maxHeight = heightOfLine / this.lineHeight,\n leftOffset = this._getLineLeftOffset(i);\n this._renderTextLine(\n method,\n ctx,\n this._textLines[i],\n left + leftOffset,\n top + lineHeights + maxHeight,\n i\n );\n lineHeights += heightOfLine;\n }\n ctx.restore();\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderTextFill: function(ctx) {\n if (!this.fill && !this.styleHas('fill')) {\n return;\n }\n\n this._renderTextCommon(ctx, 'fillText');\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderTextStroke: function(ctx) {\n if ((!this.stroke || this.strokeWidth === 0) && this.isEmptyStyles()) {\n return;\n }\n\n if (this.shadow && !this.shadow.affectStroke) {\n this._removeShadow(ctx);\n }\n\n ctx.save();\n this._setLineDash(ctx, this.strokeDashArray);\n ctx.beginPath();\n this._renderTextCommon(ctx, 'strokeText');\n ctx.closePath();\n ctx.restore();\n },\n\n /**\n * @private\n * @param {String} method fillText or strokeText.\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {Array} line Content of the line, splitted in an array by grapheme\n * @param {Number} left\n * @param {Number} top\n * @param {Number} lineIndex\n */\n _renderChars: function(method, ctx, line, left, top, lineIndex) {\n // set proper line offset\n var lineHeight = this.getHeightOfLine(lineIndex),\n isJustify = this.textAlign.indexOf('justify') !== -1,\n actualStyle,\n nextStyle,\n charsToRender = '',\n charBox,\n boxWidth = 0,\n timeToRender,\n path = this.path,\n shortCut = !isJustify && this.charSpacing === 0 && this.isEmptyStyles(lineIndex) && !path,\n isLtr = this.direction === 'ltr', sign = this.direction === 'ltr' ? 1 : -1,\n drawingLeft, currentDirection = ctx.canvas.getAttribute('dir');\n ctx.save();\n if (currentDirection !== this.direction) {\n ctx.canvas.setAttribute('dir', isLtr ? 'ltr' : 'rtl');\n ctx.direction = isLtr ? 'ltr' : 'rtl';\n ctx.textAlign = isLtr ? 'left' : 'right';\n }\n top -= lineHeight * this._fontSizeFraction / this.lineHeight;\n if (shortCut) {\n // render all the line in one pass without checking\n // drawingLeft = isLtr ? left : left - this.getLineWidth(lineIndex);\n this._renderChar(method, ctx, lineIndex, 0, line.join(''), left, top, lineHeight);\n ctx.restore();\n return;\n }\n for (var i = 0, len = line.length - 1; i <= len; i++) {\n timeToRender = i === len || this.charSpacing || path;\n charsToRender += line[i];\n charBox = this.__charBounds[lineIndex][i];\n if (boxWidth === 0) {\n left += sign * (charBox.kernedWidth - charBox.width);\n boxWidth += charBox.width;\n }\n else {\n boxWidth += charBox.kernedWidth;\n }\n if (isJustify && !timeToRender) {\n if (this._reSpaceAndTab.test(line[i])) {\n timeToRender = true;\n }\n }\n if (!timeToRender) {\n // if we have charSpacing, we render char by char\n actualStyle = actualStyle || this.getCompleteStyleDeclaration(lineIndex, i);\n nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1);\n timeToRender = this._hasStyleChanged(actualStyle, nextStyle);\n }\n if (timeToRender) {\n if (path) {\n ctx.save();\n ctx.translate(charBox.renderLeft, charBox.renderTop);\n ctx.rotate(charBox.angle);\n this._renderChar(method, ctx, lineIndex, i, charsToRender, -boxWidth / 2, 0, lineHeight);\n ctx.restore();\n }\n else {\n drawingLeft = left;\n this._renderChar(method, ctx, lineIndex, i, charsToRender, drawingLeft, top, lineHeight);\n }\n charsToRender = '';\n actualStyle = nextStyle;\n left += sign * boxWidth;\n boxWidth = 0;\n }\n }\n ctx.restore();\n },\n\n /**\n * This function try to patch the missing gradientTransform on canvas gradients.\n * transforming a context to transform the gradient, is going to transform the stroke too.\n * we want to transform the gradient but not the stroke operation, so we create\n * a transformed gradient on a pattern and then we use the pattern instead of the gradient.\n * this method has drawbacks: is slow, is in low resolution, needs a patch for when the size\n * is limited.\n * @private\n * @param {fabric.Gradient} filler a fabric gradient instance\n * @return {CanvasPattern} a pattern to use as fill/stroke style\n */\n _applyPatternGradientTransformText: function(filler) {\n var pCanvas = fabric.util.createCanvasElement(), pCtx,\n // TODO: verify compatibility with strokeUniform\n width = this.width + this.strokeWidth, height = this.height + this.strokeWidth;\n pCanvas.width = width;\n pCanvas.height = height;\n pCtx = pCanvas.getContext('2d');\n pCtx.beginPath(); pCtx.moveTo(0, 0); pCtx.lineTo(width, 0); pCtx.lineTo(width, height);\n pCtx.lineTo(0, height); pCtx.closePath();\n pCtx.translate(width / 2, height / 2);\n pCtx.fillStyle = filler.toLive(pCtx);\n this._applyPatternGradientTransform(pCtx, filler);\n pCtx.fill();\n return pCtx.createPattern(pCanvas, 'no-repeat');\n },\n\n handleFiller: function(ctx, property, filler) {\n var offsetX, offsetY;\n if (filler.toLive) {\n if (filler.gradientUnits === 'percentage' || filler.gradientTransform || filler.patternTransform) {\n // need to transform gradient in a pattern.\n // this is a slow process. If you are hitting this codepath, and the object\n // is not using caching, you should consider switching it on.\n // we need a canvas as big as the current object caching canvas.\n offsetX = -this.width / 2;\n offsetY = -this.height / 2;\n ctx.translate(offsetX, offsetY);\n ctx[property] = this._applyPatternGradientTransformText(filler);\n return { offsetX: offsetX, offsetY: offsetY };\n }\n else {\n // is a simple gradient or pattern\n ctx[property] = filler.toLive(ctx, this);\n return this._applyPatternGradientTransform(ctx, filler);\n }\n }\n else {\n // is a color\n ctx[property] = filler;\n }\n return { offsetX: 0, offsetY: 0 };\n },\n\n _setStrokeStyles: function(ctx, decl) {\n ctx.lineWidth = decl.strokeWidth;\n ctx.lineCap = this.strokeLineCap;\n ctx.lineDashOffset = this.strokeDashOffset;\n ctx.lineJoin = this.strokeLineJoin;\n ctx.miterLimit = this.strokeMiterLimit;\n return this.handleFiller(ctx, 'strokeStyle', decl.stroke);\n },\n\n _setFillStyles: function(ctx, decl) {\n return this.handleFiller(ctx, 'fillStyle', decl.fill);\n },\n\n /**\n * @private\n * @param {String} method\n * @param {CanvasRenderingContext2D} ctx Context to render on\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @param {String} _char\n * @param {Number} left Left coordinate\n * @param {Number} top Top coordinate\n * @param {Number} lineHeight Height of the line\n */\n _renderChar: function(method, ctx, lineIndex, charIndex, _char, left, top) {\n var decl = this._getStyleDeclaration(lineIndex, charIndex),\n fullDecl = this.getCompleteStyleDeclaration(lineIndex, charIndex),\n shouldFill = method === 'fillText' && fullDecl.fill,\n shouldStroke = method === 'strokeText' && fullDecl.stroke && fullDecl.strokeWidth,\n fillOffsets, strokeOffsets;\n\n if (!shouldStroke && !shouldFill) {\n return;\n }\n ctx.save();\n\n shouldFill && (fillOffsets = this._setFillStyles(ctx, fullDecl));\n shouldStroke && (strokeOffsets = this._setStrokeStyles(ctx, fullDecl));\n\n ctx.font = this._getFontDeclaration(fullDecl);\n\n\n if (decl && decl.textBackgroundColor) {\n this._removeShadow(ctx);\n }\n if (decl && decl.deltaY) {\n top += decl.deltaY;\n }\n shouldFill && ctx.fillText(_char, left - fillOffsets.offsetX, top - fillOffsets.offsetY);\n shouldStroke && ctx.strokeText(_char, left - strokeOffsets.offsetX, top - strokeOffsets.offsetY);\n ctx.restore();\n },\n\n /**\n * Turns the character into a 'superior figure' (i.e. 'superscript')\n * @param {Number} start selection start\n * @param {Number} end selection end\n * @returns {fabric.Text} thisArg\n * @chainable\n */\n setSuperscript: function(start, end) {\n return this._setScript(start, end, this.superscript);\n },\n\n /**\n * Turns the character into an 'inferior figure' (i.e. 'subscript')\n * @param {Number} start selection start\n * @param {Number} end selection end\n * @returns {fabric.Text} thisArg\n * @chainable\n */\n setSubscript: function(start, end) {\n return this._setScript(start, end, this.subscript);\n },\n\n /**\n * Applies 'schema' at given position\n * @private\n * @param {Number} start selection start\n * @param {Number} end selection end\n * @param {Number} schema\n * @returns {fabric.Text} thisArg\n * @chainable\n */\n _setScript: function(start, end, schema) {\n var loc = this.get2DCursorLocation(start, true),\n fontSize = this.getValueOfPropertyAt(loc.lineIndex, loc.charIndex, 'fontSize'),\n dy = this.getValueOfPropertyAt(loc.lineIndex, loc.charIndex, 'deltaY'),\n style = { fontSize: fontSize * schema.size, deltaY: dy + fontSize * schema.baseline };\n this.setSelectionStyles(style, start, end);\n return this;\n },\n\n /**\n * @private\n * @param {Object} prevStyle\n * @param {Object} thisStyle\n */\n _hasStyleChanged: function(prevStyle, thisStyle) {\n return prevStyle.fill !== thisStyle.fill ||\n prevStyle.stroke !== thisStyle.stroke ||\n prevStyle.strokeWidth !== thisStyle.strokeWidth ||\n prevStyle.fontSize !== thisStyle.fontSize ||\n prevStyle.fontFamily !== thisStyle.fontFamily ||\n prevStyle.fontWeight !== thisStyle.fontWeight ||\n prevStyle.fontStyle !== thisStyle.fontStyle ||\n prevStyle.deltaY !== thisStyle.deltaY;\n },\n\n /**\n * @private\n * @param {Object} prevStyle\n * @param {Object} thisStyle\n */\n _hasStyleChangedForSvg: function(prevStyle, thisStyle) {\n return this._hasStyleChanged(prevStyle, thisStyle) ||\n prevStyle.overline !== thisStyle.overline ||\n prevStyle.underline !== thisStyle.underline ||\n prevStyle.linethrough !== thisStyle.linethrough;\n },\n\n /**\n * @private\n * @param {Number} lineIndex index text line\n * @return {Number} Line left offset\n */\n _getLineLeftOffset: function(lineIndex) {\n var lineWidth = this.getLineWidth(lineIndex),\n lineDiff = this.width - lineWidth, textAlign = this.textAlign, direction = this.direction,\n isEndOfWrapping, leftOffset = 0, isEndOfWrapping = this.isEndOfWrapping(lineIndex);\n if (textAlign === 'justify'\n || (textAlign === 'justify-center' && !isEndOfWrapping)\n || (textAlign === 'justify-right' && !isEndOfWrapping)\n || (textAlign === 'justify-left' && !isEndOfWrapping)\n ) {\n return 0;\n }\n if (textAlign === 'center') {\n leftOffset = lineDiff / 2;\n }\n if (textAlign === 'right') {\n leftOffset = lineDiff;\n }\n if (textAlign === 'justify-center') {\n leftOffset = lineDiff / 2;\n }\n if (textAlign === 'justify-right') {\n leftOffset = lineDiff;\n }\n if (direction === 'rtl') {\n leftOffset -= lineDiff;\n }\n return leftOffset;\n },\n\n /**\n * @private\n */\n _clearCache: function() {\n this.__lineWidths = [];\n this.__lineHeights = [];\n this.__charBounds = [];\n },\n\n /**\n * @private\n */\n _shouldClearDimensionCache: function() {\n var shouldClear = this._forceClearCache;\n shouldClear || (shouldClear = this.hasStateChanged('_dimensionAffectingProps'));\n if (shouldClear) {\n this.dirty = true;\n this._forceClearCache = false;\n }\n return shouldClear;\n },\n\n /**\n * Measure a single line given its index. Used to calculate the initial\n * text bounding box. The values are calculated and stored in __lineWidths cache.\n * @private\n * @param {Number} lineIndex line number\n * @return {Number} Line width\n */\n getLineWidth: function(lineIndex) {\n if (this.__lineWidths[lineIndex] !== undefined) {\n return this.__lineWidths[lineIndex];\n }\n\n var lineInfo = this.measureLine(lineIndex);\n var width = lineInfo.width;\n this.__lineWidths[lineIndex] = width;\n return width;\n },\n\n _getWidthOfCharSpacing: function() {\n if (this.charSpacing !== 0) {\n return this.fontSize * this.charSpacing / 1000;\n }\n return 0;\n },\n\n /**\n * Retrieves the value of property at given character position\n * @param {Number} lineIndex the line number\n * @param {Number} charIndex the character number\n * @param {String} property the property name\n * @returns the value of 'property'\n */\n getValueOfPropertyAt: function(lineIndex, charIndex, property) {\n var charStyle = this._getStyleDeclaration(lineIndex, charIndex);\n if (charStyle && typeof charStyle[property] !== 'undefined') {\n return charStyle[property];\n }\n return this[property];\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _renderTextDecoration: function(ctx, type) {\n if (!this[type] && !this.styleHas(type)) {\n return;\n }\n var heightOfLine, size, _size,\n lineLeftOffset, dy, _dy,\n line, lastDecoration,\n leftOffset = this._getLeftOffset(),\n topOffset = this._getTopOffset(), top,\n boxStart, boxWidth, charBox, currentDecoration,\n maxHeight, currentFill, lastFill, path = this.path,\n charSpacing = this._getWidthOfCharSpacing(),\n offsetY = this.offsets[type];\n\n for (var i = 0, len = this._textLines.length; i < len; i++) {\n heightOfLine = this.getHeightOfLine(i);\n if (!this[type] && !this.styleHas(type, i)) {\n topOffset += heightOfLine;\n continue;\n }\n line = this._textLines[i];\n maxHeight = heightOfLine / this.lineHeight;\n lineLeftOffset = this._getLineLeftOffset(i);\n boxStart = 0;\n boxWidth = 0;\n lastDecoration = this.getValueOfPropertyAt(i, 0, type);\n lastFill = this.getValueOfPropertyAt(i, 0, 'fill');\n top = topOffset + maxHeight * (1 - this._fontSizeFraction);\n size = this.getHeightOfChar(i, 0);\n dy = this.getValueOfPropertyAt(i, 0, 'deltaY');\n for (var j = 0, jlen = line.length; j < jlen; j++) {\n charBox = this.__charBounds[i][j];\n currentDecoration = this.getValueOfPropertyAt(i, j, type);\n currentFill = this.getValueOfPropertyAt(i, j, 'fill');\n _size = this.getHeightOfChar(i, j);\n _dy = this.getValueOfPropertyAt(i, j, 'deltaY');\n if (path && currentDecoration && currentFill) {\n ctx.save();\n ctx.fillStyle = lastFill;\n ctx.translate(charBox.renderLeft, charBox.renderTop);\n ctx.rotate(charBox.angle);\n ctx.fillRect(\n -charBox.kernedWidth / 2,\n offsetY * _size + _dy,\n charBox.kernedWidth,\n this.fontSize / 15\n );\n ctx.restore();\n }\n else if (\n (currentDecoration !== lastDecoration || currentFill !== lastFill || _size !== size || _dy !== dy)\n && boxWidth > 0\n ) {\n var drawStart = leftOffset + lineLeftOffset + boxStart;\n if (this.direction === 'rtl') {\n drawStart = this.width - drawStart - boxWidth;\n }\n if (lastDecoration && lastFill) {\n ctx.fillStyle = lastFill;\n ctx.fillRect(\n drawStart,\n top + offsetY * size + dy,\n boxWidth,\n this.fontSize / 15\n );\n }\n boxStart = charBox.left;\n boxWidth = charBox.width;\n lastDecoration = currentDecoration;\n lastFill = currentFill;\n size = _size;\n dy = _dy;\n }\n else {\n boxWidth += charBox.kernedWidth;\n }\n }\n var drawStart = leftOffset + lineLeftOffset + boxStart;\n if (this.direction === 'rtl') {\n drawStart = this.width - drawStart - boxWidth;\n }\n ctx.fillStyle = currentFill;\n currentDecoration && currentFill && ctx.fillRect(\n drawStart,\n top + offsetY * size + dy,\n boxWidth - charSpacing,\n this.fontSize / 15\n );\n topOffset += heightOfLine;\n }\n // if there is text background color no\n // other shadows should be casted\n this._removeShadow(ctx);\n },\n\n /**\n * return font declaration string for canvas context\n * @param {Object} [styleObject] object\n * @returns {String} font declaration formatted for canvas context.\n */\n _getFontDeclaration: function(styleObject, forMeasuring) {\n var style = styleObject || this, family = this.fontFamily,\n fontIsGeneric = fabric.Text.genericFonts.indexOf(family.toLowerCase()) > -1;\n var fontFamily = family === undefined ||\n family.indexOf('\\'') > -1 || family.indexOf(',') > -1 ||\n family.indexOf('\"') > -1 || fontIsGeneric\n ? style.fontFamily : '\"' + style.fontFamily + '\"';\n return [\n // node-canvas needs \"weight style\", while browsers need \"style weight\"\n // verify if this can be fixed in JSDOM\n (fabric.isLikelyNode ? style.fontWeight : style.fontStyle),\n (fabric.isLikelyNode ? style.fontStyle : style.fontWeight),\n forMeasuring ? this.CACHE_FONT_SIZE + 'px' : style.fontSize + 'px',\n fontFamily\n ].join(' ');\n },\n\n /**\n * Renders text instance on a specified context\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n render: function(ctx) {\n // do not render if object is not visible\n if (!this.visible) {\n return;\n }\n if (this.canvas && this.canvas.skipOffscreen && !this.group && !this.isOnScreen()) {\n return;\n }\n if (this._shouldClearDimensionCache()) {\n this.initDimensions();\n }\n this.callSuper('render', ctx);\n },\n\n /**\n * Returns the text as an array of lines.\n * @param {String} text text to split\n * @returns {Array} Lines in the text\n */\n _splitTextIntoLines: function(text) {\n var lines = text.split(this._reNewline),\n newLines = new Array(lines.length),\n newLine = ['\\n'],\n newText = [];\n for (var i = 0; i < lines.length; i++) {\n newLines[i] = fabric.util.string.graphemeSplit(lines[i]);\n newText = newText.concat(newLines[i], newLine);\n }\n newText.pop();\n return { _unwrappedLines: newLines, lines: lines, graphemeText: newText, graphemeLines: newLines };\n },\n\n /**\n * Returns object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} Object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n var allProperties = additionalProps.concat(propertiesToInclude);\n var obj = this.callSuper('toObject', allProperties);\n // styles will be overridden with a properly cloned structure\n obj.styles = clone(this.styles, true);\n if (obj.path) {\n obj.path = this.path.toObject();\n }\n return obj;\n },\n\n /**\n * Sets property to a given value. When changing position/dimension -related properties (left, top, scale, angle, etc.) `set` does not update position of object's borders/controls. If you need to update those, call `setCoords()`.\n * @param {String|Object} key Property name or object (if object, iterate over the object properties)\n * @param {Object|Function} value Property value (if function, the value is passed into it and its return value is used as a new one)\n * @return {fabric.Object} thisArg\n * @chainable\n */\n set: function(key, value) {\n this.callSuper('set', key, value);\n var needsDims = false;\n var isAddingPath = false;\n if (typeof key === 'object') {\n for (var _key in key) {\n if (_key === 'path') {\n this.setPathInfo();\n }\n needsDims = needsDims || this._dimensionAffectingProps.indexOf(_key) !== -1;\n isAddingPath = isAddingPath || _key === 'path';\n }\n }\n else {\n needsDims = this._dimensionAffectingProps.indexOf(key) !== -1;\n isAddingPath = key === 'path';\n }\n if (isAddingPath) {\n this.setPathInfo();\n }\n if (needsDims) {\n this.initDimensions();\n this.setCoords();\n }\n return this;\n },\n\n /**\n * Returns complexity of an instance\n * @return {Number} complexity\n */\n complexity: function() {\n return 1;\n }\n });\n\n /* _FROM_SVG_START_ */\n /**\n * List of attribute names to account for when parsing SVG element (used by {@link fabric.Text.fromElement})\n * @static\n * @memberOf fabric.Text\n * @see: http://www.w3.org/TR/SVG/text.html#TextElement\n */\n fabric.Text.ATTRIBUTE_NAMES = fabric.SHARED_ATTRIBUTES.concat(\n 'x y dx dy font-family font-style font-weight font-size letter-spacing text-decoration text-anchor'.split(' '));\n\n /**\n * Default SVG font size\n * @static\n * @memberOf fabric.Text\n */\n fabric.Text.DEFAULT_SVG_FONT_SIZE = 16;\n\n /**\n * Returns fabric.Text instance from an SVG element (not yet implemented)\n * @static\n * @memberOf fabric.Text\n * @param {SVGElement} element Element to parse\n * @param {Function} callback callback function invoked after parsing\n * @param {Object} [options] Options object\n */\n fabric.Text.fromElement = function(element, callback, options) {\n if (!element) {\n return callback(null);\n }\n\n var parsedAttributes = fabric.parseAttributes(element, fabric.Text.ATTRIBUTE_NAMES),\n parsedAnchor = parsedAttributes.textAnchor || 'left';\n options = fabric.util.object.extend((options ? clone(options) : { }), parsedAttributes);\n\n options.top = options.top || 0;\n options.left = options.left || 0;\n if (parsedAttributes.textDecoration) {\n var textDecoration = parsedAttributes.textDecoration;\n if (textDecoration.indexOf('underline') !== -1) {\n options.underline = true;\n }\n if (textDecoration.indexOf('overline') !== -1) {\n options.overline = true;\n }\n if (textDecoration.indexOf('line-through') !== -1) {\n options.linethrough = true;\n }\n delete options.textDecoration;\n }\n if ('dx' in parsedAttributes) {\n options.left += parsedAttributes.dx;\n }\n if ('dy' in parsedAttributes) {\n options.top += parsedAttributes.dy;\n }\n if (!('fontSize' in options)) {\n options.fontSize = fabric.Text.DEFAULT_SVG_FONT_SIZE;\n }\n\n var textContent = '';\n\n // The XML is not properly parsed in IE9 so a workaround to get\n // textContent is through firstChild.data. Another workaround would be\n // to convert XML loaded from a file to be converted using DOMParser (same way loadSVGFromString() does)\n if (!('textContent' in element)) {\n if ('firstChild' in element && element.firstChild !== null) {\n if ('data' in element.firstChild && element.firstChild.data !== null) {\n textContent = element.firstChild.data;\n }\n }\n }\n else {\n textContent = element.textContent;\n }\n\n textContent = textContent.replace(/^\\s+|\\s+$|\\n+/g, '').replace(/\\s+/g, ' ');\n var originalStrokeWidth = options.strokeWidth;\n options.strokeWidth = 0;\n\n var text = new fabric.Text(textContent, options),\n textHeightScaleFactor = text.getScaledHeight() / text.height,\n lineHeightDiff = (text.height + text.strokeWidth) * text.lineHeight - text.height,\n scaledDiff = lineHeightDiff * textHeightScaleFactor,\n textHeight = text.getScaledHeight() + scaledDiff,\n offX = 0;\n /*\n Adjust positioning:\n x/y attributes in SVG correspond to the bottom-left corner of text bounding box\n fabric output by default at top, left.\n */\n if (parsedAnchor === 'center') {\n offX = text.getScaledWidth() / 2;\n }\n if (parsedAnchor === 'right') {\n offX = text.getScaledWidth();\n }\n text.set({\n left: text.left - offX,\n top: text.top - (textHeight - text.fontSize * (0.07 + text._fontSizeFraction)) / text.lineHeight,\n strokeWidth: typeof originalStrokeWidth !== 'undefined' ? originalStrokeWidth : 1,\n });\n callback(text);\n };\n /* _FROM_SVG_END_ */\n\n /**\n * Returns fabric.Text instance from an object representation\n * @static\n * @memberOf fabric.Text\n * @param {Object} object plain js Object to create an instance from\n * @param {Function} [callback] Callback to invoke when an fabric.Text instance is created\n */\n fabric.Text.fromObject = function(object, callback) {\n var objectCopy = clone(object), path = object.path;\n delete objectCopy.path;\n return fabric.Object._fromObject('Text', objectCopy, function(textInstance) {\n if (path) {\n fabric.Object._fromObject('Path', path, function(pathInstance) {\n textInstance.set('path', pathInstance);\n callback(textInstance);\n }, 'path');\n }\n else {\n callback(textInstance);\n }\n }, 'text');\n };\n\n fabric.Text.genericFonts = ['sans-serif', 'serif', 'cursive', 'fantasy', 'monospace'];\n\n fabric.util.createAccessors && fabric.util.createAccessors(fabric.Text);\n\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n fabric.util.object.extend(fabric.Text.prototype, /** @lends fabric.Text.prototype */ {\n /**\n * Returns true if object has no styling or no styling in a line\n * @param {Number} lineIndex , lineIndex is on wrapped lines.\n * @return {Boolean}\n */\n isEmptyStyles: function(lineIndex) {\n if (!this.styles) {\n return true;\n }\n if (typeof lineIndex !== 'undefined' && !this.styles[lineIndex]) {\n return true;\n }\n var obj = typeof lineIndex === 'undefined' ? this.styles : { line: this.styles[lineIndex] };\n for (var p1 in obj) {\n for (var p2 in obj[p1]) {\n // eslint-disable-next-line no-unused-vars\n for (var p3 in obj[p1][p2]) {\n return false;\n }\n }\n }\n return true;\n },\n\n /**\n * Returns true if object has a style property or has it ina specified line\n * This function is used to detect if a text will use a particular property or not.\n * @param {String} property to check for\n * @param {Number} lineIndex to check the style on\n * @return {Boolean}\n */\n styleHas: function(property, lineIndex) {\n if (!this.styles || !property || property === '') {\n return false;\n }\n if (typeof lineIndex !== 'undefined' && !this.styles[lineIndex]) {\n return false;\n }\n var obj = typeof lineIndex === 'undefined' ? this.styles : { 0: this.styles[lineIndex] };\n // eslint-disable-next-line\n for (var p1 in obj) {\n // eslint-disable-next-line\n for (var p2 in obj[p1]) {\n if (typeof obj[p1][p2][property] !== 'undefined') {\n return true;\n }\n }\n }\n return false;\n },\n\n /**\n * Check if characters in a text have a value for a property\n * whose value matches the textbox's value for that property. If so,\n * the character-level property is deleted. If the character\n * has no other properties, then it is also deleted. Finally,\n * if the line containing that character has no other characters\n * then it also is deleted.\n *\n * @param {string} property The property to compare between characters and text.\n */\n cleanStyle: function(property) {\n if (!this.styles || !property || property === '') {\n return false;\n }\n var obj = this.styles, stylesCount = 0, letterCount, stylePropertyValue,\n allStyleObjectPropertiesMatch = true, graphemeCount = 0, styleObject;\n // eslint-disable-next-line\n for (var p1 in obj) {\n letterCount = 0;\n // eslint-disable-next-line\n for (var p2 in obj[p1]) {\n var styleObject = obj[p1][p2],\n stylePropertyHasBeenSet = styleObject.hasOwnProperty(property);\n\n stylesCount++;\n\n if (stylePropertyHasBeenSet) {\n if (!stylePropertyValue) {\n stylePropertyValue = styleObject[property];\n }\n else if (styleObject[property] !== stylePropertyValue) {\n allStyleObjectPropertiesMatch = false;\n }\n\n if (styleObject[property] === this[property]) {\n delete styleObject[property];\n }\n }\n else {\n allStyleObjectPropertiesMatch = false;\n }\n\n if (Object.keys(styleObject).length !== 0) {\n letterCount++;\n }\n else {\n delete obj[p1][p2];\n }\n }\n\n if (letterCount === 0) {\n delete obj[p1];\n }\n }\n // if every grapheme has the same style set then\n // delete those styles and set it on the parent\n for (var i = 0; i < this._textLines.length; i++) {\n graphemeCount += this._textLines[i].length;\n }\n if (allStyleObjectPropertiesMatch && stylesCount === graphemeCount) {\n this[property] = stylePropertyValue;\n this.removeStyle(property);\n }\n },\n\n /**\n * Remove a style property or properties from all individual character styles\n * in a text object. Deletes the character style object if it contains no other style\n * props. Deletes a line style object if it contains no other character styles.\n *\n * @param {String} props The property to remove from character styles.\n */\n removeStyle: function(property) {\n if (!this.styles || !property || property === '') {\n return;\n }\n var obj = this.styles, line, lineNum, charNum;\n for (lineNum in obj) {\n line = obj[lineNum];\n for (charNum in line) {\n delete line[charNum][property];\n if (Object.keys(line[charNum]).length === 0) {\n delete line[charNum];\n }\n }\n if (Object.keys(line).length === 0) {\n delete obj[lineNum];\n }\n }\n },\n\n /**\n * @private\n */\n _extendStyles: function(index, styles) {\n var loc = this.get2DCursorLocation(index);\n\n if (!this._getLineStyle(loc.lineIndex)) {\n this._setLineStyle(loc.lineIndex);\n }\n\n if (!this._getStyleDeclaration(loc.lineIndex, loc.charIndex)) {\n this._setStyleDeclaration(loc.lineIndex, loc.charIndex, {});\n }\n\n fabric.util.object.extend(this._getStyleDeclaration(loc.lineIndex, loc.charIndex), styles);\n },\n\n /**\n * Returns 2d representation (lineIndex and charIndex) of cursor (or selection start)\n * @param {Number} [selectionStart] Optional index. When not given, current selectionStart is used.\n * @param {Boolean} [skipWrapping] consider the location for unwrapped lines. useful to manage styles.\n */\n get2DCursorLocation: function(selectionStart, skipWrapping) {\n if (typeof selectionStart === 'undefined') {\n selectionStart = this.selectionStart;\n }\n var lines = skipWrapping ? this._unwrappedTextLines : this._textLines,\n len = lines.length;\n for (var i = 0; i < len; i++) {\n if (selectionStart <= lines[i].length) {\n return {\n lineIndex: i,\n charIndex: selectionStart\n };\n }\n selectionStart -= lines[i].length + this.missingNewlineOffset(i);\n }\n return {\n lineIndex: i - 1,\n charIndex: lines[i - 1].length < selectionStart ? lines[i - 1].length : selectionStart\n };\n },\n\n /**\n * Gets style of a current selection/cursor (at the start position)\n * if startIndex or endIndex are not provided, selectionStart or selectionEnd will be used.\n * @param {Number} [startIndex] Start index to get styles at\n * @param {Number} [endIndex] End index to get styles at, if not specified selectionEnd or startIndex + 1\n * @param {Boolean} [complete] get full style or not\n * @return {Array} styles an array with one, zero or more Style objects\n */\n getSelectionStyles: function(startIndex, endIndex, complete) {\n if (typeof startIndex === 'undefined') {\n startIndex = this.selectionStart || 0;\n }\n if (typeof endIndex === 'undefined') {\n endIndex = this.selectionEnd || startIndex;\n }\n var styles = [];\n for (var i = startIndex; i < endIndex; i++) {\n styles.push(this.getStyleAtPosition(i, complete));\n }\n return styles;\n },\n\n /**\n * Gets style of a current selection/cursor position\n * @param {Number} position to get styles at\n * @param {Boolean} [complete] full style if true\n * @return {Object} style Style object at a specified index\n * @private\n */\n getStyleAtPosition: function(position, complete) {\n var loc = this.get2DCursorLocation(position),\n style = complete ? this.getCompleteStyleDeclaration(loc.lineIndex, loc.charIndex) :\n this._getStyleDeclaration(loc.lineIndex, loc.charIndex);\n return style || {};\n },\n\n /**\n * Sets style of a current selection, if no selection exist, do not set anything.\n * @param {Object} [styles] Styles object\n * @param {Number} [startIndex] Start index to get styles at\n * @param {Number} [endIndex] End index to get styles at, if not specified selectionEnd or startIndex + 1\n * @return {fabric.IText} thisArg\n * @chainable\n */\n setSelectionStyles: function(styles, startIndex, endIndex) {\n if (typeof startIndex === 'undefined') {\n startIndex = this.selectionStart || 0;\n }\n if (typeof endIndex === 'undefined') {\n endIndex = this.selectionEnd || startIndex;\n }\n for (var i = startIndex; i < endIndex; i++) {\n this._extendStyles(i, styles);\n }\n /* not included in _extendStyles to avoid clearing cache more than once */\n this._forceClearCache = true;\n return this;\n },\n\n /**\n * get the reference, not a clone, of the style object for a given character\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @return {Object} style object\n */\n _getStyleDeclaration: function(lineIndex, charIndex) {\n var lineStyle = this.styles && this.styles[lineIndex];\n if (!lineStyle) {\n return null;\n }\n return lineStyle[charIndex];\n },\n\n /**\n * return a new object that contains all the style property for a character\n * the object returned is newly created\n * @param {Number} lineIndex of the line where the character is\n * @param {Number} charIndex position of the character on the line\n * @return {Object} style object\n */\n getCompleteStyleDeclaration: function(lineIndex, charIndex) {\n var style = this._getStyleDeclaration(lineIndex, charIndex) || { },\n styleObject = { }, prop;\n for (var i = 0; i < this._styleProperties.length; i++) {\n prop = this._styleProperties[i];\n styleObject[prop] = typeof style[prop] === 'undefined' ? this[prop] : style[prop];\n }\n return styleObject;\n },\n\n /**\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @param {Object} style\n * @private\n */\n _setStyleDeclaration: function(lineIndex, charIndex, style) {\n this.styles[lineIndex][charIndex] = style;\n },\n\n /**\n *\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @private\n */\n _deleteStyleDeclaration: function(lineIndex, charIndex) {\n delete this.styles[lineIndex][charIndex];\n },\n\n /**\n * @param {Number} lineIndex\n * @return {Boolean} if the line exists or not\n * @private\n */\n _getLineStyle: function(lineIndex) {\n return !!this.styles[lineIndex];\n },\n\n /**\n * Set the line style to an empty object so that is initialized\n * @param {Number} lineIndex\n * @private\n */\n _setLineStyle: function(lineIndex) {\n this.styles[lineIndex] = {};\n },\n\n /**\n * @param {Number} lineIndex\n * @private\n */\n _deleteLineStyle: function(lineIndex) {\n delete this.styles[lineIndex];\n }\n });\n})();\n\n\n(function() {\n\n function parseDecoration(object) {\n if (object.textDecoration) {\n object.textDecoration.indexOf('underline') > -1 && (object.underline = true);\n object.textDecoration.indexOf('line-through') > -1 && (object.linethrough = true);\n object.textDecoration.indexOf('overline') > -1 && (object.overline = true);\n delete object.textDecoration;\n }\n }\n\n /**\n * IText class (introduced in v1.4) Events are also fired with \"text:\"\n * prefix when observing canvas.\n * @class fabric.IText\n * @extends fabric.Text\n * @mixes fabric.Observable\n *\n * @fires changed\n * @fires selection:changed\n * @fires editing:entered\n * @fires editing:exited\n *\n * @return {fabric.IText} thisArg\n * @see {@link fabric.IText#initialize} for constructor definition\n *\n *

Supported key combinations:

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

Supported mouse/touch combination

\n *
\n   *   Position cursor:                click/touch\n   *   Create selection:               click/touch & drag\n   *   Create selection:               click & shift + click\n   *   Select word:                    double click\n   *   Select line:                    triple click\n   * 
\n */\n fabric.IText = fabric.util.createClass(fabric.Text, fabric.Observable, /** @lends fabric.IText.prototype */ {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'i-text',\n\n /**\n * Index where text selection starts (or where cursor is when there is no selection)\n * @type Number\n * @default\n */\n selectionStart: 0,\n\n /**\n * Index where text selection ends\n * @type Number\n * @default\n */\n selectionEnd: 0,\n\n /**\n * Color of text selection\n * @type String\n * @default\n */\n selectionColor: 'rgba(17,119,255,0.3)',\n\n /**\n * Indicates whether text is in editing mode\n * @type Boolean\n * @default\n */\n isEditing: false,\n\n /**\n * Indicates whether a text can be edited\n * @type Boolean\n * @default\n */\n editable: true,\n\n /**\n * Border color of text object while it's in editing mode\n * @type String\n * @default\n */\n editingBorderColor: 'rgba(102,153,255,0.25)',\n\n /**\n * Width of cursor (in px)\n * @type Number\n * @default\n */\n cursorWidth: 2,\n\n /**\n * Color of text cursor color in editing mode.\n * if not set (default) will take color from the text.\n * if set to a color value that fabric can understand, it will\n * be used instead of the color of the text at the current position.\n * @type String\n * @default\n */\n cursorColor: '',\n\n /**\n * Delay between cursor blink (in ms)\n * @type Number\n * @default\n */\n cursorDelay: 1000,\n\n /**\n * Duration of cursor fadein (in ms)\n * @type Number\n * @default\n */\n cursorDuration: 600,\n\n /**\n * Indicates whether internal text char widths can be cached\n * @type Boolean\n * @default\n */\n caching: true,\n\n /**\n * DOM container to append the hiddenTextarea.\n * An alternative to attaching to the document.body.\n * Useful to reduce laggish redraw of the full document.body tree and\n * also with modals event capturing that won't let the textarea take focus.\n * @type HTMLElement\n * @default\n */\n hiddenTextareaContainer: null,\n\n /**\n * @private\n */\n _reSpace: /\\s|\\n/,\n\n /**\n * @private\n */\n _currentCursorOpacity: 0,\n\n /**\n * @private\n */\n _selectionDirection: null,\n\n /**\n * @private\n */\n _abortCursorAnimation: false,\n\n /**\n * @private\n */\n __widthOfSpace: [],\n\n /**\n * Helps determining when the text is in composition, so that the cursor\n * rendering is altered.\n */\n inCompositionMode: false,\n\n /**\n * Constructor\n * @param {String} text Text string\n * @param {Object} [options] Options object\n * @return {fabric.IText} thisArg\n */\n initialize: function(text, options) {\n this.callSuper('initialize', text, options);\n this.initBehavior();\n },\n\n /**\n * Sets selection start (left boundary of a selection)\n * @param {Number} index Index to set selection start to\n */\n setSelectionStart: function(index) {\n index = Math.max(index, 0);\n this._updateAndFire('selectionStart', index);\n },\n\n /**\n * Sets selection end (right boundary of a selection)\n * @param {Number} index Index to set selection end to\n */\n setSelectionEnd: function(index) {\n index = Math.min(index, this.text.length);\n this._updateAndFire('selectionEnd', index);\n },\n\n /**\n * @private\n * @param {String} property 'selectionStart' or 'selectionEnd'\n * @param {Number} index new position of property\n */\n _updateAndFire: function(property, index) {\n if (this[property] !== index) {\n this._fireSelectionChanged();\n this[property] = index;\n }\n this._updateTextarea();\n },\n\n /**\n * Fires the even of selection changed\n * @private\n */\n _fireSelectionChanged: function() {\n this.fire('selection:changed');\n this.canvas && this.canvas.fire('text:selection:changed', { target: this });\n },\n\n /**\n * Initialize text dimensions. Render all text on given context\n * or on a offscreen canvas to get the text width with measureText.\n * Updates this.width and this.height with the proper values.\n * Does not return dimensions.\n * @private\n */\n initDimensions: function() {\n this.isEditing && this.initDelayedCursor();\n this.clearContextTop();\n this.callSuper('initDimensions');\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n render: function(ctx) {\n this.clearContextTop();\n this.callSuper('render', ctx);\n // clear the cursorOffsetCache, so we ensure to calculate once per renderCursor\n // the correct position but not at every cursor animation.\n this.cursorOffsetCache = { };\n this.renderCursorOrSelection();\n },\n\n /**\n * @private\n * @param {CanvasRenderingContext2D} ctx Context to render on\n */\n _render: function(ctx) {\n this.callSuper('_render', ctx);\n },\n\n /**\n * Prepare and clean the contextTop\n */\n clearContextTop: function(skipRestore) {\n if (!this.isEditing || !this.canvas || !this.canvas.contextTop) {\n return;\n }\n var ctx = this.canvas.contextTop, v = this.canvas.viewportTransform;\n ctx.save();\n ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);\n this.transform(ctx);\n this._clearTextArea(ctx);\n skipRestore || ctx.restore();\n },\n /**\n * Renders cursor or selection (depending on what exists)\n * it does on the contextTop. If contextTop is not available, do nothing.\n */\n renderCursorOrSelection: function() {\n if (!this.isEditing || !this.canvas || !this.canvas.contextTop) {\n return;\n }\n var boundaries = this._getCursorBoundaries(),\n ctx = this.canvas.contextTop;\n this.clearContextTop(true);\n if (this.selectionStart === this.selectionEnd) {\n this.renderCursor(boundaries, ctx);\n }\n else {\n this.renderSelection(boundaries, ctx);\n }\n ctx.restore();\n },\n\n _clearTextArea: function(ctx) {\n // we add 4 pixel, to be sure to do not leave any pixel out\n var width = this.width + 4, height = this.height + 4;\n ctx.clearRect(-width / 2, -height / 2, width, height);\n },\n\n /**\n * Returns cursor boundaries (left, top, leftOffset, topOffset)\n * @private\n * @param {Array} chars Array of characters\n * @param {String} typeOfBoundaries\n */\n _getCursorBoundaries: function(position) {\n\n // left/top are left/top of entire text box\n // leftOffset/topOffset are offset from that left/top point of a text box\n\n if (typeof position === 'undefined') {\n position = this.selectionStart;\n }\n\n var left = this._getLeftOffset(),\n top = this._getTopOffset(),\n offsets = this._getCursorBoundariesOffsets(position);\n return {\n left: left,\n top: top,\n leftOffset: offsets.left,\n topOffset: offsets.top\n };\n },\n\n /**\n * @private\n */\n _getCursorBoundariesOffsets: function(position) {\n if (this.cursorOffsetCache && 'top' in this.cursorOffsetCache) {\n return this.cursorOffsetCache;\n }\n var lineLeftOffset,\n lineIndex,\n charIndex,\n topOffset = 0,\n leftOffset = 0,\n boundaries,\n cursorPosition = this.get2DCursorLocation(position);\n charIndex = cursorPosition.charIndex;\n lineIndex = cursorPosition.lineIndex;\n for (var i = 0; i < lineIndex; i++) {\n topOffset += this.getHeightOfLine(i);\n }\n lineLeftOffset = this._getLineLeftOffset(lineIndex);\n var bound = this.__charBounds[lineIndex][charIndex];\n bound && (leftOffset = bound.left);\n if (this.charSpacing !== 0 && charIndex === this._textLines[lineIndex].length) {\n leftOffset -= this._getWidthOfCharSpacing();\n }\n boundaries = {\n top: topOffset,\n left: lineLeftOffset + (leftOffset > 0 ? leftOffset : 0),\n };\n if (this.direction === 'rtl') {\n boundaries.left *= -1;\n }\n this.cursorOffsetCache = boundaries;\n return this.cursorOffsetCache;\n },\n\n /**\n * Renders cursor\n * @param {Object} boundaries\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n renderCursor: function(boundaries, ctx) {\n var cursorLocation = this.get2DCursorLocation(),\n lineIndex = cursorLocation.lineIndex,\n charIndex = cursorLocation.charIndex > 0 ? cursorLocation.charIndex - 1 : 0,\n charHeight = this.getValueOfPropertyAt(lineIndex, charIndex, 'fontSize'),\n multiplier = this.scaleX * this.canvas.getZoom(),\n cursorWidth = this.cursorWidth / multiplier,\n topOffset = boundaries.topOffset,\n dy = this.getValueOfPropertyAt(lineIndex, charIndex, 'deltaY');\n topOffset += (1 - this._fontSizeFraction) * this.getHeightOfLine(lineIndex) / this.lineHeight\n - charHeight * (1 - this._fontSizeFraction);\n\n if (this.inCompositionMode) {\n this.renderSelection(boundaries, ctx);\n }\n ctx.fillStyle = this.cursorColor || this.getValueOfPropertyAt(lineIndex, charIndex, 'fill');\n ctx.globalAlpha = this.__isMousedown ? 1 : this._currentCursorOpacity;\n ctx.fillRect(\n boundaries.left + boundaries.leftOffset - cursorWidth / 2,\n topOffset + boundaries.top + dy,\n cursorWidth,\n charHeight);\n },\n\n /**\n * Renders text selection\n * @param {Object} boundaries Object with left/top/leftOffset/topOffset\n * @param {CanvasRenderingContext2D} ctx transformed context to draw on\n */\n renderSelection: function(boundaries, ctx) {\n\n var selectionStart = this.inCompositionMode ? this.hiddenTextarea.selectionStart : this.selectionStart,\n selectionEnd = this.inCompositionMode ? this.hiddenTextarea.selectionEnd : this.selectionEnd,\n isJustify = this.textAlign.indexOf('justify') !== -1,\n start = this.get2DCursorLocation(selectionStart),\n end = this.get2DCursorLocation(selectionEnd),\n startLine = start.lineIndex,\n endLine = end.lineIndex,\n startChar = start.charIndex < 0 ? 0 : start.charIndex,\n endChar = end.charIndex < 0 ? 0 : end.charIndex;\n\n for (var i = startLine; i <= endLine; i++) {\n var lineOffset = this._getLineLeftOffset(i) || 0,\n lineHeight = this.getHeightOfLine(i),\n realLineHeight = 0, boxStart = 0, boxEnd = 0;\n\n if (i === startLine) {\n boxStart = this.__charBounds[startLine][startChar].left;\n }\n if (i >= startLine && i < endLine) {\n boxEnd = isJustify && !this.isEndOfWrapping(i) ? this.width : this.getLineWidth(i) || 5; // WTF is this 5?\n }\n else if (i === endLine) {\n if (endChar === 0) {\n boxEnd = this.__charBounds[endLine][endChar].left;\n }\n else {\n var charSpacing = this._getWidthOfCharSpacing();\n boxEnd = this.__charBounds[endLine][endChar - 1].left\n + this.__charBounds[endLine][endChar - 1].width - charSpacing;\n }\n }\n realLineHeight = lineHeight;\n if (this.lineHeight < 1 || (i === endLine && this.lineHeight > 1)) {\n lineHeight /= this.lineHeight;\n }\n var drawStart = boundaries.left + lineOffset + boxStart,\n drawWidth = boxEnd - boxStart,\n drawHeight = lineHeight, extraTop = 0;\n if (this.inCompositionMode) {\n ctx.fillStyle = this.compositionColor || 'black';\n drawHeight = 1;\n extraTop = lineHeight;\n }\n else {\n ctx.fillStyle = this.selectionColor;\n }\n if (this.direction === 'rtl') {\n drawStart = this.width - drawStart - drawWidth;\n }\n ctx.fillRect(\n drawStart,\n boundaries.top + boundaries.topOffset + extraTop,\n drawWidth,\n drawHeight);\n boundaries.topOffset += realLineHeight;\n }\n },\n\n /**\n * High level function to know the height of the cursor.\n * the currentChar is the one that precedes the cursor\n * Returns fontSize of char at the current cursor\n * Unused from the library, is for the end user\n * @return {Number} Character font size\n */\n getCurrentCharFontSize: function() {\n var cp = this._getCurrentCharIndex();\n return this.getValueOfPropertyAt(cp.l, cp.c, 'fontSize');\n },\n\n /**\n * High level function to know the color of the cursor.\n * the currentChar is the one that precedes the cursor\n * Returns color (fill) of char at the current cursor\n * if the text object has a pattern or gradient for filler, it will return that.\n * Unused by the library, is for the end user\n * @return {String | fabric.Gradient | fabric.Pattern} Character color (fill)\n */\n getCurrentCharColor: function() {\n var cp = this._getCurrentCharIndex();\n return this.getValueOfPropertyAt(cp.l, cp.c, 'fill');\n },\n\n /**\n * Returns the cursor position for the getCurrent.. functions\n * @private\n */\n _getCurrentCharIndex: function() {\n var cursorPosition = this.get2DCursorLocation(this.selectionStart, true),\n charIndex = cursorPosition.charIndex > 0 ? cursorPosition.charIndex - 1 : 0;\n return { l: cursorPosition.lineIndex, c: charIndex };\n }\n });\n\n /**\n * Returns fabric.IText instance from an object representation\n * @static\n * @memberOf fabric.IText\n * @param {Object} object Object to create an instance from\n * @param {function} [callback] invoked with new instance as argument\n */\n fabric.IText.fromObject = function(object, callback) {\n parseDecoration(object);\n if (object.styles) {\n for (var i in object.styles) {\n for (var j in object.styles[i]) {\n parseDecoration(object.styles[i][j]);\n }\n }\n }\n fabric.Object._fromObject('IText', object, callback, 'text');\n };\n})();\n\n\n(function() {\n\n var clone = fabric.util.object.clone;\n\n fabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n /**\n * Initializes all the interactive behavior of IText\n */\n initBehavior: function() {\n this.initAddedHandler();\n this.initRemovedHandler();\n this.initCursorSelectionHandlers();\n this.initDoubleClickSimulation();\n this.mouseMoveHandler = this.mouseMoveHandler.bind(this);\n },\n\n onDeselect: function() {\n this.isEditing && this.exitEditing();\n this.selected = false;\n },\n\n /**\n * Initializes \"added\" event handler\n */\n initAddedHandler: function() {\n var _this = this;\n this.on('added', function() {\n var canvas = _this.canvas;\n if (canvas) {\n if (!canvas._hasITextHandlers) {\n canvas._hasITextHandlers = true;\n _this._initCanvasHandlers(canvas);\n }\n canvas._iTextInstances = canvas._iTextInstances || [];\n canvas._iTextInstances.push(_this);\n }\n });\n },\n\n initRemovedHandler: function() {\n var _this = this;\n this.on('removed', function() {\n var canvas = _this.canvas;\n if (canvas) {\n canvas._iTextInstances = canvas._iTextInstances || [];\n fabric.util.removeFromArray(canvas._iTextInstances, _this);\n if (canvas._iTextInstances.length === 0) {\n canvas._hasITextHandlers = false;\n _this._removeCanvasHandlers(canvas);\n }\n }\n });\n },\n\n /**\n * register canvas event to manage exiting on other instances\n * @private\n */\n _initCanvasHandlers: function(canvas) {\n canvas._mouseUpITextHandler = function() {\n if (canvas._iTextInstances) {\n canvas._iTextInstances.forEach(function(obj) {\n obj.__isMousedown = false;\n });\n }\n };\n canvas.on('mouse:up', canvas._mouseUpITextHandler);\n },\n\n /**\n * remove canvas event to manage exiting on other instances\n * @private\n */\n _removeCanvasHandlers: function(canvas) {\n canvas.off('mouse:up', canvas._mouseUpITextHandler);\n },\n\n /**\n * @private\n */\n _tick: function() {\n this._currentTickState = this._animateCursor(this, 1, this.cursorDuration, '_onTickComplete');\n },\n\n /**\n * @private\n */\n _animateCursor: function(obj, targetOpacity, duration, completeMethod) {\n\n var tickState;\n\n tickState = {\n isAborted: false,\n abort: function() {\n this.isAborted = true;\n },\n };\n\n obj.animate('_currentCursorOpacity', targetOpacity, {\n duration: duration,\n onComplete: function() {\n if (!tickState.isAborted) {\n obj[completeMethod]();\n }\n },\n onChange: function() {\n // we do not want to animate a selection, only cursor\n if (obj.canvas && obj.selectionStart === obj.selectionEnd) {\n obj.renderCursorOrSelection();\n }\n },\n abort: function() {\n return tickState.isAborted;\n }\n });\n return tickState;\n },\n\n /**\n * @private\n */\n _onTickComplete: function() {\n\n var _this = this;\n\n if (this._cursorTimeout1) {\n clearTimeout(this._cursorTimeout1);\n }\n this._cursorTimeout1 = setTimeout(function() {\n _this._currentTickCompleteState = _this._animateCursor(_this, 0, this.cursorDuration / 2, '_tick');\n }, 100);\n },\n\n /**\n * Initializes delayed cursor\n */\n initDelayedCursor: function(restart) {\n var _this = this,\n delay = restart ? 0 : this.cursorDelay;\n\n this.abortCursorAnimation();\n this._currentCursorOpacity = 1;\n this._cursorTimeout2 = setTimeout(function() {\n _this._tick();\n }, delay);\n },\n\n /**\n * Aborts cursor animation and clears all timeouts\n */\n abortCursorAnimation: function() {\n var shouldClear = this._currentTickState || this._currentTickCompleteState,\n canvas = this.canvas;\n this._currentTickState && this._currentTickState.abort();\n this._currentTickCompleteState && this._currentTickCompleteState.abort();\n\n clearTimeout(this._cursorTimeout1);\n clearTimeout(this._cursorTimeout2);\n\n this._currentCursorOpacity = 0;\n // to clear just itext area we need to transform the context\n // it may not be worth it\n if (shouldClear && canvas) {\n canvas.clearContext(canvas.contextTop || canvas.contextContainer);\n }\n\n },\n\n /**\n * Selects entire text\n * @return {fabric.IText} thisArg\n * @chainable\n */\n selectAll: function() {\n this.selectionStart = 0;\n this.selectionEnd = this._text.length;\n this._fireSelectionChanged();\n this._updateTextarea();\n return this;\n },\n\n /**\n * Returns selected text\n * @return {String}\n */\n getSelectedText: function() {\n return this._text.slice(this.selectionStart, this.selectionEnd).join('');\n },\n\n /**\n * Find new selection index representing start of current word according to current selection index\n * @param {Number} startFrom Current selection index\n * @return {Number} New selection index\n */\n findWordBoundaryLeft: function(startFrom) {\n var offset = 0, index = startFrom - 1;\n\n // remove space before cursor first\n if (this._reSpace.test(this._text[index])) {\n while (this._reSpace.test(this._text[index])) {\n offset++;\n index--;\n }\n }\n while (/\\S/.test(this._text[index]) && index > -1) {\n offset++;\n index--;\n }\n\n return startFrom - offset;\n },\n\n /**\n * Find new selection index representing end of current word according to current selection index\n * @param {Number} startFrom Current selection index\n * @return {Number} New selection index\n */\n findWordBoundaryRight: function(startFrom) {\n var offset = 0, index = startFrom;\n\n // remove space after cursor first\n if (this._reSpace.test(this._text[index])) {\n while (this._reSpace.test(this._text[index])) {\n offset++;\n index++;\n }\n }\n while (/\\S/.test(this._text[index]) && index < this._text.length) {\n offset++;\n index++;\n }\n\n return startFrom + offset;\n },\n\n /**\n * Find new selection index representing start of current line according to current selection index\n * @param {Number} startFrom Current selection index\n * @return {Number} New selection index\n */\n findLineBoundaryLeft: function(startFrom) {\n var offset = 0, index = startFrom - 1;\n\n while (!/\\n/.test(this._text[index]) && index > -1) {\n offset++;\n index--;\n }\n\n return startFrom - offset;\n },\n\n /**\n * Find new selection index representing end of current line according to current selection index\n * @param {Number} startFrom Current selection index\n * @return {Number} New selection index\n */\n findLineBoundaryRight: function(startFrom) {\n var offset = 0, index = startFrom;\n\n while (!/\\n/.test(this._text[index]) && index < this._text.length) {\n offset++;\n index++;\n }\n\n return startFrom + offset;\n },\n\n /**\n * Finds index corresponding to beginning or end of a word\n * @param {Number} selectionStart Index of a character\n * @param {Number} direction 1 or -1\n * @return {Number} Index of the beginning or end of a word\n */\n searchWordBoundary: function(selectionStart, direction) {\n var text = this._text,\n index = this._reSpace.test(text[selectionStart]) ? selectionStart - 1 : selectionStart,\n _char = text[index],\n // wrong\n reNonWord = fabric.reNonWord;\n\n while (!reNonWord.test(_char) && index > 0 && index < text.length) {\n index += direction;\n _char = text[index];\n }\n if (reNonWord.test(_char)) {\n index += direction === 1 ? 0 : 1;\n }\n return index;\n },\n\n /**\n * Selects a word based on the index\n * @param {Number} selectionStart Index of a character\n */\n selectWord: function(selectionStart) {\n selectionStart = selectionStart || this.selectionStart;\n var newSelectionStart = this.searchWordBoundary(selectionStart, -1), /* search backwards */\n newSelectionEnd = this.searchWordBoundary(selectionStart, 1); /* search forward */\n\n this.selectionStart = newSelectionStart;\n this.selectionEnd = newSelectionEnd;\n this._fireSelectionChanged();\n this._updateTextarea();\n this.renderCursorOrSelection();\n },\n\n /**\n * Selects a line based on the index\n * @param {Number} selectionStart Index of a character\n * @return {fabric.IText} thisArg\n * @chainable\n */\n selectLine: function(selectionStart) {\n selectionStart = selectionStart || this.selectionStart;\n var newSelectionStart = this.findLineBoundaryLeft(selectionStart),\n newSelectionEnd = this.findLineBoundaryRight(selectionStart);\n\n this.selectionStart = newSelectionStart;\n this.selectionEnd = newSelectionEnd;\n this._fireSelectionChanged();\n this._updateTextarea();\n return this;\n },\n\n /**\n * Enters editing state\n * @return {fabric.IText} thisArg\n * @chainable\n */\n enterEditing: function(e) {\n if (this.isEditing || !this.editable) {\n return;\n }\n\n if (this.canvas) {\n this.canvas.calcOffset();\n this.exitEditingOnOthers(this.canvas);\n }\n\n this.isEditing = true;\n\n this.initHiddenTextarea(e);\n this.hiddenTextarea.focus();\n this.hiddenTextarea.value = this.text;\n this._updateTextarea();\n this._saveEditingProps();\n this._setEditingProps();\n this._textBeforeEdit = this.text;\n\n this._tick();\n this.fire('editing:entered');\n this._fireSelectionChanged();\n if (!this.canvas) {\n return this;\n }\n this.canvas.fire('text:editing:entered', { target: this });\n this.initMouseMoveHandler();\n this.canvas.requestRenderAll();\n return this;\n },\n\n exitEditingOnOthers: function(canvas) {\n if (canvas._iTextInstances) {\n canvas._iTextInstances.forEach(function(obj) {\n obj.selected = false;\n if (obj.isEditing) {\n obj.exitEditing();\n }\n });\n }\n },\n\n /**\n * Initializes \"mousemove\" event handler\n */\n initMouseMoveHandler: function() {\n this.canvas.on('mouse:move', this.mouseMoveHandler);\n },\n\n /**\n * @private\n */\n mouseMoveHandler: function(options) {\n if (!this.__isMousedown || !this.isEditing) {\n return;\n }\n\n var newSelectionStart = this.getSelectionStartFromPointer(options.e),\n currentStart = this.selectionStart,\n currentEnd = this.selectionEnd;\n if (\n (newSelectionStart !== this.__selectionStartOnMouseDown || currentStart === currentEnd)\n &&\n (currentStart === newSelectionStart || currentEnd === newSelectionStart)\n ) {\n return;\n }\n if (newSelectionStart > this.__selectionStartOnMouseDown) {\n this.selectionStart = this.__selectionStartOnMouseDown;\n this.selectionEnd = newSelectionStart;\n }\n else {\n this.selectionStart = newSelectionStart;\n this.selectionEnd = this.__selectionStartOnMouseDown;\n }\n if (this.selectionStart !== currentStart || this.selectionEnd !== currentEnd) {\n this.restartCursorIfNeeded();\n this._fireSelectionChanged();\n this._updateTextarea();\n this.renderCursorOrSelection();\n }\n },\n\n /**\n * @private\n */\n _setEditingProps: function() {\n this.hoverCursor = 'text';\n\n if (this.canvas) {\n this.canvas.defaultCursor = this.canvas.moveCursor = 'text';\n }\n\n this.borderColor = this.editingBorderColor;\n this.hasControls = this.selectable = false;\n this.lockMovementX = this.lockMovementY = true;\n },\n\n /**\n * convert from textarea to grapheme indexes\n */\n fromStringToGraphemeSelection: function(start, end, text) {\n var smallerTextStart = text.slice(0, start),\n graphemeStart = fabric.util.string.graphemeSplit(smallerTextStart).length;\n if (start === end) {\n return { selectionStart: graphemeStart, selectionEnd: graphemeStart };\n }\n var smallerTextEnd = text.slice(start, end),\n graphemeEnd = fabric.util.string.graphemeSplit(smallerTextEnd).length;\n return { selectionStart: graphemeStart, selectionEnd: graphemeStart + graphemeEnd };\n },\n\n /**\n * convert from fabric to textarea values\n */\n fromGraphemeToStringSelection: function(start, end, _text) {\n var smallerTextStart = _text.slice(0, start),\n graphemeStart = smallerTextStart.join('').length;\n if (start === end) {\n return { selectionStart: graphemeStart, selectionEnd: graphemeStart };\n }\n var smallerTextEnd = _text.slice(start, end),\n graphemeEnd = smallerTextEnd.join('').length;\n return { selectionStart: graphemeStart, selectionEnd: graphemeStart + graphemeEnd };\n },\n\n /**\n * @private\n */\n _updateTextarea: function() {\n this.cursorOffsetCache = { };\n if (!this.hiddenTextarea) {\n return;\n }\n if (!this.inCompositionMode) {\n var newSelection = this.fromGraphemeToStringSelection(this.selectionStart, this.selectionEnd, this._text);\n this.hiddenTextarea.selectionStart = newSelection.selectionStart;\n this.hiddenTextarea.selectionEnd = newSelection.selectionEnd;\n }\n this.updateTextareaPosition();\n },\n\n /**\n * @private\n */\n updateFromTextArea: function() {\n if (!this.hiddenTextarea) {\n return;\n }\n this.cursorOffsetCache = { };\n this.text = this.hiddenTextarea.value;\n if (this._shouldClearDimensionCache()) {\n this.initDimensions();\n this.setCoords();\n }\n var newSelection = this.fromStringToGraphemeSelection(\n this.hiddenTextarea.selectionStart, this.hiddenTextarea.selectionEnd, this.hiddenTextarea.value);\n this.selectionEnd = this.selectionStart = newSelection.selectionEnd;\n if (!this.inCompositionMode) {\n this.selectionStart = newSelection.selectionStart;\n }\n this.updateTextareaPosition();\n },\n\n /**\n * @private\n */\n updateTextareaPosition: function() {\n if (this.selectionStart === this.selectionEnd) {\n var style = this._calcTextareaPosition();\n this.hiddenTextarea.style.left = style.left;\n this.hiddenTextarea.style.top = style.top;\n }\n },\n\n /**\n * @private\n * @return {Object} style contains style for hiddenTextarea\n */\n _calcTextareaPosition: function() {\n if (!this.canvas) {\n return { x: 1, y: 1 };\n }\n var desiredPosition = this.inCompositionMode ? this.compositionStart : this.selectionStart,\n boundaries = this._getCursorBoundaries(desiredPosition),\n cursorLocation = this.get2DCursorLocation(desiredPosition),\n lineIndex = cursorLocation.lineIndex,\n charIndex = cursorLocation.charIndex,\n charHeight = this.getValueOfPropertyAt(lineIndex, charIndex, 'fontSize') * this.lineHeight,\n leftOffset = boundaries.leftOffset,\n m = this.calcTransformMatrix(),\n p = {\n x: boundaries.left + leftOffset,\n y: boundaries.top + boundaries.topOffset + charHeight\n },\n retinaScaling = this.canvas.getRetinaScaling(),\n upperCanvas = this.canvas.upperCanvasEl,\n upperCanvasWidth = upperCanvas.width / retinaScaling,\n upperCanvasHeight = upperCanvas.height / retinaScaling,\n maxWidth = upperCanvasWidth - charHeight,\n maxHeight = upperCanvasHeight - charHeight,\n scaleX = upperCanvas.clientWidth / upperCanvasWidth,\n scaleY = upperCanvas.clientHeight / upperCanvasHeight;\n\n p = fabric.util.transformPoint(p, m);\n p = fabric.util.transformPoint(p, this.canvas.viewportTransform);\n p.x *= scaleX;\n p.y *= scaleY;\n if (p.x < 0) {\n p.x = 0;\n }\n if (p.x > maxWidth) {\n p.x = maxWidth;\n }\n if (p.y < 0) {\n p.y = 0;\n }\n if (p.y > maxHeight) {\n p.y = maxHeight;\n }\n\n // add canvas offset on document\n p.x += this.canvas._offset.left;\n p.y += this.canvas._offset.top;\n\n return { left: p.x + 'px', top: p.y + 'px', fontSize: charHeight + 'px', charHeight: charHeight };\n },\n\n /**\n * @private\n */\n _saveEditingProps: function() {\n this._savedProps = {\n hasControls: this.hasControls,\n borderColor: this.borderColor,\n lockMovementX: this.lockMovementX,\n lockMovementY: this.lockMovementY,\n hoverCursor: this.hoverCursor,\n selectable: this.selectable,\n defaultCursor: this.canvas && this.canvas.defaultCursor,\n moveCursor: this.canvas && this.canvas.moveCursor\n };\n },\n\n /**\n * @private\n */\n _restoreEditingProps: function() {\n if (!this._savedProps) {\n return;\n }\n\n this.hoverCursor = this._savedProps.hoverCursor;\n this.hasControls = this._savedProps.hasControls;\n this.borderColor = this._savedProps.borderColor;\n this.selectable = this._savedProps.selectable;\n this.lockMovementX = this._savedProps.lockMovementX;\n this.lockMovementY = this._savedProps.lockMovementY;\n\n if (this.canvas) {\n this.canvas.defaultCursor = this._savedProps.defaultCursor;\n this.canvas.moveCursor = this._savedProps.moveCursor;\n }\n },\n\n /**\n * Exits from editing state\n * @return {fabric.IText} thisArg\n * @chainable\n */\n exitEditing: function() {\n var isTextChanged = (this._textBeforeEdit !== this.text);\n var hiddenTextarea = this.hiddenTextarea;\n this.selected = false;\n this.isEditing = false;\n\n this.selectionEnd = this.selectionStart;\n\n if (hiddenTextarea) {\n hiddenTextarea.blur && hiddenTextarea.blur();\n hiddenTextarea.parentNode && hiddenTextarea.parentNode.removeChild(hiddenTextarea);\n }\n this.hiddenTextarea = null;\n this.abortCursorAnimation();\n this._restoreEditingProps();\n this._currentCursorOpacity = 0;\n if (this._shouldClearDimensionCache()) {\n this.initDimensions();\n this.setCoords();\n }\n this.fire('editing:exited');\n isTextChanged && this.fire('modified');\n if (this.canvas) {\n this.canvas.off('mouse:move', this.mouseMoveHandler);\n this.canvas.fire('text:editing:exited', { target: this });\n isTextChanged && this.canvas.fire('object:modified', { target: this });\n }\n return this;\n },\n\n /**\n * @private\n */\n _removeExtraneousStyles: function() {\n for (var prop in this.styles) {\n if (!this._textLines[prop]) {\n delete this.styles[prop];\n }\n }\n },\n\n /**\n * remove and reflow a style block from start to end.\n * @param {Number} start linear start position for removal (included in removal)\n * @param {Number} end linear end position for removal ( excluded from removal )\n */\n removeStyleFromTo: function(start, end) {\n var cursorStart = this.get2DCursorLocation(start, true),\n cursorEnd = this.get2DCursorLocation(end, true),\n lineStart = cursorStart.lineIndex,\n charStart = cursorStart.charIndex,\n lineEnd = cursorEnd.lineIndex,\n charEnd = cursorEnd.charIndex,\n i, styleObj;\n if (lineStart !== lineEnd) {\n // step1 remove the trailing of lineStart\n if (this.styles[lineStart]) {\n for (i = charStart; i < this._unwrappedTextLines[lineStart].length; i++) {\n delete this.styles[lineStart][i];\n }\n }\n // step2 move the trailing of lineEnd to lineStart if needed\n if (this.styles[lineEnd]) {\n for (i = charEnd; i < this._unwrappedTextLines[lineEnd].length; i++) {\n styleObj = this.styles[lineEnd][i];\n if (styleObj) {\n this.styles[lineStart] || (this.styles[lineStart] = { });\n this.styles[lineStart][charStart + i - charEnd] = styleObj;\n }\n }\n }\n // step3 detects lines will be completely removed.\n for (i = lineStart + 1; i <= lineEnd; i++) {\n delete this.styles[i];\n }\n // step4 shift remaining lines.\n this.shiftLineStyles(lineEnd, lineStart - lineEnd);\n }\n else {\n // remove and shift left on the same line\n if (this.styles[lineStart]) {\n styleObj = this.styles[lineStart];\n var diff = charEnd - charStart, numericChar, _char;\n for (i = charStart; i < charEnd; i++) {\n delete styleObj[i];\n }\n for (_char in this.styles[lineStart]) {\n numericChar = parseInt(_char, 10);\n if (numericChar >= charEnd) {\n styleObj[numericChar - diff] = styleObj[_char];\n delete styleObj[_char];\n }\n }\n }\n }\n },\n\n /**\n * Shifts line styles up or down\n * @param {Number} lineIndex Index of a line\n * @param {Number} offset Can any number?\n */\n shiftLineStyles: function(lineIndex, offset) {\n // shift all line styles by offset upward or downward\n // do not clone deep. we need new array, not new style objects\n var clonedStyles = clone(this.styles);\n for (var line in this.styles) {\n var numericLine = parseInt(line, 10);\n if (numericLine > lineIndex) {\n this.styles[numericLine + offset] = clonedStyles[numericLine];\n if (!clonedStyles[numericLine - offset]) {\n delete this.styles[numericLine];\n }\n }\n }\n },\n\n restartCursorIfNeeded: function() {\n if (!this._currentTickState || this._currentTickState.isAborted\n || !this._currentTickCompleteState || this._currentTickCompleteState.isAborted\n ) {\n this.initDelayedCursor();\n }\n },\n\n /**\n * Handle insertion of more consecutive style lines for when one or more\n * newlines gets added to the text. Since current style needs to be shifted\n * first we shift the current style of the number lines needed, then we add\n * new lines from the last to the first.\n * @param {Number} lineIndex Index of a line\n * @param {Number} charIndex Index of a char\n * @param {Number} qty number of lines to add\n * @param {Array} copiedStyle Array of objects styles\n */\n insertNewlineStyleObject: function(lineIndex, charIndex, qty, copiedStyle) {\n var currentCharStyle,\n newLineStyles = {},\n somethingAdded = false,\n isEndOfLine = this._unwrappedTextLines[lineIndex].length === charIndex;\n\n qty || (qty = 1);\n this.shiftLineStyles(lineIndex, qty);\n if (this.styles[lineIndex]) {\n currentCharStyle = this.styles[lineIndex][charIndex === 0 ? charIndex : charIndex - 1];\n }\n // we clone styles of all chars\n // after cursor onto the current line\n for (var index in this.styles[lineIndex]) {\n var numIndex = parseInt(index, 10);\n if (numIndex >= charIndex) {\n somethingAdded = true;\n newLineStyles[numIndex - charIndex] = this.styles[lineIndex][index];\n // remove lines from the previous line since they're on a new line now\n if (!(isEndOfLine && charIndex === 0)) {\n delete this.styles[lineIndex][index];\n }\n }\n }\n var styleCarriedOver = false;\n if (somethingAdded && !isEndOfLine) {\n // if is end of line, the extra style we copied\n // is probably not something we want\n this.styles[lineIndex + qty] = newLineStyles;\n styleCarriedOver = true;\n }\n if (styleCarriedOver) {\n // skip the last line of since we already prepared it.\n qty--;\n }\n // for the all the lines or all the other lines\n // we clone current char style onto the next (otherwise empty) line\n while (qty > 0) {\n if (copiedStyle && copiedStyle[qty - 1]) {\n this.styles[lineIndex + qty] = { 0: clone(copiedStyle[qty - 1]) };\n }\n else if (currentCharStyle) {\n this.styles[lineIndex + qty] = { 0: clone(currentCharStyle) };\n }\n else {\n delete this.styles[lineIndex + qty];\n }\n qty--;\n }\n this._forceClearCache = true;\n },\n\n /**\n * Inserts style object for a given line/char index\n * @param {Number} lineIndex Index of a line\n * @param {Number} charIndex Index of a char\n * @param {Number} quantity number Style object to insert, if given\n * @param {Array} copiedStyle array of style objects\n */\n insertCharStyleObject: function(lineIndex, charIndex, quantity, copiedStyle) {\n if (!this.styles) {\n this.styles = {};\n }\n var currentLineStyles = this.styles[lineIndex],\n currentLineStylesCloned = currentLineStyles ? clone(currentLineStyles) : {};\n\n quantity || (quantity = 1);\n // shift all char styles by quantity forward\n // 0,1,2,3 -> (charIndex=2) -> 0,1,3,4 -> (insert 2) -> 0,1,2,3,4\n for (var index in currentLineStylesCloned) {\n var numericIndex = parseInt(index, 10);\n if (numericIndex >= charIndex) {\n currentLineStyles[numericIndex + quantity] = currentLineStylesCloned[numericIndex];\n // only delete the style if there was nothing moved there\n if (!currentLineStylesCloned[numericIndex - quantity]) {\n delete currentLineStyles[numericIndex];\n }\n }\n }\n this._forceClearCache = true;\n if (copiedStyle) {\n while (quantity--) {\n if (!Object.keys(copiedStyle[quantity]).length) {\n continue;\n }\n if (!this.styles[lineIndex]) {\n this.styles[lineIndex] = {};\n }\n this.styles[lineIndex][charIndex + quantity] = clone(copiedStyle[quantity]);\n }\n return;\n }\n if (!currentLineStyles) {\n return;\n }\n var newStyle = currentLineStyles[charIndex ? charIndex - 1 : 1];\n while (newStyle && quantity--) {\n this.styles[lineIndex][charIndex + quantity] = clone(newStyle);\n }\n },\n\n /**\n * Inserts style object(s)\n * @param {Array} insertedText Characters at the location where style is inserted\n * @param {Number} start cursor index for inserting style\n * @param {Array} [copiedStyle] array of style objects to insert.\n */\n insertNewStyleBlock: function(insertedText, start, copiedStyle) {\n var cursorLoc = this.get2DCursorLocation(start, true),\n addedLines = [0], linesLength = 0;\n // get an array of how many char per lines are being added.\n for (var i = 0; i < insertedText.length; i++) {\n if (insertedText[i] === '\\n') {\n linesLength++;\n addedLines[linesLength] = 0;\n }\n else {\n addedLines[linesLength]++;\n }\n }\n // for the first line copy the style from the current char position.\n if (addedLines[0] > 0) {\n this.insertCharStyleObject(cursorLoc.lineIndex, cursorLoc.charIndex, addedLines[0], copiedStyle);\n copiedStyle = copiedStyle && copiedStyle.slice(addedLines[0] + 1);\n }\n linesLength && this.insertNewlineStyleObject(\n cursorLoc.lineIndex, cursorLoc.charIndex + addedLines[0], linesLength);\n for (var i = 1; i < linesLength; i++) {\n if (addedLines[i] > 0) {\n this.insertCharStyleObject(cursorLoc.lineIndex + i, 0, addedLines[i], copiedStyle);\n }\n else if (copiedStyle) {\n // this test is required in order to close #6841\n // when a pasted buffer begins with a newline then\n // this.styles[cursorLoc.lineIndex + i] and copiedStyle[0]\n // may be undefined for some reason\n if (this.styles[cursorLoc.lineIndex + i] && copiedStyle[0]) {\n this.styles[cursorLoc.lineIndex + i][0] = copiedStyle[0];\n }\n }\n copiedStyle = copiedStyle && copiedStyle.slice(addedLines[i] + 1);\n }\n // we use i outside the loop to get it like linesLength\n if (addedLines[i] > 0) {\n this.insertCharStyleObject(cursorLoc.lineIndex + i, 0, addedLines[i], copiedStyle);\n }\n },\n\n /**\n * Set the selectionStart and selectionEnd according to the new position of cursor\n * mimic the key - mouse navigation when shift is pressed.\n */\n setSelectionStartEndWithShift: function(start, end, newSelection) {\n if (newSelection <= start) {\n if (end === start) {\n this._selectionDirection = 'left';\n }\n else if (this._selectionDirection === 'right') {\n this._selectionDirection = 'left';\n this.selectionEnd = start;\n }\n this.selectionStart = newSelection;\n }\n else if (newSelection > start && newSelection < end) {\n if (this._selectionDirection === 'right') {\n this.selectionEnd = newSelection;\n }\n else {\n this.selectionStart = newSelection;\n }\n }\n else {\n // newSelection is > selection start and end\n if (end === start) {\n this._selectionDirection = 'right';\n }\n else if (this._selectionDirection === 'left') {\n this._selectionDirection = 'right';\n this.selectionStart = end;\n }\n this.selectionEnd = newSelection;\n }\n },\n\n setSelectionInBoundaries: function() {\n var length = this.text.length;\n if (this.selectionStart > length) {\n this.selectionStart = length;\n }\n else if (this.selectionStart < 0) {\n this.selectionStart = 0;\n }\n if (this.selectionEnd > length) {\n this.selectionEnd = length;\n }\n else if (this.selectionEnd < 0) {\n this.selectionEnd = 0;\n }\n }\n });\n})();\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n /**\n * Initializes \"dbclick\" event handler\n */\n initDoubleClickSimulation: function() {\n\n // for double click\n this.__lastClickTime = +new Date();\n\n // for triple click\n this.__lastLastClickTime = +new Date();\n\n this.__lastPointer = { };\n\n this.on('mousedown', this.onMouseDown);\n },\n\n /**\n * Default event handler to simulate triple click\n * @private\n */\n onMouseDown: function(options) {\n if (!this.canvas) {\n return;\n }\n this.__newClickTime = +new Date();\n var newPointer = options.pointer;\n if (this.isTripleClick(newPointer)) {\n this.fire('tripleclick', options);\n this._stopEvent(options.e);\n }\n this.__lastLastClickTime = this.__lastClickTime;\n this.__lastClickTime = this.__newClickTime;\n this.__lastPointer = newPointer;\n this.__lastIsEditing = this.isEditing;\n this.__lastSelected = this.selected;\n },\n\n isTripleClick: function(newPointer) {\n return this.__newClickTime - this.__lastClickTime < 500 &&\n this.__lastClickTime - this.__lastLastClickTime < 500 &&\n this.__lastPointer.x === newPointer.x &&\n this.__lastPointer.y === newPointer.y;\n },\n\n /**\n * @private\n */\n _stopEvent: function(e) {\n e.preventDefault && e.preventDefault();\n e.stopPropagation && e.stopPropagation();\n },\n\n /**\n * Initializes event handlers related to cursor or selection\n */\n initCursorSelectionHandlers: function() {\n this.initMousedownHandler();\n this.initMouseupHandler();\n this.initClicks();\n },\n\n /**\n * Default handler for double click, select a word\n */\n doubleClickHandler: function(options) {\n if (!this.isEditing) {\n return;\n }\n this.selectWord(this.getSelectionStartFromPointer(options.e));\n },\n\n /**\n * Default handler for triple click, select a line\n */\n tripleClickHandler: function(options) {\n if (!this.isEditing) {\n return;\n }\n this.selectLine(this.getSelectionStartFromPointer(options.e));\n },\n\n /**\n * Initializes double and triple click event handlers\n */\n initClicks: function() {\n this.on('mousedblclick', this.doubleClickHandler);\n this.on('tripleclick', this.tripleClickHandler);\n },\n\n /**\n * Default event handler for the basic functionalities needed on _mouseDown\n * can be overridden to do something different.\n * Scope of this implementation is: find the click position, set selectionStart\n * find selectionEnd, initialize the drawing of either cursor or selection area\n * initializing a mousedDown on a text area will cancel fabricjs knowledge of\n * current compositionMode. It will be set to false.\n */\n _mouseDownHandler: function(options) {\n if (!this.canvas || !this.editable || (options.e.button && options.e.button !== 1)) {\n return;\n }\n\n this.__isMousedown = true;\n\n if (this.selected) {\n this.inCompositionMode = false;\n this.setCursorByClick(options.e);\n }\n\n if (this.isEditing) {\n this.__selectionStartOnMouseDown = this.selectionStart;\n if (this.selectionStart === this.selectionEnd) {\n this.abortCursorAnimation();\n }\n this.renderCursorOrSelection();\n }\n },\n\n /**\n * Default event handler for the basic functionalities needed on mousedown:before\n * can be overridden to do something different.\n * Scope of this implementation is: verify the object is already selected when mousing down\n */\n _mouseDownHandlerBefore: function(options) {\n if (!this.canvas || !this.editable || (options.e.button && options.e.button !== 1)) {\n return;\n }\n // we want to avoid that an object that was selected and then becomes unselectable,\n // may trigger editing mode in some way.\n this.selected = this === this.canvas._activeObject;\n },\n\n /**\n * Initializes \"mousedown\" event handler\n */\n initMousedownHandler: function() {\n this.on('mousedown', this._mouseDownHandler);\n this.on('mousedown:before', this._mouseDownHandlerBefore);\n },\n\n /**\n * Initializes \"mouseup\" event handler\n */\n initMouseupHandler: function() {\n this.on('mouseup', this.mouseUpHandler);\n },\n\n /**\n * standard handler for mouse up, overridable\n * @private\n */\n mouseUpHandler: function(options) {\n this.__isMousedown = false;\n if (!this.editable || this.group ||\n (options.transform && options.transform.actionPerformed) ||\n (options.e.button && options.e.button !== 1)) {\n return;\n }\n\n if (this.canvas) {\n var currentActive = this.canvas._activeObject;\n if (currentActive && currentActive !== this) {\n // avoid running this logic when there is an active object\n // this because is possible with shift click and fast clicks,\n // to rapidly deselect and reselect this object and trigger an enterEdit\n return;\n }\n }\n\n if (this.__lastSelected && !this.__corner) {\n this.selected = false;\n this.__lastSelected = false;\n this.enterEditing(options.e);\n if (this.selectionStart === this.selectionEnd) {\n this.initDelayedCursor(true);\n }\n else {\n this.renderCursorOrSelection();\n }\n }\n else {\n this.selected = true;\n }\n },\n\n /**\n * Changes cursor location in a text depending on passed pointer (x/y) object\n * @param {Event} e Event object\n */\n setCursorByClick: function(e) {\n var newSelection = this.getSelectionStartFromPointer(e),\n start = this.selectionStart, end = this.selectionEnd;\n if (e.shiftKey) {\n this.setSelectionStartEndWithShift(start, end, newSelection);\n }\n else {\n this.selectionStart = newSelection;\n this.selectionEnd = newSelection;\n }\n if (this.isEditing) {\n this._fireSelectionChanged();\n this._updateTextarea();\n }\n },\n\n /**\n * Returns index of a character corresponding to where an object was clicked\n * @param {Event} e Event object\n * @return {Number} Index of a character\n */\n getSelectionStartFromPointer: function(e) {\n var mouseOffset = this.getLocalPointer(e),\n prevWidth = 0,\n width = 0,\n height = 0,\n charIndex = 0,\n lineIndex = 0,\n lineLeftOffset,\n line;\n for (var i = 0, len = this._textLines.length; i < len; i++) {\n if (height <= mouseOffset.y) {\n height += this.getHeightOfLine(i) * this.scaleY;\n lineIndex = i;\n if (i > 0) {\n charIndex += this._textLines[i - 1].length + this.missingNewlineOffset(i - 1);\n }\n }\n else {\n break;\n }\n }\n lineLeftOffset = this._getLineLeftOffset(lineIndex);\n width = lineLeftOffset * this.scaleX;\n line = this._textLines[lineIndex];\n // handling of RTL: in order to get things work correctly,\n // we assume RTL writing is mirrored compared to LTR writing.\n // so in position detection we mirror the X offset, and when is time\n // of rendering it, we mirror it again.\n if (this.direction === 'rtl') {\n mouseOffset.x = this.width * this.scaleX - mouseOffset.x + width;\n }\n for (var j = 0, jlen = line.length; j < jlen; j++) {\n prevWidth = width;\n // i removed something about flipX here, check.\n width += this.__charBounds[lineIndex][j].kernedWidth * this.scaleX;\n if (width <= mouseOffset.x) {\n charIndex++;\n }\n else {\n break;\n }\n }\n return this._getNewSelectionStartFromOffset(mouseOffset, prevWidth, width, charIndex, jlen);\n },\n\n /**\n * @private\n */\n _getNewSelectionStartFromOffset: function(mouseOffset, prevWidth, width, index, jlen) {\n // we need Math.abs because when width is after the last char, the offset is given as 1, while is 0\n var distanceBtwLastCharAndCursor = mouseOffset.x - prevWidth,\n distanceBtwNextCharAndCursor = width - mouseOffset.x,\n offset = distanceBtwNextCharAndCursor > distanceBtwLastCharAndCursor ||\n distanceBtwNextCharAndCursor < 0 ? 0 : 1,\n newSelectionStart = index + offset;\n // if object is horizontally flipped, mirror cursor location from the end\n if (this.flipX) {\n newSelectionStart = jlen - newSelectionStart;\n }\n\n if (newSelectionStart > this._text.length) {\n newSelectionStart = this._text.length;\n }\n\n return newSelectionStart;\n }\n});\n\n\nfabric.util.object.extend(fabric.IText.prototype, /** @lends fabric.IText.prototype */ {\n\n /**\n * Initializes hidden textarea (needed to bring up keyboard in iOS)\n */\n initHiddenTextarea: function() {\n this.hiddenTextarea = fabric.document.createElement('textarea');\n this.hiddenTextarea.setAttribute('autocapitalize', 'off');\n this.hiddenTextarea.setAttribute('autocorrect', 'off');\n this.hiddenTextarea.setAttribute('autocomplete', 'off');\n this.hiddenTextarea.setAttribute('spellcheck', 'false');\n this.hiddenTextarea.setAttribute('data-fabric-hiddentextarea', '');\n this.hiddenTextarea.setAttribute('wrap', 'off');\n var style = this._calcTextareaPosition();\n // line-height: 1px; was removed from the style to fix this:\n // https://bugs.chromium.org/p/chromium/issues/detail?id=870966\n this.hiddenTextarea.style.cssText = 'position: absolute; top: ' + style.top +\n '; left: ' + style.left + '; z-index: -999; opacity: 0; width: 1px; height: 1px; font-size: 1px;' +\n ' paddingï½°top: ' + style.fontSize + ';';\n\n if (this.hiddenTextareaContainer) {\n this.hiddenTextareaContainer.appendChild(this.hiddenTextarea);\n }\n else {\n fabric.document.body.appendChild(this.hiddenTextarea);\n }\n\n fabric.util.addListener(this.hiddenTextarea, 'keydown', this.onKeyDown.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'keyup', this.onKeyUp.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'input', this.onInput.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'copy', this.copy.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'cut', this.copy.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'paste', this.paste.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'compositionstart', this.onCompositionStart.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'compositionupdate', this.onCompositionUpdate.bind(this));\n fabric.util.addListener(this.hiddenTextarea, 'compositionend', this.onCompositionEnd.bind(this));\n\n if (!this._clickHandlerInitialized && this.canvas) {\n fabric.util.addListener(this.canvas.upperCanvasEl, 'click', this.onClick.bind(this));\n this._clickHandlerInitialized = true;\n }\n },\n\n /**\n * For functionalities on keyDown\n * Map a special key to a function of the instance/prototype\n * If you need different behaviour for ESC or TAB or arrows, you have to change\n * this map setting the name of a function that you build on the fabric.Itext or\n * your prototype.\n * the map change will affect all Instances unless you need for only some text Instances\n * in that case you have to clone this object and assign your Instance.\n * this.keysMap = fabric.util.object.clone(this.keysMap);\n * The function must be in fabric.Itext.prototype.myFunction And will receive event as args[0]\n */\n keysMap: {\n 9: 'exitEditing',\n 27: 'exitEditing',\n 33: 'moveCursorUp',\n 34: 'moveCursorDown',\n 35: 'moveCursorRight',\n 36: 'moveCursorLeft',\n 37: 'moveCursorLeft',\n 38: 'moveCursorUp',\n 39: 'moveCursorRight',\n 40: 'moveCursorDown',\n },\n\n keysMapRtl: {\n 9: 'exitEditing',\n 27: 'exitEditing',\n 33: 'moveCursorUp',\n 34: 'moveCursorDown',\n 35: 'moveCursorLeft',\n 36: 'moveCursorRight',\n 37: 'moveCursorRight',\n 38: 'moveCursorUp',\n 39: 'moveCursorLeft',\n 40: 'moveCursorDown',\n },\n\n /**\n * For functionalities on keyUp + ctrl || cmd\n */\n ctrlKeysMapUp: {\n 67: 'copy',\n 88: 'cut'\n },\n\n /**\n * For functionalities on keyDown + ctrl || cmd\n */\n ctrlKeysMapDown: {\n 65: 'selectAll'\n },\n\n onClick: function() {\n // No need to trigger click event here, focus is enough to have the keyboard appear on Android\n this.hiddenTextarea && this.hiddenTextarea.focus();\n },\n\n /**\n * Handles keydown event\n * only used for arrows and combination of modifier keys.\n * @param {Event} e Event object\n */\n onKeyDown: function(e) {\n if (!this.isEditing) {\n return;\n }\n var keyMap = this.direction === 'rtl' ? this.keysMapRtl : this.keysMap;\n if (e.keyCode in keyMap) {\n this[keyMap[e.keyCode]](e);\n }\n else if ((e.keyCode in this.ctrlKeysMapDown) && (e.ctrlKey || e.metaKey)) {\n this[this.ctrlKeysMapDown[e.keyCode]](e);\n }\n else {\n return;\n }\n e.stopImmediatePropagation();\n e.preventDefault();\n if (e.keyCode >= 33 && e.keyCode <= 40) {\n // if i press an arrow key just update selection\n this.inCompositionMode = false;\n this.clearContextTop();\n this.renderCursorOrSelection();\n }\n else {\n this.canvas && this.canvas.requestRenderAll();\n }\n },\n\n /**\n * Handles keyup event\n * We handle KeyUp because ie11 and edge have difficulties copy/pasting\n * if a copy/cut event fired, keyup is dismissed\n * @param {Event} e Event object\n */\n onKeyUp: function(e) {\n if (!this.isEditing || this._copyDone || this.inCompositionMode) {\n this._copyDone = false;\n return;\n }\n if ((e.keyCode in this.ctrlKeysMapUp) && (e.ctrlKey || e.metaKey)) {\n this[this.ctrlKeysMapUp[e.keyCode]](e);\n }\n else {\n return;\n }\n e.stopImmediatePropagation();\n e.preventDefault();\n this.canvas && this.canvas.requestRenderAll();\n },\n\n /**\n * Handles onInput event\n * @param {Event} e Event object\n */\n onInput: function(e) {\n var fromPaste = this.fromPaste;\n this.fromPaste = false;\n e && e.stopPropagation();\n if (!this.isEditing) {\n return;\n }\n // decisions about style changes.\n var nextText = this._splitTextIntoLines(this.hiddenTextarea.value).graphemeText,\n charCount = this._text.length,\n nextCharCount = nextText.length,\n removedText, insertedText,\n charDiff = nextCharCount - charCount,\n selectionStart = this.selectionStart, selectionEnd = this.selectionEnd,\n selection = selectionStart !== selectionEnd,\n copiedStyle, removeFrom, removeTo;\n if (this.hiddenTextarea.value === '') {\n this.styles = { };\n this.updateFromTextArea();\n this.fire('changed');\n if (this.canvas) {\n this.canvas.fire('text:changed', { target: this });\n this.canvas.requestRenderAll();\n }\n return;\n }\n\n var textareaSelection = this.fromStringToGraphemeSelection(\n this.hiddenTextarea.selectionStart,\n this.hiddenTextarea.selectionEnd,\n this.hiddenTextarea.value\n );\n var backDelete = selectionStart > textareaSelection.selectionStart;\n\n if (selection) {\n removedText = this._text.slice(selectionStart, selectionEnd);\n charDiff += selectionEnd - selectionStart;\n }\n else if (nextCharCount < charCount) {\n if (backDelete) {\n removedText = this._text.slice(selectionEnd + charDiff, selectionEnd);\n }\n else {\n removedText = this._text.slice(selectionStart, selectionStart - charDiff);\n }\n }\n insertedText = nextText.slice(textareaSelection.selectionEnd - charDiff, textareaSelection.selectionEnd);\n if (removedText && removedText.length) {\n if (insertedText.length) {\n // let's copy some style before deleting.\n // we want to copy the style before the cursor OR the style at the cursor if selection\n // is bigger than 0.\n copiedStyle = this.getSelectionStyles(selectionStart, selectionStart + 1, false);\n // now duplicate the style one for each inserted text.\n copiedStyle = insertedText.map(function() {\n // this return an array of references, but that is fine since we are\n // copying the style later.\n return copiedStyle[0];\n });\n }\n if (selection) {\n removeFrom = selectionStart;\n removeTo = selectionEnd;\n }\n else if (backDelete) {\n // detect differences between forwardDelete and backDelete\n removeFrom = selectionEnd - removedText.length;\n removeTo = selectionEnd;\n }\n else {\n removeFrom = selectionEnd;\n removeTo = selectionEnd + removedText.length;\n }\n this.removeStyleFromTo(removeFrom, removeTo);\n }\n if (insertedText.length) {\n if (fromPaste && insertedText.join('') === fabric.copiedText && !fabric.disableStyleCopyPaste) {\n copiedStyle = fabric.copiedTextStyle;\n }\n this.insertNewStyleBlock(insertedText, selectionStart, copiedStyle);\n }\n this.updateFromTextArea();\n this.fire('changed');\n if (this.canvas) {\n this.canvas.fire('text:changed', { target: this });\n this.canvas.requestRenderAll();\n }\n },\n /**\n * Composition start\n */\n onCompositionStart: function() {\n this.inCompositionMode = true;\n },\n\n /**\n * Composition end\n */\n onCompositionEnd: function() {\n this.inCompositionMode = false;\n },\n\n // /**\n // * Composition update\n // */\n onCompositionUpdate: function(e) {\n this.compositionStart = e.target.selectionStart;\n this.compositionEnd = e.target.selectionEnd;\n this.updateTextareaPosition();\n },\n\n /**\n * Copies selected text\n * @param {Event} e Event object\n */\n copy: function() {\n if (this.selectionStart === this.selectionEnd) {\n //do not cut-copy if no selection\n return;\n }\n\n fabric.copiedText = this.getSelectedText();\n if (!fabric.disableStyleCopyPaste) {\n fabric.copiedTextStyle = this.getSelectionStyles(this.selectionStart, this.selectionEnd, true);\n }\n else {\n fabric.copiedTextStyle = null;\n }\n this._copyDone = true;\n },\n\n /**\n * Pastes text\n * @param {Event} e Event object\n */\n paste: function() {\n this.fromPaste = true;\n },\n\n /**\n * @private\n * @param {Event} e Event object\n * @return {Object} Clipboard data object\n */\n _getClipboardData: function(e) {\n return (e && e.clipboardData) || fabric.window.clipboardData;\n },\n\n /**\n * Finds the width in pixels before the cursor on the same line\n * @private\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @return {Number} widthBeforeCursor width before cursor\n */\n _getWidthBeforeCursor: function(lineIndex, charIndex) {\n var widthBeforeCursor = this._getLineLeftOffset(lineIndex), bound;\n\n if (charIndex > 0) {\n bound = this.__charBounds[lineIndex][charIndex - 1];\n widthBeforeCursor += bound.left + bound.width;\n }\n return widthBeforeCursor;\n },\n\n /**\n * Gets start offset of a selection\n * @param {Event} e Event object\n * @param {Boolean} isRight\n * @return {Number}\n */\n getDownCursorOffset: function(e, isRight) {\n var selectionProp = this._getSelectionForOffset(e, isRight),\n cursorLocation = this.get2DCursorLocation(selectionProp),\n lineIndex = cursorLocation.lineIndex;\n // if on last line, down cursor goes to end of line\n if (lineIndex === this._textLines.length - 1 || e.metaKey || e.keyCode === 34) {\n // move to the end of a text\n return this._text.length - selectionProp;\n }\n var charIndex = cursorLocation.charIndex,\n widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),\n indexOnOtherLine = this._getIndexOnLine(lineIndex + 1, widthBeforeCursor),\n textAfterCursor = this._textLines[lineIndex].slice(charIndex);\n return textAfterCursor.length + indexOnOtherLine + 1 + this.missingNewlineOffset(lineIndex);\n },\n\n /**\n * private\n * Helps finding if the offset should be counted from Start or End\n * @param {Event} e Event object\n * @param {Boolean} isRight\n * @return {Number}\n */\n _getSelectionForOffset: function(e, isRight) {\n if (e.shiftKey && this.selectionStart !== this.selectionEnd && isRight) {\n return this.selectionEnd;\n }\n else {\n return this.selectionStart;\n }\n },\n\n /**\n * @param {Event} e Event object\n * @param {Boolean} isRight\n * @return {Number}\n */\n getUpCursorOffset: function(e, isRight) {\n var selectionProp = this._getSelectionForOffset(e, isRight),\n cursorLocation = this.get2DCursorLocation(selectionProp),\n lineIndex = cursorLocation.lineIndex;\n if (lineIndex === 0 || e.metaKey || e.keyCode === 33) {\n // if on first line, up cursor goes to start of line\n return -selectionProp;\n }\n var charIndex = cursorLocation.charIndex,\n widthBeforeCursor = this._getWidthBeforeCursor(lineIndex, charIndex),\n indexOnOtherLine = this._getIndexOnLine(lineIndex - 1, widthBeforeCursor),\n textBeforeCursor = this._textLines[lineIndex].slice(0, charIndex),\n missingNewlineOffset = this.missingNewlineOffset(lineIndex - 1);\n // return a negative offset\n return -this._textLines[lineIndex - 1].length\n + indexOnOtherLine - textBeforeCursor.length + (1 - missingNewlineOffset);\n },\n\n /**\n * for a given width it founds the matching character.\n * @private\n */\n _getIndexOnLine: function(lineIndex, width) {\n\n var line = this._textLines[lineIndex],\n lineLeftOffset = this._getLineLeftOffset(lineIndex),\n widthOfCharsOnLine = lineLeftOffset,\n indexOnLine = 0, charWidth, foundMatch;\n\n for (var j = 0, jlen = line.length; j < jlen; j++) {\n charWidth = this.__charBounds[lineIndex][j].width;\n widthOfCharsOnLine += charWidth;\n if (widthOfCharsOnLine > width) {\n foundMatch = true;\n var leftEdge = widthOfCharsOnLine - charWidth,\n rightEdge = widthOfCharsOnLine,\n offsetFromLeftEdge = Math.abs(leftEdge - width),\n offsetFromRightEdge = Math.abs(rightEdge - width);\n\n indexOnLine = offsetFromRightEdge < offsetFromLeftEdge ? j : (j - 1);\n break;\n }\n }\n\n // reached end\n if (!foundMatch) {\n indexOnLine = line.length - 1;\n }\n\n return indexOnLine;\n },\n\n\n /**\n * Moves cursor down\n * @param {Event} e Event object\n */\n moveCursorDown: function(e) {\n if (this.selectionStart >= this._text.length && this.selectionEnd >= this._text.length) {\n return;\n }\n this._moveCursorUpOrDown('Down', e);\n },\n\n /**\n * Moves cursor up\n * @param {Event} e Event object\n */\n moveCursorUp: function(e) {\n if (this.selectionStart === 0 && this.selectionEnd === 0) {\n return;\n }\n this._moveCursorUpOrDown('Up', e);\n },\n\n /**\n * Moves cursor up or down, fires the events\n * @param {String} direction 'Up' or 'Down'\n * @param {Event} e Event object\n */\n _moveCursorUpOrDown: function(direction, e) {\n // getUpCursorOffset\n // getDownCursorOffset\n var action = 'get' + direction + 'CursorOffset',\n offset = this[action](e, this._selectionDirection === 'right');\n if (e.shiftKey) {\n this.moveCursorWithShift(offset);\n }\n else {\n this.moveCursorWithoutShift(offset);\n }\n if (offset !== 0) {\n this.setSelectionInBoundaries();\n this.abortCursorAnimation();\n this._currentCursorOpacity = 1;\n this.initDelayedCursor();\n this._fireSelectionChanged();\n this._updateTextarea();\n }\n },\n\n /**\n * Moves cursor with shift\n * @param {Number} offset\n */\n moveCursorWithShift: function(offset) {\n var newSelection = this._selectionDirection === 'left'\n ? this.selectionStart + offset\n : this.selectionEnd + offset;\n this.setSelectionStartEndWithShift(this.selectionStart, this.selectionEnd, newSelection);\n return offset !== 0;\n },\n\n /**\n * Moves cursor up without shift\n * @param {Number} offset\n */\n moveCursorWithoutShift: function(offset) {\n if (offset < 0) {\n this.selectionStart += offset;\n this.selectionEnd = this.selectionStart;\n }\n else {\n this.selectionEnd += offset;\n this.selectionStart = this.selectionEnd;\n }\n return offset !== 0;\n },\n\n /**\n * Moves cursor left\n * @param {Event} e Event object\n */\n moveCursorLeft: function(e) {\n if (this.selectionStart === 0 && this.selectionEnd === 0) {\n return;\n }\n this._moveCursorLeftOrRight('Left', e);\n },\n\n /**\n * @private\n * @return {Boolean} true if a change happened\n */\n _move: function(e, prop, direction) {\n var newValue;\n if (e.altKey) {\n newValue = this['findWordBoundary' + direction](this[prop]);\n }\n else if (e.metaKey || e.keyCode === 35 || e.keyCode === 36 ) {\n newValue = this['findLineBoundary' + direction](this[prop]);\n }\n else {\n this[prop] += direction === 'Left' ? -1 : 1;\n return true;\n }\n if (typeof newValue !== undefined && this[prop] !== newValue) {\n this[prop] = newValue;\n return true;\n }\n },\n\n /**\n * @private\n */\n _moveLeft: function(e, prop) {\n return this._move(e, prop, 'Left');\n },\n\n /**\n * @private\n */\n _moveRight: function(e, prop) {\n return this._move(e, prop, 'Right');\n },\n\n /**\n * Moves cursor left without keeping selection\n * @param {Event} e\n */\n moveCursorLeftWithoutShift: function(e) {\n var change = true;\n this._selectionDirection = 'left';\n\n // only move cursor when there is no selection,\n // otherwise we discard it, and leave cursor on same place\n if (this.selectionEnd === this.selectionStart && this.selectionStart !== 0) {\n change = this._moveLeft(e, 'selectionStart');\n\n }\n this.selectionEnd = this.selectionStart;\n return change;\n },\n\n /**\n * Moves cursor left while keeping selection\n * @param {Event} e\n */\n moveCursorLeftWithShift: function(e) {\n if (this._selectionDirection === 'right' && this.selectionStart !== this.selectionEnd) {\n return this._moveLeft(e, 'selectionEnd');\n }\n else if (this.selectionStart !== 0){\n this._selectionDirection = 'left';\n return this._moveLeft(e, 'selectionStart');\n }\n },\n\n /**\n * Moves cursor right\n * @param {Event} e Event object\n */\n moveCursorRight: function(e) {\n if (this.selectionStart >= this._text.length && this.selectionEnd >= this._text.length) {\n return;\n }\n this._moveCursorLeftOrRight('Right', e);\n },\n\n /**\n * Moves cursor right or Left, fires event\n * @param {String} direction 'Left', 'Right'\n * @param {Event} e Event object\n */\n _moveCursorLeftOrRight: function(direction, e) {\n var actionName = 'moveCursor' + direction + 'With';\n this._currentCursorOpacity = 1;\n\n if (e.shiftKey) {\n actionName += 'Shift';\n }\n else {\n actionName += 'outShift';\n }\n if (this[actionName](e)) {\n this.abortCursorAnimation();\n this.initDelayedCursor();\n this._fireSelectionChanged();\n this._updateTextarea();\n }\n },\n\n /**\n * Moves cursor right while keeping selection\n * @param {Event} e\n */\n moveCursorRightWithShift: function(e) {\n if (this._selectionDirection === 'left' && this.selectionStart !== this.selectionEnd) {\n return this._moveRight(e, 'selectionStart');\n }\n else if (this.selectionEnd !== this._text.length) {\n this._selectionDirection = 'right';\n return this._moveRight(e, 'selectionEnd');\n }\n },\n\n /**\n * Moves cursor right without keeping selection\n * @param {Event} e Event object\n */\n moveCursorRightWithoutShift: function(e) {\n var changed = true;\n this._selectionDirection = 'right';\n\n if (this.selectionStart === this.selectionEnd) {\n changed = this._moveRight(e, 'selectionStart');\n this.selectionEnd = this.selectionStart;\n }\n else {\n this.selectionStart = this.selectionEnd;\n }\n return changed;\n },\n\n /**\n * Removes characters from start/end\n * start/end ar per grapheme position in _text array.\n *\n * @param {Number} start\n * @param {Number} end default to start + 1\n */\n removeChars: function(start, end) {\n if (typeof end === 'undefined') {\n end = start + 1;\n }\n this.removeStyleFromTo(start, end);\n this._text.splice(start, end - start);\n this.text = this._text.join('');\n this.set('dirty', true);\n if (this._shouldClearDimensionCache()) {\n this.initDimensions();\n this.setCoords();\n }\n this._removeExtraneousStyles();\n },\n\n /**\n * insert characters at start position, before start position.\n * start equal 1 it means the text get inserted between actual grapheme 0 and 1\n * if style array is provided, it must be as the same length of text in graphemes\n * if end is provided and is bigger than start, old text is replaced.\n * start/end ar per grapheme position in _text array.\n *\n * @param {String} text text to insert\n * @param {Array} style array of style objects\n * @param {Number} start\n * @param {Number} end default to start + 1\n */\n insertChars: function(text, style, start, end) {\n if (typeof end === 'undefined') {\n end = start;\n }\n if (end > start) {\n this.removeStyleFromTo(start, end);\n }\n var graphemes = fabric.util.string.graphemeSplit(text);\n this.insertNewStyleBlock(graphemes, start, style);\n this._text = [].concat(this._text.slice(0, start), graphemes, this._text.slice(end));\n this.text = this._text.join('');\n this.set('dirty', true);\n if (this._shouldClearDimensionCache()) {\n this.initDimensions();\n this.setCoords();\n }\n this._removeExtraneousStyles();\n },\n\n});\n\n\n/* _TO_SVG_START_ */\n(function() {\n var toFixed = fabric.util.toFixed,\n multipleSpacesRegex = / +/g;\n\n fabric.util.object.extend(fabric.Text.prototype, /** @lends fabric.Text.prototype */ {\n\n /**\n * Returns SVG representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n _toSVG: function() {\n var offsets = this._getSVGLeftTopOffsets(),\n textAndBg = this._getSVGTextAndBg(offsets.textTop, offsets.textLeft);\n return this._wrapSVGTextAndBg(textAndBg);\n },\n\n /**\n * Returns svg representation of an instance\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n toSVG: function(reviver) {\n return this._createBaseSVGMarkup(\n this._toSVG(),\n { reviver: reviver, noStyle: true, withShadow: true }\n );\n },\n\n /**\n * @private\n */\n _getSVGLeftTopOffsets: function() {\n return {\n textLeft: -this.width / 2,\n textTop: -this.height / 2,\n lineTop: this.getHeightOfLine(0)\n };\n },\n\n /**\n * @private\n */\n _wrapSVGTextAndBg: function(textAndBg) {\n var noShadow = true,\n textDecoration = this.getSvgTextDecoration(this);\n return [\n textAndBg.textBgRects.join(''),\n '\\t\\t',\n textAndBg.textSpans.join(''),\n '\\n'\n ];\n },\n\n /**\n * @private\n * @param {Number} textTopOffset Text top offset\n * @param {Number} textLeftOffset Text left offset\n * @return {Object}\n */\n _getSVGTextAndBg: function(textTopOffset, textLeftOffset) {\n var textSpans = [],\n textBgRects = [],\n height = textTopOffset, lineOffset;\n // bounding-box background\n this._setSVGBg(textBgRects);\n\n // text and text-background\n for (var i = 0, len = this._textLines.length; i < len; i++) {\n lineOffset = this._getLineLeftOffset(i);\n if (this.textBackgroundColor || this.styleHas('textBackgroundColor', i)) {\n this._setSVGTextLineBg(textBgRects, i, textLeftOffset + lineOffset, height);\n }\n this._setSVGTextLineText(textSpans, i, textLeftOffset + lineOffset, height);\n height += this.getHeightOfLine(i);\n }\n\n return {\n textSpans: textSpans,\n textBgRects: textBgRects\n };\n },\n\n /**\n * @private\n */\n _createTextCharSpan: function(_char, styleDecl, left, top) {\n var shouldUseWhitespace = _char !== _char.trim() || _char.match(multipleSpacesRegex),\n styleProps = this.getSvgSpanStyles(styleDecl, shouldUseWhitespace),\n fillStyles = styleProps ? 'style=\"' + styleProps + '\"' : '',\n dy = styleDecl.deltaY, dySpan = '',\n NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n if (dy) {\n dySpan = ' dy=\"' + toFixed(dy, NUM_FRACTION_DIGITS) + '\" ';\n }\n return [\n '',\n fabric.util.string.escapeXml(_char),\n ''\n ].join('');\n },\n\n _setSVGTextLineText: function(textSpans, lineIndex, textLeftOffset, textTopOffset) {\n // set proper line offset\n var lineHeight = this.getHeightOfLine(lineIndex),\n isJustify = this.textAlign.indexOf('justify') !== -1,\n actualStyle,\n nextStyle,\n charsToRender = '',\n charBox, style,\n boxWidth = 0,\n line = this._textLines[lineIndex],\n timeToRender;\n\n textTopOffset += lineHeight * (1 - this._fontSizeFraction) / this.lineHeight;\n for (var i = 0, len = line.length - 1; i <= len; i++) {\n timeToRender = i === len || this.charSpacing;\n charsToRender += line[i];\n charBox = this.__charBounds[lineIndex][i];\n if (boxWidth === 0) {\n textLeftOffset += charBox.kernedWidth - charBox.width;\n boxWidth += charBox.width;\n }\n else {\n boxWidth += charBox.kernedWidth;\n }\n if (isJustify && !timeToRender) {\n if (this._reSpaceAndTab.test(line[i])) {\n timeToRender = true;\n }\n }\n if (!timeToRender) {\n // if we have charSpacing, we render char by char\n actualStyle = actualStyle || this.getCompleteStyleDeclaration(lineIndex, i);\n nextStyle = this.getCompleteStyleDeclaration(lineIndex, i + 1);\n timeToRender = this._hasStyleChangedForSvg(actualStyle, nextStyle);\n }\n if (timeToRender) {\n style = this._getStyleDeclaration(lineIndex, i) || { };\n textSpans.push(this._createTextCharSpan(charsToRender, style, textLeftOffset, textTopOffset));\n charsToRender = '';\n actualStyle = nextStyle;\n textLeftOffset += boxWidth;\n boxWidth = 0;\n }\n }\n },\n\n _pushTextBgRect: function(textBgRects, color, left, top, width, height) {\n var NUM_FRACTION_DIGITS = fabric.Object.NUM_FRACTION_DIGITS;\n textBgRects.push(\n '\\t\\t\\n');\n },\n\n _setSVGTextLineBg: function(textBgRects, i, leftOffset, textTopOffset) {\n var line = this._textLines[i],\n heightOfLine = this.getHeightOfLine(i) / this.lineHeight,\n boxWidth = 0,\n boxStart = 0,\n charBox, currentColor,\n lastColor = this.getValueOfPropertyAt(i, 0, 'textBackgroundColor');\n for (var j = 0, jlen = line.length; j < jlen; j++) {\n charBox = this.__charBounds[i][j];\n currentColor = this.getValueOfPropertyAt(i, j, 'textBackgroundColor');\n if (currentColor !== lastColor) {\n lastColor && this._pushTextBgRect(textBgRects, lastColor, leftOffset + boxStart,\n textTopOffset, boxWidth, heightOfLine);\n boxStart = charBox.left;\n boxWidth = charBox.width;\n lastColor = currentColor;\n }\n else {\n boxWidth += charBox.kernedWidth;\n }\n }\n currentColor && this._pushTextBgRect(textBgRects, currentColor, leftOffset + boxStart,\n textTopOffset, boxWidth, heightOfLine);\n },\n\n /**\n * Adobe Illustrator (at least CS5) is unable to render rgba()-based fill values\n * we work around it by \"moving\" alpha channel into opacity attribute and setting fill's alpha to 1\n *\n * @private\n * @param {*} value\n * @return {String}\n */\n _getFillAttributes: function(value) {\n var fillColor = (value && typeof value === 'string') ? new fabric.Color(value) : '';\n if (!fillColor || !fillColor.getSource() || fillColor.getAlpha() === 1) {\n return 'fill=\"' + value + '\"';\n }\n return 'opacity=\"' + fillColor.getAlpha() + '\" fill=\"' + fillColor.setAlpha(1).toRgb() + '\"';\n },\n\n /**\n * @private\n */\n _getSVGLineTopOffset: function(lineIndex) {\n var lineTopOffset = 0, lastHeight = 0;\n for (var j = 0; j < lineIndex; j++) {\n lineTopOffset += this.getHeightOfLine(j);\n }\n lastHeight = this.getHeightOfLine(j);\n return {\n lineTop: lineTopOffset,\n offset: (this._fontSizeMult - this._fontSizeFraction) * lastHeight / (this.lineHeight * this._fontSizeMult)\n };\n },\n\n /**\n * Returns styles-string for svg-export\n * @param {Boolean} skipShadow a boolean to skip shadow filter output\n * @return {String}\n */\n getSvgStyles: function(skipShadow) {\n var svgStyle = fabric.Object.prototype.getSvgStyles.call(this, skipShadow);\n return svgStyle + ' white-space: pre;';\n },\n });\n})();\n/* _TO_SVG_END_ */\n\n\n(function(global) {\n\n 'use strict';\n\n var fabric = global.fabric || (global.fabric = {});\n\n /**\n * Textbox class, based on IText, allows the user to resize the text rectangle\n * and wraps lines automatically. Textboxes have their Y scaling locked, the\n * user can only change width. Height is adjusted automatically based on the\n * wrapping of lines.\n * @class fabric.Textbox\n * @extends fabric.IText\n * @mixes fabric.Observable\n * @return {fabric.Textbox} thisArg\n * @see {@link fabric.Textbox#initialize} for constructor definition\n */\n fabric.Textbox = fabric.util.createClass(fabric.IText, fabric.Observable, {\n\n /**\n * Type of an object\n * @type String\n * @default\n */\n type: 'textbox',\n\n /**\n * Minimum width of textbox, in pixels.\n * @type Number\n * @default\n */\n minWidth: 20,\n\n /**\n * Minimum calculated width of a textbox, in pixels.\n * fixed to 2 so that an empty textbox cannot go to 0\n * and is still selectable without text.\n * @type Number\n * @default\n */\n dynamicMinWidth: 2,\n\n /**\n * Cached array of text wrapping.\n * @type Array\n */\n __cachedLines: null,\n\n /**\n * Override standard Object class values\n */\n lockScalingFlip: true,\n\n /**\n * Override standard Object class values\n * Textbox needs this on false\n */\n noScaleCache: false,\n\n /**\n * Properties which when set cause object to change dimensions\n * @type Object\n * @private\n */\n _dimensionAffectingProps: fabric.Text.prototype._dimensionAffectingProps.concat('width'),\n\n /**\n * Use this regular expression to split strings in breakable lines\n * @private\n */\n _wordJoiners: /[ \\t\\r]/,\n\n /**\n * Use this boolean property in order to split strings that have no white space concept.\n * this is a cheap way to help with chinese/japanese\n * @type Boolean\n * @since 2.6.0\n */\n splitByGrapheme: false,\n\n /**\n * Unlike superclass's version of this function, Textbox does not update\n * its width.\n * @private\n * @override\n */\n initDimensions: function() {\n if (this.__skipDimension) {\n return;\n }\n this.isEditing && this.initDelayedCursor();\n this.clearContextTop();\n this._clearCache();\n // clear dynamicMinWidth as it will be different after we re-wrap line\n this.dynamicMinWidth = 0;\n // wrap lines\n this._styleMap = this._generateStyleMap(this._splitText());\n // if after wrapping, the width is smaller than dynamicMinWidth, change the width and re-wrap\n if (this.dynamicMinWidth > this.width) {\n this._set('width', this.dynamicMinWidth);\n }\n if (this.textAlign.indexOf('justify') !== -1) {\n // once text is measured we need to make space fatter to make justified text.\n this.enlargeSpaces();\n }\n // clear cache and re-calculate height\n this.height = this.calcTextHeight();\n this.saveState({ propertySet: '_dimensionAffectingProps' });\n },\n\n /**\n * Generate an object that translates the style object so that it is\n * broken up by visual lines (new lines and automatic wrapping).\n * The original text styles object is broken up by actual lines (new lines only),\n * which is only sufficient for Text / IText\n * @private\n */\n _generateStyleMap: function(textInfo) {\n var realLineCount = 0,\n realLineCharCount = 0,\n charCount = 0,\n map = {};\n\n for (var i = 0; i < textInfo.graphemeLines.length; i++) {\n if (textInfo.graphemeText[charCount] === '\\n' && i > 0) {\n realLineCharCount = 0;\n charCount++;\n realLineCount++;\n }\n else if (!this.splitByGrapheme && this._reSpaceAndTab.test(textInfo.graphemeText[charCount]) && i > 0) {\n // this case deals with space's that are removed from end of lines when wrapping\n realLineCharCount++;\n charCount++;\n }\n\n map[i] = { line: realLineCount, offset: realLineCharCount };\n\n charCount += textInfo.graphemeLines[i].length;\n realLineCharCount += textInfo.graphemeLines[i].length;\n }\n\n return map;\n },\n\n /**\n * Returns true if object has a style property or has it on a specified line\n * @param {Number} lineIndex\n * @return {Boolean}\n */\n styleHas: function(property, lineIndex) {\n if (this._styleMap && !this.isWrapping) {\n var map = this._styleMap[lineIndex];\n if (map) {\n lineIndex = map.line;\n }\n }\n return fabric.Text.prototype.styleHas.call(this, property, lineIndex);\n },\n\n /**\n * Returns true if object has no styling or no styling in a line\n * @param {Number} lineIndex , lineIndex is on wrapped lines.\n * @return {Boolean}\n */\n isEmptyStyles: function(lineIndex) {\n if (!this.styles) {\n return true;\n }\n var offset = 0, nextLineIndex = lineIndex + 1, nextOffset, obj, shouldLimit = false,\n map = this._styleMap[lineIndex], mapNextLine = this._styleMap[lineIndex + 1];\n if (map) {\n lineIndex = map.line;\n offset = map.offset;\n }\n if (mapNextLine) {\n nextLineIndex = mapNextLine.line;\n shouldLimit = nextLineIndex === lineIndex;\n nextOffset = mapNextLine.offset;\n }\n obj = typeof lineIndex === 'undefined' ? this.styles : { line: this.styles[lineIndex] };\n for (var p1 in obj) {\n for (var p2 in obj[p1]) {\n if (p2 >= offset && (!shouldLimit || p2 < nextOffset)) {\n // eslint-disable-next-line no-unused-vars\n for (var p3 in obj[p1][p2]) {\n return false;\n }\n }\n }\n }\n return true;\n },\n\n /**\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @private\n */\n _getStyleDeclaration: function(lineIndex, charIndex) {\n if (this._styleMap && !this.isWrapping) {\n var map = this._styleMap[lineIndex];\n if (!map) {\n return null;\n }\n lineIndex = map.line;\n charIndex = map.offset + charIndex;\n }\n return this.callSuper('_getStyleDeclaration', lineIndex, charIndex);\n },\n\n /**\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @param {Object} style\n * @private\n */\n _setStyleDeclaration: function(lineIndex, charIndex, style) {\n var map = this._styleMap[lineIndex];\n lineIndex = map.line;\n charIndex = map.offset + charIndex;\n\n this.styles[lineIndex][charIndex] = style;\n },\n\n /**\n * @param {Number} lineIndex\n * @param {Number} charIndex\n * @private\n */\n _deleteStyleDeclaration: function(lineIndex, charIndex) {\n var map = this._styleMap[lineIndex];\n lineIndex = map.line;\n charIndex = map.offset + charIndex;\n delete this.styles[lineIndex][charIndex];\n },\n\n /**\n * probably broken need a fix\n * Returns the real style line that correspond to the wrapped lineIndex line\n * Used just to verify if the line does exist or not.\n * @param {Number} lineIndex\n * @returns {Boolean} if the line exists or not\n * @private\n */\n _getLineStyle: function(lineIndex) {\n var map = this._styleMap[lineIndex];\n return !!this.styles[map.line];\n },\n\n /**\n * Set the line style to an empty object so that is initialized\n * @param {Number} lineIndex\n * @param {Object} style\n * @private\n */\n _setLineStyle: function(lineIndex) {\n var map = this._styleMap[lineIndex];\n this.styles[map.line] = {};\n },\n\n /**\n * Wraps text using the 'width' property of Textbox. First this function\n * splits text on newlines, so we preserve newlines entered by the user.\n * Then it wraps each line using the width of the Textbox by calling\n * _wrapLine().\n * @param {Array} lines The string array of text that is split into lines\n * @param {Number} desiredWidth width you want to wrap to\n * @returns {Array} Array of lines\n */\n _wrapText: function(lines, desiredWidth) {\n var wrapped = [], i;\n this.isWrapping = true;\n for (i = 0; i < lines.length; i++) {\n wrapped = wrapped.concat(this._wrapLine(lines[i], i, desiredWidth));\n }\n this.isWrapping = false;\n return wrapped;\n },\n\n /**\n * Helper function to measure a string of text, given its lineIndex and charIndex offset\n * it gets called when charBounds are not available yet.\n * @param {CanvasRenderingContext2D} ctx\n * @param {String} text\n * @param {number} lineIndex\n * @param {number} charOffset\n * @returns {number}\n * @private\n */\n _measureWord: function(word, lineIndex, charOffset) {\n var width = 0, prevGrapheme, skipLeft = true;\n charOffset = charOffset || 0;\n for (var i = 0, len = word.length; i < len; i++) {\n var box = this._getGraphemeBox(word[i], lineIndex, i + charOffset, prevGrapheme, skipLeft);\n width += box.kernedWidth;\n prevGrapheme = word[i];\n }\n return width;\n },\n\n /**\n * Wraps a line of text using the width of the Textbox and a context.\n * @param {Array} line The grapheme array that represent the line\n * @param {Number} lineIndex\n * @param {Number} desiredWidth width you want to wrap the line to\n * @param {Number} reservedSpace space to remove from wrapping for custom functionalities\n * @returns {Array} Array of line(s) into which the given text is wrapped\n * to.\n */\n _wrapLine: function(_line, lineIndex, desiredWidth, reservedSpace) {\n var lineWidth = 0,\n splitByGrapheme = this.splitByGrapheme,\n graphemeLines = [],\n line = [],\n // spaces in different languages?\n words = splitByGrapheme ? fabric.util.string.graphemeSplit(_line) : _line.split(this._wordJoiners),\n word = '',\n offset = 0,\n infix = splitByGrapheme ? '' : ' ',\n wordWidth = 0,\n infixWidth = 0,\n largestWordWidth = 0,\n lineJustStarted = true,\n additionalSpace = this._getWidthOfCharSpacing(),\n reservedSpace = reservedSpace || 0;\n // fix a difference between split and graphemeSplit\n if (words.length === 0) {\n words.push([]);\n }\n desiredWidth -= reservedSpace;\n for (var i = 0; i < words.length; i++) {\n // if using splitByGrapheme words are already in graphemes.\n word = splitByGrapheme ? words[i] : fabric.util.string.graphemeSplit(words[i]);\n wordWidth = this._measureWord(word, lineIndex, offset);\n offset += word.length;\n\n lineWidth += infixWidth + wordWidth - additionalSpace;\n if (lineWidth > desiredWidth && !lineJustStarted) {\n graphemeLines.push(line);\n line = [];\n lineWidth = wordWidth;\n lineJustStarted = true;\n }\n else {\n lineWidth += additionalSpace;\n }\n\n if (!lineJustStarted && !splitByGrapheme) {\n line.push(infix);\n }\n line = line.concat(word);\n\n infixWidth = splitByGrapheme ? 0 : this._measureWord([infix], lineIndex, offset);\n offset++;\n lineJustStarted = false;\n // keep track of largest word\n if (wordWidth > largestWordWidth) {\n largestWordWidth = wordWidth;\n }\n }\n\n i && graphemeLines.push(line);\n\n if (largestWordWidth + reservedSpace > this.dynamicMinWidth) {\n this.dynamicMinWidth = largestWordWidth - additionalSpace + reservedSpace;\n }\n return graphemeLines;\n },\n\n /**\n * Detect if the text line is ended with an hard break\n * text and itext do not have wrapping, return false\n * @param {Number} lineIndex text to split\n * @return {Boolean}\n */\n isEndOfWrapping: function(lineIndex) {\n if (!this._styleMap[lineIndex + 1]) {\n // is last line, return true;\n return true;\n }\n if (this._styleMap[lineIndex + 1].line !== this._styleMap[lineIndex].line) {\n // this is last line before a line break, return true;\n return true;\n }\n return false;\n },\n\n /**\n * Detect if a line has a linebreak and so we need to account for it when moving\n * and counting style.\n * @return Number\n */\n missingNewlineOffset: function(lineIndex) {\n if (this.splitByGrapheme) {\n return this.isEndOfWrapping(lineIndex) ? 1 : 0;\n }\n return 1;\n },\n\n /**\n * Gets lines of text to render in the Textbox. This function calculates\n * text wrapping on the fly every time it is called.\n * @param {String} text text to split\n * @returns {Array} Array of lines in the Textbox.\n * @override\n */\n _splitTextIntoLines: function(text) {\n var newText = fabric.Text.prototype._splitTextIntoLines.call(this, text),\n graphemeLines = this._wrapText(newText.lines, this.width),\n lines = new Array(graphemeLines.length);\n for (var i = 0; i < graphemeLines.length; i++) {\n lines[i] = graphemeLines[i].join('');\n }\n newText.lines = lines;\n newText.graphemeLines = graphemeLines;\n return newText;\n },\n\n getMinWidth: function() {\n return Math.max(this.minWidth, this.dynamicMinWidth);\n },\n\n _removeExtraneousStyles: function() {\n var linesToKeep = {};\n for (var prop in this._styleMap) {\n if (this._textLines[prop]) {\n linesToKeep[this._styleMap[prop].line] = 1;\n }\n }\n for (var prop in this.styles) {\n if (!linesToKeep[prop]) {\n delete this.styles[prop];\n }\n }\n },\n\n /**\n * Returns object representation of an instance\n * @method toObject\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} object representation of an instance\n */\n toObject: function(propertiesToInclude) {\n return this.callSuper('toObject', ['minWidth', 'splitByGrapheme'].concat(propertiesToInclude));\n }\n });\n\n /**\n * Returns fabric.Textbox instance from an object representation\n * @static\n * @memberOf fabric.Textbox\n * @param {Object} object Object to create an instance from\n * @param {Function} [callback] Callback to invoke when an fabric.Textbox instance is created\n */\n fabric.Textbox.fromObject = function(object, callback) {\n return fabric.Object._fromObject('Textbox', object, callback, 'text');\n };\n})(typeof exports !== 'undefined' ? exports : this);\n\n\n(function() {\n\n var controlsUtils = fabric.controlsUtils,\n scaleSkewStyleHandler = controlsUtils.scaleSkewCursorStyleHandler,\n scaleStyleHandler = controlsUtils.scaleCursorStyleHandler,\n scalingEqually = controlsUtils.scalingEqually,\n scalingYOrSkewingX = controlsUtils.scalingYOrSkewingX,\n scalingXOrSkewingY = controlsUtils.scalingXOrSkewingY,\n scaleOrSkewActionName = controlsUtils.scaleOrSkewActionName,\n objectControls = fabric.Object.prototype.controls;\n\n objectControls.ml = new fabric.Control({\n x: -0.5,\n y: 0,\n cursorStyleHandler: scaleSkewStyleHandler,\n actionHandler: scalingXOrSkewingY,\n getActionName: scaleOrSkewActionName,\n });\n\n objectControls.mr = new fabric.Control({\n x: 0.5,\n y: 0,\n cursorStyleHandler: scaleSkewStyleHandler,\n actionHandler: scalingXOrSkewingY,\n getActionName: scaleOrSkewActionName,\n });\n\n objectControls.mb = new fabric.Control({\n x: 0,\n y: 0.5,\n cursorStyleHandler: scaleSkewStyleHandler,\n actionHandler: scalingYOrSkewingX,\n getActionName: scaleOrSkewActionName,\n });\n\n objectControls.mt = new fabric.Control({\n x: 0,\n y: -0.5,\n cursorStyleHandler: scaleSkewStyleHandler,\n actionHandler: scalingYOrSkewingX,\n getActionName: scaleOrSkewActionName,\n });\n\n objectControls.tl = new fabric.Control({\n x: -0.5,\n y: -0.5,\n cursorStyleHandler: scaleStyleHandler,\n actionHandler: scalingEqually\n });\n\n objectControls.tr = new fabric.Control({\n x: 0.5,\n y: -0.5,\n cursorStyleHandler: scaleStyleHandler,\n actionHandler: scalingEqually\n });\n\n objectControls.bl = new fabric.Control({\n x: -0.5,\n y: 0.5,\n cursorStyleHandler: scaleStyleHandler,\n actionHandler: scalingEqually\n });\n\n objectControls.br = new fabric.Control({\n x: 0.5,\n y: 0.5,\n cursorStyleHandler: scaleStyleHandler,\n actionHandler: scalingEqually\n });\n\n objectControls.mtr = new fabric.Control({\n x: 0,\n y: -0.5,\n actionHandler: controlsUtils.rotationWithSnapping,\n cursorStyleHandler: controlsUtils.rotationStyleHandler,\n offsetY: -40,\n withConnection: true,\n actionName: 'rotate',\n });\n\n if (fabric.Textbox) {\n // this is breaking the prototype inheritance, no time / ideas to fix it.\n // is important to document that if you want to have all objects to have a\n // specific custom control, you have to add it to Object prototype and to Textbox\n // prototype. The controls are shared as references. So changes to control `tr`\n // can still apply to all objects if needed.\n var textBoxControls = fabric.Textbox.prototype.controls = { };\n\n textBoxControls.mtr = objectControls.mtr;\n textBoxControls.tr = objectControls.tr;\n textBoxControls.br = objectControls.br;\n textBoxControls.tl = objectControls.tl;\n textBoxControls.bl = objectControls.bl;\n textBoxControls.mt = objectControls.mt;\n textBoxControls.mb = objectControls.mb;\n\n textBoxControls.mr = new fabric.Control({\n x: 0.5,\n y: 0,\n actionHandler: controlsUtils.changeWidth,\n cursorStyleHandler: scaleSkewStyleHandler,\n actionName: 'resizing',\n });\n\n textBoxControls.ml = new fabric.Control({\n x: -0.5,\n y: 0,\n actionHandler: controlsUtils.changeWidth,\n cursorStyleHandler: scaleSkewStyleHandler,\n actionName: 'resizing',\n });\n }\n})();\n\n\n(function () {\n /** ERASER_START */\n\n /**\n * add `eraser` to enlivened props\n */\n fabric.Object.ENLIVEN_PROPS.push('eraser');\n\n var __drawClipPath = fabric.Object.prototype._drawClipPath;\n var _needsItsOwnCache = fabric.Object.prototype.needsItsOwnCache;\n var _toObject = fabric.Object.prototype.toObject;\n var _getSvgCommons = fabric.Object.prototype.getSvgCommons;\n var __createBaseClipPathSVGMarkup = fabric.Object.prototype._createBaseClipPathSVGMarkup;\n var __createBaseSVGMarkup = fabric.Object.prototype._createBaseSVGMarkup;\n\n fabric.Object.prototype.cacheProperties.push('eraser');\n fabric.Object.prototype.stateProperties.push('eraser');\n\n /**\n * @fires erasing:end\n */\n fabric.util.object.extend(fabric.Object.prototype, {\n /**\n * Indicates whether this object can be erased by {@link fabric.EraserBrush}\n * The `deep` option introduces fine grained control over a group's `erasable` property.\n * When set to `deep` the eraser will erase nested objects if they are erasable, leaving the group and the other objects untouched.\n * When set to `true` the eraser will erase the entire group. Once the group changes the eraser is propagated to its children for proper functionality.\n * When set to `false` the eraser will leave all objects including the group untouched.\n * @tutorial {@link http://fabricjs.com/erasing#erasable_property}\n * @type boolean | 'deep'\n * @default true\n */\n erasable: true,\n\n /**\n * @tutorial {@link http://fabricjs.com/erasing#eraser}\n * @type fabric.Eraser\n */\n eraser: undefined,\n\n /**\n * @override\n * @returns Boolean\n */\n needsItsOwnCache: function () {\n return _needsItsOwnCache.call(this) || !!this.eraser;\n },\n\n /**\n * draw eraser above clip path\n * @override\n * @private\n * @param {CanvasRenderingContext2D} ctx\n * @param {fabric.Object} clipPath\n */\n _drawClipPath: function (ctx, clipPath) {\n __drawClipPath.call(this, ctx, clipPath);\n if (this.eraser) {\n // update eraser size to match instance\n var size = this._getNonTransformedDimensions();\n this.eraser.isType('eraser') && this.eraser.set({\n width: size.x,\n height: size.y\n });\n __drawClipPath.call(this, ctx, this.eraser);\n }\n },\n\n /**\n * Returns an object representation of an instance\n * @param {Array} [propertiesToInclude] Any properties that you might want to additionally include in the output\n * @return {Object} Object representation of an instance\n */\n toObject: function (propertiesToInclude) {\n var object = _toObject.call(this, ['erasable'].concat(propertiesToInclude));\n if (this.eraser && !this.eraser.excludeFromExport) {\n object.eraser = this.eraser.toObject(propertiesToInclude);\n }\n return object;\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns id attribute for svg output\n * @override\n * @return {String}\n */\n getSvgCommons: function () {\n return _getSvgCommons.call(this) + (this.eraser ? 'mask=\"url(#' + this.eraser.clipPathId + ')\" ' : '');\n },\n\n /**\n * create svg markup for eraser\n * use to achieve erasing for svg, credit: https://travishorn.com/removing-parts-of-shapes-in-svg-b539a89e5649\n * must be called before object markup creation as it relies on the `clipPathId` property of the mask\n * @param {Function} [reviver]\n * @returns\n */\n _createEraserSVGMarkup: function (reviver) {\n if (this.eraser) {\n this.eraser.clipPathId = 'MASK_' + fabric.Object.__uid++;\n return [\n '',\n this.eraser.toSVG(reviver),\n '', '\\n'\n ].join('');\n }\n return '';\n },\n\n /**\n * @private\n */\n _createBaseClipPathSVGMarkup: function (objectMarkup, options) {\n return [\n this._createEraserSVGMarkup(options && options.reviver),\n __createBaseClipPathSVGMarkup.call(this, objectMarkup, options)\n ].join('');\n },\n\n /**\n * @private\n */\n _createBaseSVGMarkup: function (objectMarkup, options) {\n return [\n this._createEraserSVGMarkup(options && options.reviver),\n __createBaseSVGMarkup.call(this, objectMarkup, options)\n ].join('');\n }\n /* _TO_SVG_END_ */\n });\n\n var __restoreObjectsState = fabric.Group.prototype._restoreObjectsState;\n fabric.util.object.extend(fabric.Group.prototype, {\n /**\n * @private\n * @param {fabric.Path} path\n */\n _addEraserPathToObjects: function (path) {\n this._objects.forEach(function (object) {\n fabric.EraserBrush.prototype._addPathToObjectEraser.call(\n fabric.EraserBrush.prototype,\n object,\n path\n );\n });\n },\n\n /**\n * Applies the group's eraser to its objects\n * @tutorial {@link http://fabricjs.com/erasing#erasable_property}\n */\n applyEraserToObjects: function () {\n var _this = this, eraser = this.eraser;\n if (eraser) {\n delete this.eraser;\n var transform = _this.calcTransformMatrix();\n eraser.clone(function (eraser) {\n var clipPath = _this.clipPath;\n eraser.getObjects('path')\n .forEach(function (path) {\n // first we transform the path from the group's coordinate system to the canvas'\n var originalTransform = fabric.util.multiplyTransformMatrices(\n transform,\n path.calcTransformMatrix()\n );\n fabric.util.applyTransformToObject(path, originalTransform);\n if (clipPath) {\n clipPath.clone(function (_clipPath) {\n var eraserPath = fabric.EraserBrush.prototype.applyClipPathToPath.call(\n fabric.EraserBrush.prototype,\n path,\n _clipPath,\n transform\n );\n _this._addEraserPathToObjects(eraserPath);\n }, ['absolutePositioned', 'inverted']);\n }\n else {\n _this._addEraserPathToObjects(path);\n }\n });\n });\n }\n },\n\n /**\n * Propagate the group's eraser to its objects, crucial for proper functionality of the eraser within the group and nested objects.\n * @private\n */\n _restoreObjectsState: function () {\n this.erasable === true && this.applyEraserToObjects();\n return __restoreObjectsState.call(this);\n }\n });\n\n /**\n * An object's Eraser\n * @private\n * @class fabric.Eraser\n * @extends fabric.Group\n * @memberof fabric\n */\n fabric.Eraser = fabric.util.createClass(fabric.Group, {\n /**\n * @readonly\n * @static\n */\n type: 'eraser',\n\n /**\n * @default\n */\n originX: 'center',\n\n /**\n * @default\n */\n originY: 'center',\n\n drawObject: function (ctx) {\n ctx.save();\n ctx.fillStyle = 'black';\n ctx.fillRect(-this.width / 2, -this.height / 2, this.width, this.height);\n ctx.restore();\n this.callSuper('drawObject', ctx);\n },\n\n /**\n * eraser should retain size\n * dimensions should not change when paths are added or removed\n * handled by {@link fabric.Object#_drawClipPath}\n * @override\n * @private\n */\n _getBounds: function () {\n // noop\n },\n\n /* _TO_SVG_START_ */\n /**\n * Returns svg representation of an instance\n * use to achieve erasing for svg, credit: https://travishorn.com/removing-parts-of-shapes-in-svg-b539a89e5649\n * for masking we need to add a white rect before all paths\n *\n * @param {Function} [reviver] Method for further parsing of svg representation.\n * @return {String} svg representation of an instance\n */\n _toSVG: function (reviver) {\n var svgString = ['\\n'];\n var x = -this.width / 2, y = -this.height / 2;\n var rectSvg = [\n '\\n'\n ].join('');\n svgString.push('\\t\\t', rectSvg);\n for (var i = 0, len = this._objects.length; i < len; i++) {\n svgString.push('\\t\\t', this._objects[i].toSVG(reviver));\n }\n svgString.push('\\n');\n return svgString;\n },\n /* _TO_SVG_END_ */\n });\n\n /**\n * Returns {@link fabric.Eraser} instance from an object representation\n * @static\n * @memberOf fabric.Eraser\n * @param {Object} object Object to create an Eraser from\n * @param {Function} [callback] Callback to invoke when an eraser instance is created\n */\n fabric.Eraser.fromObject = function (object, callback) {\n var objects = object.objects;\n fabric.util.enlivenObjects(objects, function (enlivenedObjects) {\n var options = fabric.util.object.clone(object, true);\n delete options.objects;\n fabric.util.enlivenObjectEnlivables(object, options, function () {\n callback && callback(new fabric.Eraser(enlivenedObjects, options, true));\n });\n });\n };\n\n var __renderOverlay = fabric.Canvas.prototype._renderOverlay;\n /**\n * @fires erasing:start\n * @fires erasing:end\n */\n fabric.util.object.extend(fabric.Canvas.prototype, {\n /**\n * Used by {@link #renderAll}\n * @returns boolean\n */\n isErasing: function () {\n return (\n this.isDrawingMode &&\n this.freeDrawingBrush &&\n this.freeDrawingBrush.type === 'eraser' &&\n this.freeDrawingBrush._isErasing\n );\n },\n\n /**\n * While erasing the brush clips out the erasing path from canvas\n * so we need to render it on top of canvas every render\n * @param {CanvasRenderingContext2D} ctx\n */\n _renderOverlay: function (ctx) {\n __renderOverlay.call(this, ctx);\n if (this.isErasing() && !this.freeDrawingBrush.inverted) {\n this.freeDrawingBrush._render();\n }\n }\n });\n\n /**\n * EraserBrush class\n * Supports selective erasing meaning that only erasable objects are affected by the eraser brush.\n * Supports **inverted** erasing meaning that the brush can \"undo\" erasing.\n *\n * In order to support selective erasing, the brush clips the entire canvas\n * and then draws all non-erasable objects over the erased path using a pattern brush so to speak (masking).\n * If brush is **inverted** there is no need to clip canvas. The brush draws all erasable objects without their eraser.\n * This achieves the desired effect of seeming to erase or unerase only erasable objects.\n * After erasing is done the created path is added to all intersected objects' `eraser` property.\n *\n * In order to update the EraserBrush call `preparePattern`.\n * It may come in handy when canvas changes during erasing (i.e animations) and you want the eraser to reflect the changes.\n *\n * @tutorial {@link http://fabricjs.com/erasing}\n * @class fabric.EraserBrush\n * @extends fabric.PencilBrush\n * @memberof fabric\n */\n fabric.EraserBrush = fabric.util.createClass(\n fabric.PencilBrush,\n /** @lends fabric.EraserBrush.prototype */ {\n type: 'eraser',\n\n /**\n * When set to `true` the brush will create a visual effect of undoing erasing\n */\n inverted: false,\n\n /**\n * @private\n */\n _isErasing: false,\n\n /**\n *\n * @private\n * @param {fabric.Object} object\n * @returns boolean\n */\n _isErasable: function (object) {\n return object.erasable !== false;\n },\n\n /**\n * @private\n * This is designed to support erasing a collection with both erasable and non-erasable objects.\n * Iterates over collections to allow nested selective erasing.\n * Prepares the pattern brush that will draw on the top context to achieve the desired visual effect.\n * If brush is **NOT** inverted render all non-erasable objects.\n * If brush is inverted render all erasable objects that have been erased with their clip path inverted.\n * This will render the erased parts as if they were not erased.\n *\n * @param {fabric.Collection} collection\n * @param {CanvasRenderingContext2D} ctx\n * @param {{ visibility: fabric.Object[], eraser: fabric.Object[], collection: fabric.Object[] }} restorationContext\n */\n _prepareCollectionTraversal: function (collection, ctx, restorationContext) {\n collection.forEachObject(function (obj) {\n if (obj.forEachObject && obj.erasable === 'deep') {\n // traverse\n this._prepareCollectionTraversal(obj, ctx, restorationContext);\n }\n else if (!this.inverted && obj.erasable && obj.visible) {\n // render only non-erasable objects\n obj.visible = false;\n collection.dirty = true;\n restorationContext.visibility.push(obj);\n restorationContext.collection.push(collection);\n }\n else if (this.inverted && obj.visible) {\n // render only erasable objects that were erased\n if (obj.erasable && obj.eraser) {\n obj.eraser.inverted = true;\n obj.dirty = true;\n collection.dirty = true;\n restorationContext.eraser.push(obj);\n restorationContext.collection.push(collection);\n }\n else {\n obj.visible = false;\n collection.dirty = true;\n restorationContext.visibility.push(obj);\n restorationContext.collection.push(collection);\n }\n }\n }, this);\n },\n\n /**\n * Prepare the pattern for the erasing brush\n * This pattern will be drawn on the top context, achieving a visual effect of erasing only erasable objects\n * @todo decide how overlay color should behave when `inverted === true`, currently draws over it which is undesirable\n * @private\n */\n preparePattern: function () {\n if (!this._patternCanvas) {\n this._patternCanvas = fabric.util.createCanvasElement();\n }\n var canvas = this._patternCanvas;\n canvas.width = this.canvas.width;\n canvas.height = this.canvas.height;\n var patternCtx = canvas.getContext('2d');\n if (this.canvas._isRetinaScaling()) {\n var retinaScaling = this.canvas.getRetinaScaling();\n this.canvas.__initRetinaScaling(retinaScaling, canvas, patternCtx);\n }\n var backgroundImage = this.canvas.backgroundImage,\n bgErasable = backgroundImage && this._isErasable(backgroundImage),\n overlayImage = this.canvas.overlayImage,\n overlayErasable = overlayImage && this._isErasable(overlayImage);\n if (!this.inverted && ((backgroundImage && !bgErasable) || !!this.canvas.backgroundColor)) {\n if (bgErasable) { this.canvas.backgroundImage = undefined; }\n this.canvas._renderBackground(patternCtx);\n if (bgErasable) { this.canvas.backgroundImage = backgroundImage; }\n }\n else if (this.inverted && (backgroundImage && bgErasable)) {\n var color = this.canvas.backgroundColor;\n this.canvas.backgroundColor = undefined;\n this.canvas._renderBackground(patternCtx);\n this.canvas.backgroundColor = color;\n }\n patternCtx.save();\n patternCtx.transform.apply(patternCtx, this.canvas.viewportTransform);\n var restorationContext = { visibility: [], eraser: [], collection: [] };\n this._prepareCollectionTraversal(this.canvas, patternCtx, restorationContext);\n this.canvas._renderObjects(patternCtx, this.canvas._objects);\n restorationContext.visibility.forEach(function (obj) { obj.visible = true; });\n restorationContext.eraser.forEach(function (obj) {\n obj.eraser.inverted = false;\n obj.dirty = true;\n });\n restorationContext.collection.forEach(function (obj) { obj.dirty = true; });\n patternCtx.restore();\n if (!this.inverted && ((overlayImage && !overlayErasable) || !!this.canvas.overlayColor)) {\n if (overlayErasable) { this.canvas.overlayImage = undefined; }\n __renderOverlay.call(this.canvas, patternCtx);\n if (overlayErasable) { this.canvas.overlayImage = overlayImage; }\n }\n else if (this.inverted && (overlayImage && overlayErasable)) {\n var color = this.canvas.overlayColor;\n this.canvas.overlayColor = undefined;\n __renderOverlay.call(this.canvas, patternCtx);\n this.canvas.overlayColor = color;\n }\n },\n\n /**\n * Sets brush styles\n * @private\n * @param {CanvasRenderingContext2D} ctx\n */\n _setBrushStyles: function (ctx) {\n this.callSuper('_setBrushStyles', ctx);\n ctx.strokeStyle = 'black';\n },\n\n /**\n * **Customiztion**\n *\n * if you need the eraser to update on each render (i.e animating during erasing) override this method by **adding** the following (performance may suffer):\n * @example\n * ```\n * if(ctx === this.canvas.contextTop) {\n * this.preparePattern();\n * }\n * ```\n *\n * @override fabric.BaseBrush#_saveAndTransform\n * @param {CanvasRenderingContext2D} ctx\n */\n _saveAndTransform: function (ctx) {\n this.callSuper('_saveAndTransform', ctx);\n this._setBrushStyles(ctx);\n ctx.globalCompositeOperation = ctx === this.canvas.getContext() ? 'destination-out' : 'source-over';\n },\n\n /**\n * We indicate {@link fabric.PencilBrush} to repaint itself if necessary\n * @returns\n */\n needsFullRender: function () {\n return true;\n },\n\n /**\n *\n * @param {fabric.Point} pointer\n * @param {fabric.IEvent} options\n * @returns\n */\n onMouseDown: function (pointer, options) {\n if (!this.canvas._isMainEvent(options.e)) {\n return;\n }\n this._prepareForDrawing(pointer);\n // capture coordinates immediately\n // this allows to draw dots (when movement never occurs)\n this._captureDrawingPath(pointer);\n\n // prepare for erasing\n this.preparePattern();\n this._isErasing = true;\n this.canvas.fire('erasing:start');\n this._render();\n },\n\n /**\n * Rendering Logic:\n * 1. Use brush to clip canvas by rendering it on top of canvas (unnecessary if `inverted === true`)\n * 2. Render brush with canvas pattern on top context\n *\n */\n _render: function () {\n var ctx;\n if (!this.inverted) {\n // clip canvas\n ctx = this.canvas.getContext();\n this.callSuper('_render', ctx);\n }\n // render brush and mask it with image of non erasables\n ctx = this.canvas.contextTop;\n this.canvas.clearContext(ctx);\n this.callSuper('_render', ctx);\n ctx.save();\n var t = this.canvas.getRetinaScaling(), s = 1 / t;\n ctx.scale(s, s);\n ctx.globalCompositeOperation = 'source-in';\n ctx.drawImage(this._patternCanvas, 0, 0);\n ctx.restore();\n },\n\n /**\n * Creates fabric.Path object\n * @override\n * @private\n * @param {(string|number)[][]} pathData Path data\n * @return {fabric.Path} Path to add on canvas\n * @returns\n */\n createPath: function (pathData) {\n var path = this.callSuper('createPath', pathData);\n path.globalCompositeOperation = this.inverted ? 'source-over' : 'destination-out';\n path.stroke = this.inverted ? 'white' : 'black';\n return path;\n },\n\n /**\n * Utility to apply a clip path to a path.\n * Used to preserve clipping on eraser paths in nested objects.\n * Called when a group has a clip path that should be applied to the path before applying erasing on the group's objects.\n * @param {fabric.Path} path The eraser path in canvas coordinate plane\n * @param {fabric.Object} clipPath The clipPath to apply to the path\n * @param {number[]} clipPathContainerTransformMatrix The transform matrix of the object that the clip path belongs to\n * @returns {fabric.Path} path with clip path\n */\n applyClipPathToPath: function (path, clipPath, clipPathContainerTransformMatrix) {\n var pathInvTransform = fabric.util.invertTransform(path.calcTransformMatrix()),\n clipPathTransform = clipPath.calcTransformMatrix(),\n transform = clipPath.absolutePositioned ?\n pathInvTransform :\n fabric.util.multiplyTransformMatrices(\n pathInvTransform,\n clipPathContainerTransformMatrix\n );\n // when passing down a clip path it becomes relative to the parent\n // so we transform it acoordingly and set `absolutePositioned` to false\n clipPath.absolutePositioned = false;\n fabric.util.applyTransformToObject(\n clipPath,\n fabric.util.multiplyTransformMatrices(\n transform,\n clipPathTransform\n )\n );\n // We need to clip `path` with both `clipPath` and it's own clip path if existing (`path.clipPath`)\n // so in turn `path` erases an object only where it overlaps with all it's clip paths, regardless of how many there are.\n // this is done because both clip paths may have nested clip paths of their own (this method walks down a collection => this may reccur),\n // so we can't assign one to the other's clip path property.\n path.clipPath = path.clipPath ? fabric.util.mergeClipPaths(clipPath, path.clipPath) : clipPath;\n return path;\n },\n\n /**\n * Utility to apply a clip path to a path.\n * Used to preserve clipping on eraser paths in nested objects.\n * Called when a group has a clip path that should be applied to the path before applying erasing on the group's objects.\n * @param {fabric.Path} path The eraser path\n * @param {fabric.Object} object The clipPath to apply to path belongs to object\n * @param {Function} callback Callback to be invoked with the cloned path after applying the clip path\n */\n clonePathWithClipPath: function (path, object, callback) {\n var objTransform = object.calcTransformMatrix();\n var clipPath = object.clipPath;\n var _this = this;\n path.clone(function (_path) {\n clipPath.clone(function (_clipPath) {\n callback(_this.applyClipPathToPath(_path, _clipPath, objTransform));\n }, ['absolutePositioned', 'inverted']);\n });\n },\n\n /**\n * Adds path to object's eraser, walks down object's descendants if necessary\n *\n * @fires erasing:end on object\n * @param {fabric.Object} obj\n * @param {fabric.Path} path\n */\n _addPathToObjectEraser: function (obj, path) {\n var _this = this;\n // object is collection, i.e group\n if (obj.forEachObject && obj.erasable === 'deep') {\n var targets = obj._objects.filter(function (_obj) {\n return _obj.erasable;\n });\n if (targets.length > 0 && obj.clipPath) {\n this.clonePathWithClipPath(path, obj, function (_path) {\n targets.forEach(function (_obj) {\n _this._addPathToObjectEraser(_obj, _path);\n });\n });\n }\n else if (targets.length > 0) {\n targets.forEach(function (_obj) {\n _this._addPathToObjectEraser(_obj, path);\n });\n }\n return;\n }\n // prepare eraser\n var eraser = obj.eraser;\n if (!eraser) {\n eraser = new fabric.Eraser();\n obj.eraser = eraser;\n }\n // clone and add path\n path.clone(function (path) {\n // http://fabricjs.com/using-transformations\n var desiredTransform = fabric.util.multiplyTransformMatrices(\n fabric.util.invertTransform(\n obj.calcTransformMatrix()\n ),\n path.calcTransformMatrix()\n );\n fabric.util.applyTransformToObject(path, desiredTransform);\n eraser.addWithUpdate(path);\n obj.set('dirty', true);\n obj.fire('erasing:end', {\n path: path\n });\n if (obj.group && Array.isArray(_this.__subTargets)) {\n _this.__subTargets.push(obj);\n }\n });\n },\n\n /**\n * Add the eraser path to canvas drawables' clip paths\n *\n * @param {fabric.Canvas} source\n * @param {fabric.Canvas} path\n * @returns {Object} canvas drawables that were erased by the path\n */\n applyEraserToCanvas: function (path) {\n var canvas = this.canvas;\n var drawables = {};\n [\n 'backgroundImage',\n 'overlayImage',\n ].forEach(function (prop) {\n var drawable = canvas[prop];\n if (drawable && drawable.erasable) {\n this._addPathToObjectEraser(drawable, path);\n drawables[prop] = drawable;\n }\n }, this);\n return drawables;\n },\n\n /**\n * On mouseup after drawing the path on contextTop canvas\n * we use the points captured to create an new fabric path object\n * and add it to every intersected erasable object.\n */\n _finalizeAndAddPath: function () {\n var ctx = this.canvas.contextTop, canvas = this.canvas;\n ctx.closePath();\n if (this.decimate) {\n this._points = this.decimatePoints(this._points, this.decimate);\n }\n\n // clear\n canvas.clearContext(canvas.contextTop);\n this._isErasing = false;\n\n var pathData = this._points && this._points.length > 1 ?\n this.convertPointsToSVGPath(this._points) :\n null;\n if (!pathData || this._isEmptySVGPath(pathData)) {\n canvas.fire('erasing:end');\n // do not create 0 width/height paths, as they are\n // rendered inconsistently across browsers\n // Firefox 4, for example, renders a dot,\n // whereas Chrome 10 renders nothing\n canvas.requestRenderAll();\n return;\n }\n\n var path = this.createPath(pathData);\n // needed for `intersectsWithObject`\n path.setCoords();\n // commense event sequence\n canvas.fire('before:path:created', { path: path });\n\n // finalize erasing\n var drawables = this.applyEraserToCanvas(path);\n var _this = this;\n this.__subTargets = [];\n var targets = [];\n canvas.forEachObject(function (obj) {\n if (obj.erasable && obj.intersectsWithObject(path, true, true)) {\n _this._addPathToObjectEraser(obj, path);\n targets.push(obj);\n }\n });\n // fire erasing:end\n canvas.fire('erasing:end', {\n path: path,\n targets: targets,\n subTargets: this.__subTargets,\n drawables: drawables\n });\n delete this.__subTargets;\n\n canvas.requestRenderAll();\n this._resetShadow();\n\n // fire event 'path' created\n canvas.fire('path:created', { path: path });\n }\n }\n );\n\n /** ERASER_END */\n})();\n\n"],"sourceRoot":""}