fabric 5.3.0 → 6.0.0-beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.babelrc +11 -0
- package/.babelrcAlt +19 -0
- package/.browserslistrc +5 -0
- package/.eslintrc.js +43 -0
- package/.eslintrc.json +38 -46
- package/.eslintrc_tests +12 -0
- package/.gitattributes +2 -0
- package/.prettierignore +16 -0
- package/.prettierrc +4 -0
- package/CHANGELOG.md +491 -189
- package/CONTRIBUTING.md +226 -58
- package/README.md +188 -239
- package/bower.json +1 -3
- package/dist/fabric.d.ts +1021 -0
- package/dist/index.cjs +28027 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.min.js +1 -0
- package/dist/index.mjs +27964 -0
- package/dist/index.mjs.map +1 -0
- package/dist/index.node.cjs +28092 -0
- package/dist/index.node.cjs.map +1 -0
- package/dist/index.node.d.ts +15 -0
- package/dist/index.node.mjs +28035 -0
- package/dist/index.node.mjs.map +1 -0
- package/dist/src/Collection.d.ts +126 -0
- package/dist/src/CommonMethods.d.ts +32 -0
- package/dist/src/EventTypeDefs.d.ts +226 -0
- package/dist/src/Intersection.d.ts +100 -0
- package/dist/src/Observable.d.ts +54 -0
- package/dist/src/Pattern.d.ts +104 -0
- package/dist/src/Point.d.ts +232 -0
- package/dist/src/Shadow.d.ts +87 -0
- package/dist/src/brushes/BaseBrush.d.ts +105 -0
- package/dist/src/brushes/CircleBrush.d.ts +49 -0
- package/dist/src/brushes/PatternBrush.d.ts +23 -0
- package/dist/src/brushes/PencilBrush.d.ts +92 -0
- package/dist/src/brushes/SprayBrush.d.ts +79 -0
- package/dist/src/cache.d.ts +46 -0
- package/dist/src/canvas/Canvas.d.ts +567 -0
- package/dist/src/canvas/SelectableCanvas.d.ts +723 -0
- package/dist/src/canvas/StaticCanvas.d.ts +751 -0
- package/dist/src/canvas/TextEditingManager.d.ts +17 -0
- package/dist/src/canvas/canvas_gestures.mixin.d.ts +2 -0
- package/dist/src/color/Color.d.ts +174 -0
- package/dist/src/color/color_map.d.ts +155 -0
- package/dist/src/color/constants.d.ts +22 -0
- package/dist/src/color/util.d.ts +12 -0
- package/dist/src/config.d.ts +115 -0
- package/dist/src/constants.d.ts +14 -0
- package/dist/src/controls/Control.d.ts +228 -0
- package/dist/src/controls/changeWidth.d.ts +13 -0
- package/dist/src/controls/controls.render.d.ts +29 -0
- package/dist/src/controls/default_controls.d.ts +50 -0
- package/dist/src/controls/drag.d.ts +12 -0
- package/dist/src/controls/polyControl.d.ts +5 -0
- package/dist/src/controls/rotate.d.ts +12 -0
- package/dist/src/controls/scale.d.ts +47 -0
- package/dist/src/controls/scaleSkew.d.ts +39 -0
- package/dist/src/controls/skew.d.ts +33 -0
- package/dist/src/controls/util.d.ts +41 -0
- package/dist/src/controls/wrapWithFireEvent.d.ts +8 -0
- package/dist/src/controls/wrapWithFixedAnchor.d.ts +9 -0
- package/dist/src/env/browser.d.ts +3 -0
- package/dist/src/env/index.d.ts +7 -0
- package/dist/src/env/node.d.ts +3 -0
- package/dist/src/env/types.d.ts +15 -0
- package/dist/src/filters/BaseFilter.d.ts +156 -0
- package/dist/src/filters/BlendColor.d.ts +80 -0
- package/dist/src/filters/BlendImage.d.ts +90 -0
- package/dist/src/filters/Blur.d.ts +50 -0
- package/dist/src/filters/Boilerplate.d.ts +46 -0
- package/dist/src/filters/Brightness.d.ts +46 -0
- package/dist/src/filters/Canvas2dFilterBackend.d.ts +27 -0
- package/dist/src/filters/ColorMatrix.d.ts +62 -0
- package/dist/src/filters/ColorMatrixFilters.d.ts +1169 -0
- package/dist/src/filters/Composed.d.ts +47 -0
- package/dist/src/filters/Contrast.d.ts +44 -0
- package/dist/src/filters/Convolute.d.ts +82 -0
- package/dist/src/filters/FilterBackend.d.ts +14 -0
- package/dist/src/filters/Gamma.d.ts +53 -0
- package/dist/src/filters/Grayscale.d.ts +45 -0
- package/dist/src/filters/HueRotation.d.ts +24 -0
- package/dist/src/filters/Invert.d.ts +54 -0
- package/dist/src/filters/Noise.d.ts +53 -0
- package/dist/src/filters/Pixelate.d.ts +43 -0
- package/dist/src/filters/RemoveColor.d.ts +62 -0
- package/dist/src/filters/Resize.d.ts +134 -0
- package/dist/src/filters/Saturation.d.ts +47 -0
- package/dist/src/filters/Vibrance.d.ts +47 -0
- package/dist/src/filters/WebGLFilterBackend.d.ts +126 -0
- package/dist/src/filters/WebGLProbe.d.ts +28 -0
- package/dist/src/filters/typedefs.d.ts +49 -0
- package/dist/src/gradient/Gradient.d.ts +149 -0
- package/dist/src/gradient/constants.d.ts +15 -0
- package/dist/src/gradient/parser/index.d.ts +4 -0
- package/dist/src/gradient/parser/misc.d.ts +4 -0
- package/dist/src/gradient/parser/parseColorStops.d.ts +6 -0
- package/dist/src/gradient/parser/parseCoords.d.ts +17 -0
- package/dist/src/gradient/typedefs.d.ts +93 -0
- package/dist/src/mixins/eraser_brush.mixin.d.ts +2 -0
- package/dist/src/mixins/stateful.mixin.d.ts +18 -0
- package/dist/src/parkinglot/canvas_animation.mixin.d.ts +2 -0
- package/dist/src/parkinglot/straighten.d.ts +2 -0
- package/dist/src/parser/applyViewboxTransform.d.ts +5 -0
- package/dist/src/parser/attributes.d.ts +6 -0
- package/dist/src/parser/constants.d.ts +54 -0
- package/dist/src/parser/doesSomeParentMatch.d.ts +2 -0
- package/dist/src/parser/elementById.d.ts +6 -0
- package/dist/src/parser/elementMatchesRule.d.ts +5 -0
- package/dist/src/parser/elements_parser.d.ts +3 -0
- package/dist/src/parser/getCSSRules.d.ts +7 -0
- package/dist/src/parser/getGlobalStylesForElement.d.ts +5 -0
- package/dist/src/parser/getGradientDefs.d.ts +7 -0
- package/dist/src/parser/getMultipleNodes.d.ts +2 -0
- package/dist/src/parser/getSvgRegex.d.ts +2 -0
- package/dist/src/parser/hasAncestorWithNodeName.d.ts +2 -0
- package/dist/src/parser/loadSVGFromString.d.ts +12 -0
- package/dist/src/parser/loadSVGFromURL.d.ts +13 -0
- package/dist/src/parser/normalizeAttr.d.ts +2 -0
- package/dist/src/parser/normalizeValue.d.ts +2 -0
- package/dist/src/parser/parseAttributes.d.ts +9 -0
- package/dist/src/parser/parseElements.d.ts +11 -0
- package/dist/src/parser/parseFontDeclaration.d.ts +10 -0
- package/dist/src/parser/parsePointsAttribute.d.ts +12 -0
- package/dist/src/parser/parseSVGDocument.d.ts +15 -0
- package/dist/src/parser/parseStyleAttribute.d.ts +9 -0
- package/dist/src/parser/parseStyleObject.d.ts +2 -0
- package/dist/src/parser/parseStyleString.d.ts +2 -0
- package/dist/src/parser/parseTransformAttribute.d.ts +10 -0
- package/dist/src/parser/parseUseDirectives.d.ts +2 -0
- package/dist/src/parser/percent.d.ts +9 -0
- package/dist/src/parser/recursivelyParseGradientsXlink.d.ts +2 -0
- package/dist/src/parser/rotateMatrix.d.ts +2 -0
- package/dist/src/parser/scaleMatrix.d.ts +2 -0
- package/dist/src/parser/selectorMatches.d.ts +2 -0
- package/dist/src/parser/setStrokeFillOpacity.d.ts +6 -0
- package/dist/src/parser/skewMatrix.d.ts +2 -0
- package/dist/src/parser/translateMatrix.d.ts +2 -0
- package/dist/src/shapes/ActiveSelection.d.ts +66 -0
- package/dist/src/shapes/Circle.d.ts +80 -0
- package/dist/src/shapes/Ellipse.d.ts +74 -0
- package/dist/src/shapes/Group.d.ts +381 -0
- package/dist/src/shapes/IText/DraggableTextDelegate.d.ts +78 -0
- package/dist/src/shapes/IText/IText.d.ts +322 -0
- package/dist/src/shapes/IText/ITextBehavior.d.ts +285 -0
- package/dist/src/shapes/IText/ITextClickBehavior.d.ts +81 -0
- package/dist/src/shapes/IText/ITextKeyBehavior.d.ts +193 -0
- package/dist/src/shapes/IText/constants.d.ts +13 -0
- package/dist/src/shapes/Image.d.ts +283 -0
- package/dist/src/shapes/Line.d.ts +117 -0
- package/dist/src/shapes/Object/AnimatableObject.d.ts +33 -0
- package/dist/src/shapes/Object/FabricObject.d.ts +9 -0
- package/dist/src/shapes/Object/FabricObjectSVGExportMixin.d.ts +74 -0
- package/dist/src/shapes/Object/InteractiveObject.d.ts +282 -0
- package/dist/src/shapes/Object/Object.d.ts +906 -0
- package/dist/src/shapes/Object/ObjectGeometry.d.ts +343 -0
- package/dist/src/shapes/Object/ObjectOrigin.d.ts +178 -0
- package/dist/src/shapes/Object/StackedObject.d.ts +62 -0
- package/dist/src/shapes/Object/defaultValues.d.ts +77 -0
- package/dist/src/shapes/Path.d.ts +123 -0
- package/dist/src/shapes/Polygon.d.ts +7 -0
- package/dist/src/shapes/Polyline.d.ts +130 -0
- package/dist/src/shapes/Rect.d.ts +62 -0
- package/dist/src/shapes/Text/StyledText.d.ts +118 -0
- package/dist/src/shapes/Text/Text.d.ts +656 -0
- package/dist/src/shapes/Text/TextSVGExportMixin.d.ts +32 -0
- package/dist/src/shapes/Textbox.d.ts +170 -0
- package/dist/src/shapes/Triangle.d.ts +17 -0
- package/dist/src/typedefs.d.ts +93 -0
- package/dist/src/util/animation/AnimationBase.d.ts +54 -0
- package/dist/src/util/animation/AnimationFrameProvider.d.ts +8 -0
- package/dist/src/util/animation/AnimationRegistry.d.ts +29 -0
- package/dist/src/util/animation/ArrayAnimation.d.ts +10 -0
- package/dist/src/util/animation/ColorAnimation.d.ts +11 -0
- package/dist/src/util/animation/ValueAnimation.d.ts +10 -0
- package/dist/src/util/animation/animate.d.ts +37 -0
- package/dist/src/util/animation/easing.d.ts +130 -0
- package/dist/src/util/animation/types.d.ts +87 -0
- package/dist/src/util/applyMixins.d.ts +8 -0
- package/dist/src/util/class_registry.d.ts +14 -0
- package/dist/src/util/dom_event.d.ts +5 -0
- package/dist/src/util/dom_misc.d.ts +40 -0
- package/dist/src/util/dom_request.d.ts +14 -0
- package/dist/src/util/dom_style.d.ts +7 -0
- package/dist/src/util/fireEvent.d.ts +3 -0
- package/dist/src/util/internals/cloneDeep.d.ts +2 -0
- package/dist/src/util/internals/getRandomInt.d.ts +8 -0
- package/dist/src/util/internals/ifNaN.d.ts +8 -0
- package/dist/src/util/internals/index.d.ts +4 -0
- package/dist/src/util/internals/removeFromArray.d.ts +9 -0
- package/dist/src/util/internals/uid.d.ts +2 -0
- package/dist/src/util/lang_class.d.ts +12 -0
- package/dist/src/util/lang_string.d.ts +22 -0
- package/dist/src/util/misc/boundingBoxFromPoints.d.ts +9 -0
- package/dist/src/util/misc/capValue.d.ts +2 -0
- package/dist/src/util/misc/cos.d.ts +10 -0
- package/dist/src/util/misc/dom.d.ts +28 -0
- package/dist/src/util/misc/findScaleTo.d.ts +29 -0
- package/dist/src/util/misc/groupSVGElements.d.ts +9 -0
- package/dist/src/util/misc/isTransparent.d.ts +11 -0
- package/dist/src/util/misc/matrix.d.ts +92 -0
- package/dist/src/util/misc/mergeClipPaths.d.ts +23 -0
- package/dist/src/util/misc/objectEnlive.d.ts +56 -0
- package/dist/src/util/misc/objectTransforms.d.ts +68 -0
- package/dist/src/util/misc/pick.d.ts +8 -0
- package/dist/src/util/misc/planeChange.d.ts +84 -0
- package/dist/src/util/misc/projectStroke/StrokeLineCapProjections.d.ts +51 -0
- package/dist/src/util/misc/projectStroke/StrokeLineJoinProjections.d.ts +81 -0
- package/dist/src/util/misc/projectStroke/StrokeProjectionsBase.d.ts +25 -0
- package/dist/src/util/misc/projectStroke/index.d.ts +11 -0
- package/dist/src/util/misc/projectStroke/types.d.ts +23 -0
- package/dist/src/util/misc/radiansDegreesConversion.d.ts +14 -0
- package/dist/src/util/misc/resolveOrigin.d.ts +9 -0
- package/dist/src/util/misc/rotatePoint.d.ts +12 -0
- package/dist/src/util/misc/sin.d.ts +10 -0
- package/dist/src/util/misc/svgParsing.d.ts +53 -0
- package/dist/src/util/misc/textStyles.d.ts +32 -0
- package/dist/src/util/misc/toFixed.d.ts +8 -0
- package/dist/src/util/misc/vectors.d.ts +57 -0
- package/dist/src/util/path.d.ts +108 -0
- package/dist/src/util/transform_matrix_removal.d.ts +14 -0
- package/dist/src/util/types.d.ts +19 -0
- package/fabric.ts +427 -0
- package/index.node.ts +43 -0
- package/index.ts +1 -0
- package/package.json +90 -39
- package/publish.js +0 -26
- package/rollup.config.mjs +79 -0
- package/rollup.test.config.js +24 -0
- package/scripts/build.mjs +50 -0
- package/scripts/buildLock.mjs +115 -0
- package/scripts/buildReporter.mjs +15 -0
- package/scripts/buildStats.mjs +139 -0
- package/scripts/dirname.mjs +14 -0
- package/scripts/index.mjs +679 -0
- package/scripts/transform_files.mjs +504 -0
- package/src/Collection.ts +311 -0
- package/src/CommonMethods.ts +63 -0
- package/src/EventTypeDefs.ts +294 -0
- package/src/Intersection.ts +273 -0
- package/src/Observable.ts +175 -0
- package/src/Pattern.ts +211 -0
- package/src/Point.ts +388 -0
- package/src/Shadow.ts +215 -0
- package/src/brushes/{base_brush.class.js → BaseBrush.ts} +65 -42
- package/src/brushes/CircleBrush.ts +145 -0
- package/src/brushes/PatternBrush.ts +70 -0
- package/src/brushes/PencilBrush.ts +300 -0
- package/src/brushes/SprayBrush.ts +219 -0
- package/src/cache.ts +89 -0
- package/src/canvas/Canvas.ts +1672 -0
- package/src/canvas/SelectableCanvas.ts +1636 -0
- package/src/canvas/StaticCanvas.ts +1709 -0
- package/src/canvas/TextEditingManager.ts +48 -0
- package/src/canvas/canvas_gestures.mixin.ts +207 -0
- package/src/color/Color.ts +404 -0
- package/src/color/color_map.ts +154 -0
- package/src/color/constants.ts +26 -0
- package/src/color/util.ts +32 -0
- package/src/config.ts +159 -0
- package/src/constants.ts +19 -0
- package/src/controls/Control.ts +377 -0
- package/src/controls/changeWidth.ts +52 -0
- package/src/controls/controls.render.ts +138 -0
- package/src/controls/default_controls.ts +132 -0
- package/src/controls/drag.ts +31 -0
- package/src/controls/polyControl.ts +135 -0
- package/src/controls/rotate.ts +87 -0
- package/src/controls/scale.ts +277 -0
- package/src/controls/scaleSkew.ts +92 -0
- package/src/controls/skew.ts +242 -0
- package/src/controls/util.ts +154 -0
- package/src/controls/wrapWithFireEvent.ts +25 -0
- package/src/controls/wrapWithFixedAnchor.ts +20 -0
- package/src/env/browser.ts +28 -0
- package/src/env/index.ts +19 -0
- package/src/env/node.ts +52 -0
- package/src/env/types.ts +15 -0
- package/src/filters/{base_filter.class.js → BaseFilter.ts} +201 -149
- package/src/filters/BlendColor.ts +258 -0
- package/src/filters/BlendImage.ts +254 -0
- package/src/filters/Blur.ts +202 -0
- package/src/filters/Boilerplate.ts +91 -0
- package/src/filters/Brightness.ts +93 -0
- package/src/filters/Canvas2dFilterBackend.ts +65 -0
- package/src/filters/ColorMatrix.ts +156 -0
- package/src/filters/ColorMatrixFilters.ts +106 -0
- package/src/filters/Composed.ts +85 -0
- package/src/filters/Contrast.ts +94 -0
- package/src/filters/Convolute.ts +341 -0
- package/src/filters/FilterBackend.ts +32 -0
- package/src/filters/Gamma.ts +127 -0
- package/src/filters/Grayscale.ts +137 -0
- package/src/filters/HueRotation.ts +66 -0
- package/src/filters/Invert.ts +117 -0
- package/src/filters/Noise.ts +109 -0
- package/src/filters/Pixelate.ts +114 -0
- package/src/filters/RemoveColor.ts +148 -0
- package/src/filters/Resize.ts +540 -0
- package/src/filters/Saturation.ts +100 -0
- package/src/filters/Vibrance.ts +103 -0
- package/src/filters/WebGLFilterBackend.ts +430 -0
- package/src/filters/WebGLProbe.ts +62 -0
- package/src/filters/typedefs.ts +65 -0
- package/src/gradient/Gradient.ts +401 -0
- package/src/gradient/constants.ts +12 -0
- package/src/gradient/parser/index.ts +3 -0
- package/src/gradient/parser/misc.ts +13 -0
- package/src/gradient/parser/parseColorStops.ts +55 -0
- package/src/gradient/parser/parseCoords.ts +73 -0
- package/src/gradient/typedefs.ts +104 -0
- package/src/mixins/{eraser_brush.mixin.js → eraser_brush.mixin.ts} +350 -239
- package/src/mixins/stateful.mixin.ts +104 -0
- package/src/parkinglot/canvas_animation.mixin.ts +121 -0
- package/src/parkinglot/straighten.ts +58 -0
- package/src/parser/applyViewboxTransform.ts +162 -0
- package/src/parser/attributes.ts +25 -0
- package/src/parser/constants.ts +118 -0
- package/src/parser/doesSomeParentMatch.ts +19 -0
- package/src/parser/elementById.ts +23 -0
- package/src/parser/elementMatchesRule.ts +19 -0
- package/src/parser/elements_parser.ts +191 -0
- package/src/parser/getCSSRules.ts +62 -0
- package/src/parser/getGlobalStylesForElement.ts +19 -0
- package/src/parser/getGradientDefs.ts +32 -0
- package/src/parser/getMultipleNodes.ts +15 -0
- package/src/parser/getSvgRegex.ts +5 -0
- package/src/parser/hasAncestorWithNodeName.ts +14 -0
- package/src/parser/loadSVGFromString.ts +26 -0
- package/src/parser/loadSVGFromURL.ts +40 -0
- package/src/parser/normalizeAttr.ts +10 -0
- package/src/parser/normalizeValue.ts +63 -0
- package/src/parser/parseAttributes.ts +90 -0
- package/src/parser/parseElements.ts +28 -0
- package/src/parser/parseFontDeclaration.ts +44 -0
- package/src/parser/parsePointsAttribute.ts +36 -0
- package/src/parser/parseSVGDocument.ts +106 -0
- package/src/parser/parseStyleAttribute.ts +27 -0
- package/src/parser/parseStyleObject.ts +15 -0
- package/src/parser/parseStyleString.ts +16 -0
- package/src/parser/parseTransformAttribute.ts +155 -0
- package/src/parser/parseUseDirectives.ts +79 -0
- package/src/parser/percent.ts +27 -0
- package/src/parser/recursivelyParseGradientsXlink.ts +42 -0
- package/src/parser/rotateMatrix.ts +21 -0
- package/src/parser/scaleMatrix.ts +9 -0
- package/src/parser/selectorMatches.ts +25 -0
- package/src/parser/setStrokeFillOpacity.ts +40 -0
- package/src/parser/skewMatrix.ts +6 -0
- package/src/parser/translateMatrix.ts +8 -0
- package/src/shapes/ActiveSelection.ts +157 -0
- package/src/shapes/Circle.ts +205 -0
- package/src/shapes/Ellipse.ts +154 -0
- package/src/shapes/Group.ts +1053 -0
- package/src/shapes/IText/DraggableTextDelegate.ts +394 -0
- package/src/shapes/IText/IText.ts +666 -0
- package/src/shapes/IText/ITextBehavior.ts +1055 -0
- package/src/shapes/IText/ITextClickBehavior.ts +321 -0
- package/src/shapes/IText/ITextKeyBehavior.ts +683 -0
- package/src/shapes/IText/constants.ts +47 -0
- package/src/shapes/Image.ts +789 -0
- package/src/shapes/Line.ts +329 -0
- package/src/shapes/Object/AnimatableObject.ts +106 -0
- package/src/shapes/Object/FabricObject.ts +19 -0
- package/src/shapes/Object/FabricObjectSVGExportMixin.ts +277 -0
- package/src/shapes/Object/InteractiveObject.ts +645 -0
- package/src/shapes/Object/Object.ts +1896 -0
- package/src/shapes/Object/ObjectGeometry.ts +830 -0
- package/src/shapes/Object/ObjectOrigin.ts +354 -0
- package/src/shapes/Object/StackedObject.ts +191 -0
- package/src/shapes/Object/defaultValues.ts +112 -0
- package/src/shapes/Path.ts +395 -0
- package/src/shapes/Polygon.ts +19 -0
- package/src/shapes/Polyline.ts +333 -0
- package/src/shapes/Rect.ts +199 -0
- package/src/shapes/Text/StyledText.ts +319 -0
- package/src/shapes/Text/Text.ts +1948 -0
- package/src/shapes/Text/TextSVGExportMixin.ts +288 -0
- package/src/shapes/Textbox.ts +471 -0
- package/src/shapes/Triangle.ts +45 -0
- package/src/typedefs.ts +119 -0
- package/src/util/animation/AnimationBase.ts +166 -0
- package/src/util/animation/AnimationFrameProvider.ts +28 -0
- package/src/util/animation/AnimationRegistry.ts +58 -0
- package/src/util/animation/ArrayAnimation.ts +27 -0
- package/src/util/animation/ColorAnimation.ts +74 -0
- package/src/util/animation/ValueAnimation.ts +29 -0
- package/src/util/animation/animate.ts +74 -0
- package/src/util/animation/easing.ts +327 -0
- package/src/util/animation/types.ts +136 -0
- package/src/util/applyMixins.ts +22 -0
- package/src/util/class_registry.ts +54 -0
- package/src/util/dom_event.ts +28 -0
- package/src/util/dom_misc.ts +138 -0
- package/src/util/dom_request.ts +64 -0
- package/src/util/dom_style.ts +20 -0
- package/src/util/fireEvent.ts +15 -0
- package/src/util/internals/cloneDeep.ts +2 -0
- package/src/util/internals/getRandomInt.ts +8 -0
- package/src/util/internals/ifNaN.ts +9 -0
- package/src/util/internals/index.ts +3 -0
- package/src/util/internals/removeFromArray.ts +14 -0
- package/src/util/internals/uid.ts +3 -0
- package/src/util/lang_class.ts +90 -0
- package/src/util/lang_string.ts +79 -0
- package/src/util/misc/boundingBoxFromPoints.ts +37 -0
- package/src/util/misc/capValue.ts +2 -0
- package/src/util/misc/cos.ts +24 -0
- package/src/util/misc/dom.ts +50 -0
- package/src/util/misc/findScaleTo.ts +44 -0
- package/src/util/misc/groupSVGElements.ts +15 -0
- package/src/util/misc/isTransparent.ts +51 -0
- package/src/util/misc/matrix.ts +207 -0
- package/src/util/misc/mergeClipPaths.ts +40 -0
- package/src/util/misc/objectEnlive.ts +189 -0
- package/src/util/misc/objectTransforms.ts +129 -0
- package/src/util/misc/pick.ts +17 -0
- package/src/util/misc/planeChange.ts +136 -0
- package/src/util/misc/projectStroke/StrokeLineCapProjections.ts +112 -0
- package/src/util/misc/projectStroke/StrokeLineJoinProjections.ts +231 -0
- package/src/util/misc/projectStroke/StrokeProjectionsBase.ts +75 -0
- package/src/util/misc/projectStroke/index.ts +53 -0
- package/src/util/misc/projectStroke/types.ts +24 -0
- package/src/util/misc/radiansDegreesConversion.ts +18 -0
- package/src/util/misc/resolveOrigin.ts +22 -0
- package/src/util/misc/rotatePoint.ts +15 -0
- package/src/util/misc/sin.ts +26 -0
- package/src/util/misc/svgParsing.ts +181 -0
- package/src/util/misc/textStyles.ts +133 -0
- package/src/util/misc/toFixed.ts +8 -0
- package/src/util/misc/vectors.ts +82 -0
- package/src/util/path.ts +941 -0
- package/src/util/transform_matrix_removal.ts +60 -0
- package/src/util/types.ts +78 -0
- package/tsconfig.json +106 -0
- package/HEADER.js +0 -203
- package/build.js +0 -287
- package/dist/fabric.js +0 -31187
- package/dist/fabric.min.js +0 -1
- package/old-travis-reference.yml +0 -97
- package/src/brushes/circle_brush.class.js +0 -144
- package/src/brushes/pattern_brush.class.js +0 -61
- package/src/brushes/pencil_brush.class.js +0 -310
- package/src/brushes/spray_brush.class.js +0 -219
- package/src/canvas.class.js +0 -1312
- package/src/color.class.js +0 -636
- package/src/control.class.js +0 -339
- package/src/controls.actions.js +0 -740
- package/src/controls.render.js +0 -99
- package/src/elements_parser.js +0 -152
- package/src/filters/2d_backend.class.js +0 -65
- package/src/filters/blendcolor_filter.class.js +0 -251
- package/src/filters/blendimage_filter.class.js +0 -247
- package/src/filters/blur_filter.class.js +0 -217
- package/src/filters/brightness_filter.class.js +0 -113
- package/src/filters/colormatrix_filter.class.js +0 -159
- package/src/filters/composed_filter.class.js +0 -72
- package/src/filters/contrast_filter.class.js +0 -113
- package/src/filters/convolute_filter.class.js +0 -352
- package/src/filters/filter_boilerplate.js +0 -111
- package/src/filters/filter_generator.js +0 -85
- package/src/filters/gamma_filter.class.js +0 -136
- package/src/filters/grayscale_filter.class.js +0 -154
- package/src/filters/hue_rotation.class.js +0 -107
- package/src/filters/invert_filter.class.js +0 -111
- package/src/filters/noise_filter.class.js +0 -134
- package/src/filters/pixelate_filter.class.js +0 -137
- package/src/filters/removecolor_filter.class.js +0 -173
- package/src/filters/resize_filter.class.js +0 -490
- package/src/filters/saturate_filter.class.js +0 -119
- package/src/filters/vibrance_filter.class.js +0 -122
- package/src/filters/webgl_backend.class.js +0 -396
- package/src/globalFabric.js +0 -4
- package/src/gradient.class.js +0 -490
- package/src/intersection.class.js +0 -172
- package/src/log.js +0 -11
- package/src/mixins/animation.mixin.js +0 -231
- package/src/mixins/canvas_dataurl_exporter.mixin.js +0 -97
- package/src/mixins/canvas_events.mixin.js +0 -974
- package/src/mixins/canvas_gestures.mixin.js +0 -149
- package/src/mixins/canvas_grouping.mixin.js +0 -177
- package/src/mixins/canvas_serialization.mixin.js +0 -228
- package/src/mixins/collection.mixin.js +0 -170
- package/src/mixins/default_controls.js +0 -114
- package/src/mixins/itext.svg_export.js +0 -241
- package/src/mixins/itext_behavior.mixin.js +0 -940
- package/src/mixins/itext_click_behavior.mixin.js +0 -278
- package/src/mixins/itext_key_behavior.mixin.js +0 -694
- package/src/mixins/object.svg_export.js +0 -258
- package/src/mixins/object_geometry.mixin.js +0 -683
- package/src/mixins/object_interactivity.mixin.js +0 -314
- package/src/mixins/object_origin.mixin.js +0 -255
- package/src/mixins/object_stacking.mixin.js +0 -80
- package/src/mixins/object_straightening.mixin.js +0 -80
- package/src/mixins/observable.mixin.js +0 -141
- package/src/mixins/shared_methods.mixin.js +0 -94
- package/src/mixins/stateful.mixin.js +0 -107
- package/src/mixins/text_style.mixin.js +0 -324
- package/src/parser.js +0 -1090
- package/src/pattern.class.js +0 -189
- package/src/point.class.js +0 -337
- package/src/shadow.class.js +0 -195
- package/src/shapes/active_selection.class.js +0 -155
- package/src/shapes/circle.class.js +0 -210
- package/src/shapes/ellipse.class.js +0 -181
- package/src/shapes/group.class.js +0 -593
- package/src/shapes/image.class.js +0 -764
- package/src/shapes/itext.class.js +0 -526
- package/src/shapes/line.class.js +0 -324
- package/src/shapes/object.class.js +0 -2008
- package/src/shapes/path.class.js +0 -384
- package/src/shapes/polygon.class.js +0 -81
- package/src/shapes/polyline.class.js +0 -268
- package/src/shapes/rect.class.js +0 -187
- package/src/shapes/text.class.js +0 -1696
- package/src/shapes/textbox.class.js +0 -461
- package/src/shapes/triangle.class.js +0 -93
- package/src/static_canvas.class.js +0 -1881
- package/src/util/anim_ease.js +0 -398
- package/src/util/animate.js +0 -254
- package/src/util/animate_color.js +0 -74
- package/src/util/dom_event.js +0 -50
- package/src/util/dom_misc.js +0 -300
- package/src/util/dom_request.js +0 -54
- package/src/util/dom_style.js +0 -70
- package/src/util/lang_array.js +0 -94
- package/src/util/lang_class.js +0 -115
- package/src/util/lang_object.js +0 -75
- package/src/util/lang_string.js +0 -110
- package/src/util/misc.js +0 -1330
- package/src/util/named_accessors.mixin.js +0 -428
- package/src/util/path.js +0 -829
|
@@ -0,0 +1,1672 @@
|
|
|
1
|
+
import { LEFT_CLICK, MIDDLE_CLICK, RIGHT_CLICK } from '../constants';
|
|
2
|
+
import { getEnv } from '../env';
|
|
3
|
+
import {
|
|
4
|
+
CanvasEvents,
|
|
5
|
+
DragEventData,
|
|
6
|
+
ObjectEvents,
|
|
7
|
+
TPointerEvent,
|
|
8
|
+
TPointerEventInfo,
|
|
9
|
+
TPointerEventNames,
|
|
10
|
+
Transform,
|
|
11
|
+
} from '../EventTypeDefs';
|
|
12
|
+
import { Point } from '../Point';
|
|
13
|
+
import { ActiveSelection } from '../shapes/ActiveSelection';
|
|
14
|
+
import { Group } from '../shapes/Group';
|
|
15
|
+
import type { FabricObject } from '../shapes/Object/FabricObject';
|
|
16
|
+
import { AssertKeys } from '../typedefs';
|
|
17
|
+
import { isTouchEvent, stopEvent } from '../util/dom_event';
|
|
18
|
+
import { createCanvasElement } from '../util/misc/dom';
|
|
19
|
+
import { sendPointToPlane } from '../util/misc/planeChange';
|
|
20
|
+
import {
|
|
21
|
+
isActiveSelection,
|
|
22
|
+
isFabricObjectWithDragSupport,
|
|
23
|
+
isInteractiveTextObject,
|
|
24
|
+
} from '../util/types';
|
|
25
|
+
import { SelectableCanvas } from './SelectableCanvas';
|
|
26
|
+
import { TextEditingManager } from './TextEditingManager';
|
|
27
|
+
|
|
28
|
+
const addEventOptions = { passive: false } as EventListenerOptions;
|
|
29
|
+
|
|
30
|
+
function checkClick(e: TPointerEvent, value: number) {
|
|
31
|
+
return !!(e as MouseEvent).button && (e as MouseEvent).button === value - 1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// just to be clear, the utils are now deprecated and those are here exactly as minifier helpers
|
|
35
|
+
// because el.addEventListener can't me be minified while a const yes and we use it 47 times in this file.
|
|
36
|
+
// few bytes but why give it away.
|
|
37
|
+
const addListener = (
|
|
38
|
+
el: HTMLElement | Document,
|
|
39
|
+
...args: Parameters<HTMLElement['addEventListener']>
|
|
40
|
+
) => el.addEventListener(...args);
|
|
41
|
+
const removeListener = (
|
|
42
|
+
el: HTMLElement | Document,
|
|
43
|
+
...args: Parameters<HTMLElement['removeEventListener']>
|
|
44
|
+
) => el.removeEventListener(...args);
|
|
45
|
+
|
|
46
|
+
const syntheticEventConfig = {
|
|
47
|
+
mouse: {
|
|
48
|
+
in: 'over',
|
|
49
|
+
out: 'out',
|
|
50
|
+
targetIn: 'mouseover',
|
|
51
|
+
targetOut: 'mouseout',
|
|
52
|
+
canvasIn: 'mouse:over',
|
|
53
|
+
canvasOut: 'mouse:out',
|
|
54
|
+
},
|
|
55
|
+
drag: {
|
|
56
|
+
in: 'enter',
|
|
57
|
+
out: 'leave',
|
|
58
|
+
targetIn: 'dragenter',
|
|
59
|
+
targetOut: 'dragleave',
|
|
60
|
+
canvasIn: 'drag:enter',
|
|
61
|
+
canvasOut: 'drag:leave',
|
|
62
|
+
},
|
|
63
|
+
} as const;
|
|
64
|
+
|
|
65
|
+
type TSyntheticEventContext = {
|
|
66
|
+
mouse: { e: TPointerEvent };
|
|
67
|
+
drag: DragEventData;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export class Canvas extends SelectableCanvas {
|
|
71
|
+
/**
|
|
72
|
+
* Contains the id of the touch event that owns the fabric transform
|
|
73
|
+
* @type Number
|
|
74
|
+
* @private
|
|
75
|
+
*/
|
|
76
|
+
declare mainTouchId: null | number;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* When the option is enabled, PointerEvent is used instead of TPointerEvent.
|
|
80
|
+
* @type Boolean
|
|
81
|
+
* @default
|
|
82
|
+
*/
|
|
83
|
+
declare enablePointerEvents: boolean;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Holds a reference to a setTimeout timer for event synchronization
|
|
87
|
+
* @type number
|
|
88
|
+
* @private
|
|
89
|
+
*/
|
|
90
|
+
private declare _willAddMouseDown: number;
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Holds a reference to an object on the canvas that is receiving the drag over event.
|
|
94
|
+
* @type FabricObject
|
|
95
|
+
* @private
|
|
96
|
+
*/
|
|
97
|
+
private declare _draggedoverTarget?: FabricObject;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Holds a reference to an object on the canvas from where the drag operation started
|
|
101
|
+
* @type FabricObject
|
|
102
|
+
* @private
|
|
103
|
+
*/
|
|
104
|
+
private declare _dragSource?: FabricObject;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Holds a reference to an object on the canvas that is the current drop target
|
|
108
|
+
* May differ from {@link _draggedoverTarget}
|
|
109
|
+
* @todo inspect whether {@link _draggedoverTarget} and {@link _dropTarget} should be merged somehow
|
|
110
|
+
* @type FabricObject
|
|
111
|
+
* @private
|
|
112
|
+
*/
|
|
113
|
+
private declare _dropTarget: FabricObject<ObjectEvents> | undefined;
|
|
114
|
+
|
|
115
|
+
declare currentTarget?: FabricObject;
|
|
116
|
+
|
|
117
|
+
declare currentSubTargets?: FabricObject[];
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Holds a reference to a pointer during mousedown to compare on mouse up and determine
|
|
121
|
+
* if it was a click event
|
|
122
|
+
* @type FabricObject
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
declare _previousPointer: Point;
|
|
126
|
+
|
|
127
|
+
private _isClick: boolean;
|
|
128
|
+
|
|
129
|
+
textEditingManager = new TextEditingManager();
|
|
130
|
+
|
|
131
|
+
constructor(el: string | HTMLCanvasElement, options = {}) {
|
|
132
|
+
super(el, options);
|
|
133
|
+
// bind event handlers
|
|
134
|
+
(
|
|
135
|
+
[
|
|
136
|
+
'_onMouseDown',
|
|
137
|
+
'_onTouchStart',
|
|
138
|
+
'_onMouseMove',
|
|
139
|
+
'_onMouseUp',
|
|
140
|
+
'_onTouchEnd',
|
|
141
|
+
'_onResize',
|
|
142
|
+
// '_onGesture',
|
|
143
|
+
// '_onDrag',
|
|
144
|
+
// '_onShake',
|
|
145
|
+
// '_onLongPress',
|
|
146
|
+
// '_onOrientationChange',
|
|
147
|
+
'_onMouseWheel',
|
|
148
|
+
'_onMouseOut',
|
|
149
|
+
'_onMouseEnter',
|
|
150
|
+
'_onContextMenu',
|
|
151
|
+
'_onDoubleClick',
|
|
152
|
+
'_onDragStart',
|
|
153
|
+
'_onDragEnd',
|
|
154
|
+
'_onDragProgress',
|
|
155
|
+
'_onDragOver',
|
|
156
|
+
'_onDragEnter',
|
|
157
|
+
'_onDragLeave',
|
|
158
|
+
'_onDrop',
|
|
159
|
+
] as (keyof this)[]
|
|
160
|
+
).forEach((eventHandler) => {
|
|
161
|
+
this[eventHandler] = (this[eventHandler] as Function).bind(this);
|
|
162
|
+
});
|
|
163
|
+
// register event handlers
|
|
164
|
+
this.addOrRemove(addListener, 'add');
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* return an event prefix pointer or mouse.
|
|
169
|
+
* @private
|
|
170
|
+
*/
|
|
171
|
+
private _getEventPrefix() {
|
|
172
|
+
return this.enablePointerEvents ? 'pointer' : 'mouse';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
addOrRemove(functor: any, eventjsFunctor: 'add' | 'remove') {
|
|
176
|
+
const canvasElement = this.upperCanvasEl,
|
|
177
|
+
eventTypePrefix = this._getEventPrefix();
|
|
178
|
+
functor(getEnv().window, 'resize', this._onResize);
|
|
179
|
+
functor(canvasElement, eventTypePrefix + 'down', this._onMouseDown);
|
|
180
|
+
functor(
|
|
181
|
+
canvasElement,
|
|
182
|
+
`${eventTypePrefix}move`,
|
|
183
|
+
this._onMouseMove,
|
|
184
|
+
addEventOptions
|
|
185
|
+
);
|
|
186
|
+
functor(canvasElement, `${eventTypePrefix}out`, this._onMouseOut);
|
|
187
|
+
functor(canvasElement, `${eventTypePrefix}enter`, this._onMouseEnter);
|
|
188
|
+
functor(canvasElement, 'wheel', this._onMouseWheel);
|
|
189
|
+
functor(canvasElement, 'contextmenu', this._onContextMenu);
|
|
190
|
+
functor(canvasElement, 'dblclick', this._onDoubleClick);
|
|
191
|
+
functor(canvasElement, 'dragstart', this._onDragStart);
|
|
192
|
+
functor(canvasElement, 'dragend', this._onDragEnd);
|
|
193
|
+
functor(canvasElement, 'dragover', this._onDragOver);
|
|
194
|
+
functor(canvasElement, 'dragenter', this._onDragEnter);
|
|
195
|
+
functor(canvasElement, 'dragleave', this._onDragLeave);
|
|
196
|
+
functor(canvasElement, 'drop', this._onDrop);
|
|
197
|
+
if (!this.enablePointerEvents) {
|
|
198
|
+
functor(canvasElement, 'touchstart', this._onTouchStart, addEventOptions);
|
|
199
|
+
}
|
|
200
|
+
// if (typeof eventjs !== 'undefined' && eventjsFunctor in eventjs) {
|
|
201
|
+
// eventjs[eventjsFunctor](canvasElement, 'gesture', this._onGesture);
|
|
202
|
+
// eventjs[eventjsFunctor](canvasElement, 'drag', this._onDrag);
|
|
203
|
+
// eventjs[eventjsFunctor](
|
|
204
|
+
// canvasElement,
|
|
205
|
+
// 'orientation',
|
|
206
|
+
// this._onOrientationChange
|
|
207
|
+
// );
|
|
208
|
+
// eventjs[eventjsFunctor](canvasElement, 'shake', this._onShake);
|
|
209
|
+
// eventjs[eventjsFunctor](canvasElement, 'longpress', this._onLongPress);
|
|
210
|
+
// }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Removes all event listeners
|
|
215
|
+
*/
|
|
216
|
+
removeListeners() {
|
|
217
|
+
this.addOrRemove(removeListener, 'remove');
|
|
218
|
+
// if you dispose on a mouseDown, before mouse up, you need to clean document to...
|
|
219
|
+
const eventTypePrefix = this._getEventPrefix();
|
|
220
|
+
removeListener(
|
|
221
|
+
getEnv().document,
|
|
222
|
+
`${eventTypePrefix}up`,
|
|
223
|
+
this._onMouseUp as EventListener
|
|
224
|
+
);
|
|
225
|
+
removeListener(
|
|
226
|
+
getEnv().document,
|
|
227
|
+
'touchend',
|
|
228
|
+
this._onTouchEnd as EventListener,
|
|
229
|
+
addEventOptions
|
|
230
|
+
);
|
|
231
|
+
removeListener(
|
|
232
|
+
getEnv().document,
|
|
233
|
+
`${eventTypePrefix}move`,
|
|
234
|
+
this._onMouseMove as EventListener,
|
|
235
|
+
addEventOptions
|
|
236
|
+
);
|
|
237
|
+
removeListener(
|
|
238
|
+
getEnv().document,
|
|
239
|
+
'touchmove',
|
|
240
|
+
this._onMouseMove as EventListener,
|
|
241
|
+
addEventOptions
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* @private
|
|
247
|
+
* @param {Event} [e] Event object fired on wheel event
|
|
248
|
+
*/
|
|
249
|
+
private _onMouseWheel(e: MouseEvent) {
|
|
250
|
+
this.__onMouseWheel(e);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* @private
|
|
255
|
+
* @param {Event} e Event object fired on mousedown
|
|
256
|
+
*/
|
|
257
|
+
private _onMouseOut(e: TPointerEvent) {
|
|
258
|
+
const target = this._hoveredTarget;
|
|
259
|
+
const shared = {
|
|
260
|
+
e,
|
|
261
|
+
isClick: false,
|
|
262
|
+
pointer: this.getPointer(e),
|
|
263
|
+
absolutePointer: this.getPointer(e, true),
|
|
264
|
+
};
|
|
265
|
+
this.fire('mouse:out', { ...shared, target });
|
|
266
|
+
this._hoveredTarget = undefined;
|
|
267
|
+
target && target.fire('mouseout', { ...shared });
|
|
268
|
+
this._hoveredTargets.forEach((nestedTarget) => {
|
|
269
|
+
this.fire('mouse:out', { ...shared, target: nestedTarget });
|
|
270
|
+
nestedTarget && nestedTarget.fire('mouseout', { ...shared });
|
|
271
|
+
});
|
|
272
|
+
this._hoveredTargets = [];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* @private
|
|
277
|
+
* @param {Event} e Event object fired on mouseenter
|
|
278
|
+
*/
|
|
279
|
+
private _onMouseEnter(e: TPointerEvent) {
|
|
280
|
+
// This find target and consequent 'mouse:over' is used to
|
|
281
|
+
// clear old instances on hovered target.
|
|
282
|
+
// calling findTarget has the side effect of killing target.__corner.
|
|
283
|
+
// as a short term fix we are not firing this if we are currently transforming.
|
|
284
|
+
// as a long term fix we need to separate the action of finding a target with the
|
|
285
|
+
// side effects we added to it.
|
|
286
|
+
if (!this._currentTransform && !this.findTarget(e)) {
|
|
287
|
+
this.fire('mouse:over', {
|
|
288
|
+
e,
|
|
289
|
+
isClick: false,
|
|
290
|
+
pointer: this.getPointer(e),
|
|
291
|
+
absolutePointer: this.getPointer(e, true),
|
|
292
|
+
});
|
|
293
|
+
this._hoveredTarget = undefined;
|
|
294
|
+
this._hoveredTargets = [];
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* supports native like text dragging
|
|
300
|
+
* @private
|
|
301
|
+
* @param {DragEvent} e
|
|
302
|
+
*/
|
|
303
|
+
private _onDragStart(e: DragEvent) {
|
|
304
|
+
this._isClick = false;
|
|
305
|
+
const activeObject = this.getActiveObject();
|
|
306
|
+
if (
|
|
307
|
+
isFabricObjectWithDragSupport(activeObject) &&
|
|
308
|
+
activeObject.onDragStart(e)
|
|
309
|
+
) {
|
|
310
|
+
this._dragSource = activeObject;
|
|
311
|
+
const options = { e, target: activeObject };
|
|
312
|
+
this.fire('dragstart', options);
|
|
313
|
+
activeObject.fire('dragstart', options);
|
|
314
|
+
addListener(
|
|
315
|
+
this.upperCanvasEl,
|
|
316
|
+
'drag',
|
|
317
|
+
this._onDragProgress as EventListener
|
|
318
|
+
);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
stopEvent(e);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* First we clear top context where the effects are being rendered.
|
|
326
|
+
* Then we render the effects.
|
|
327
|
+
* Doing so will render the correct effect for all cases including an overlap between `source` and `target`.
|
|
328
|
+
* @private
|
|
329
|
+
*/
|
|
330
|
+
private _renderDragEffects(
|
|
331
|
+
e: DragEvent,
|
|
332
|
+
source?: FabricObject,
|
|
333
|
+
target?: FabricObject
|
|
334
|
+
) {
|
|
335
|
+
let dirty = false;
|
|
336
|
+
// clear top context
|
|
337
|
+
const dropTarget = this._dropTarget;
|
|
338
|
+
if (dropTarget && dropTarget !== source && dropTarget !== target) {
|
|
339
|
+
dropTarget.clearContextTop();
|
|
340
|
+
dirty = true;
|
|
341
|
+
}
|
|
342
|
+
source?.clearContextTop();
|
|
343
|
+
target !== source && target?.clearContextTop();
|
|
344
|
+
// render effects
|
|
345
|
+
const ctx = this.contextTop;
|
|
346
|
+
ctx.save();
|
|
347
|
+
ctx.transform(...this.viewportTransform);
|
|
348
|
+
if (source) {
|
|
349
|
+
ctx.save();
|
|
350
|
+
source.transform(ctx);
|
|
351
|
+
(source as AssertKeys<FabricObject, 'canvas'>).renderDragSourceEffect(e);
|
|
352
|
+
ctx.restore();
|
|
353
|
+
dirty = true;
|
|
354
|
+
}
|
|
355
|
+
if (target) {
|
|
356
|
+
ctx.save();
|
|
357
|
+
target.transform(ctx);
|
|
358
|
+
(target as AssertKeys<FabricObject, 'canvas'>).renderDropTargetEffect(e);
|
|
359
|
+
ctx.restore();
|
|
360
|
+
dirty = true;
|
|
361
|
+
}
|
|
362
|
+
ctx.restore();
|
|
363
|
+
dirty && (this.contextTopDirty = true);
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* supports native like text dragging
|
|
368
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#finishing_a_drag
|
|
369
|
+
* @private
|
|
370
|
+
* @param {DragEvent} e
|
|
371
|
+
*/
|
|
372
|
+
private _onDragEnd(e: DragEvent) {
|
|
373
|
+
const didDrop = !!e.dataTransfer && e.dataTransfer.dropEffect !== 'none',
|
|
374
|
+
dropTarget = didDrop ? this._activeObject : undefined,
|
|
375
|
+
options = {
|
|
376
|
+
e,
|
|
377
|
+
target: this._dragSource as FabricObject,
|
|
378
|
+
subTargets: this.targets,
|
|
379
|
+
dragSource: this._dragSource as FabricObject,
|
|
380
|
+
didDrop,
|
|
381
|
+
dropTarget: dropTarget as FabricObject,
|
|
382
|
+
};
|
|
383
|
+
removeListener(
|
|
384
|
+
this.upperCanvasEl,
|
|
385
|
+
'drag',
|
|
386
|
+
this._onDragProgress as EventListener
|
|
387
|
+
);
|
|
388
|
+
this.fire('dragend', options);
|
|
389
|
+
this._dragSource && this._dragSource.fire('dragend', options);
|
|
390
|
+
delete this._dragSource;
|
|
391
|
+
// we need to call mouse up synthetically because the browser won't
|
|
392
|
+
this._onMouseUp(e);
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* fire `drag` event on canvas and drag source
|
|
397
|
+
* @private
|
|
398
|
+
* @param {DragEvent} e
|
|
399
|
+
*/
|
|
400
|
+
private _onDragProgress(e: DragEvent) {
|
|
401
|
+
const options = {
|
|
402
|
+
e,
|
|
403
|
+
target: this._dragSource as FabricObject | undefined,
|
|
404
|
+
dragSource: this._dragSource as FabricObject | undefined,
|
|
405
|
+
dropTarget: this._draggedoverTarget as FabricObject,
|
|
406
|
+
};
|
|
407
|
+
this.fire('drag', options);
|
|
408
|
+
this._dragSource && this._dragSource.fire('drag', options);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* As opposed to {@link findTarget} we want the top most object to be returned w/o the active object cutting in line.
|
|
413
|
+
* Override at will
|
|
414
|
+
*/
|
|
415
|
+
protected findDragTargets(e: DragEvent) {
|
|
416
|
+
this.targets = [];
|
|
417
|
+
const target = this._searchPossibleTargets(
|
|
418
|
+
this._objects,
|
|
419
|
+
this.getPointer(e, true)
|
|
420
|
+
);
|
|
421
|
+
return {
|
|
422
|
+
target,
|
|
423
|
+
targets: [...this.targets],
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* prevent default to allow drop event to be fired
|
|
429
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Drag_operations#specifying_drop_targets
|
|
430
|
+
* @private
|
|
431
|
+
* @param {DragEvent} [e] Event object fired on Event.js shake
|
|
432
|
+
*/
|
|
433
|
+
private _onDragOver(e: DragEvent) {
|
|
434
|
+
const eventType = 'dragover';
|
|
435
|
+
const { target, targets } = this.findDragTargets(e);
|
|
436
|
+
const dragSource = this._dragSource as FabricObject;
|
|
437
|
+
const options = {
|
|
438
|
+
e,
|
|
439
|
+
target,
|
|
440
|
+
subTargets: targets,
|
|
441
|
+
dragSource,
|
|
442
|
+
canDrop: false,
|
|
443
|
+
dropTarget: undefined,
|
|
444
|
+
};
|
|
445
|
+
let dropTarget;
|
|
446
|
+
// fire on canvas
|
|
447
|
+
this.fire(eventType, options);
|
|
448
|
+
// make sure we fire dragenter events before dragover
|
|
449
|
+
// if dragleave is needed, object will not fire dragover so we don't need to trouble ourselves with it
|
|
450
|
+
this._fireEnterLeaveEvents(target, options);
|
|
451
|
+
if (target) {
|
|
452
|
+
if (target.canDrop(e)) {
|
|
453
|
+
dropTarget = target;
|
|
454
|
+
}
|
|
455
|
+
target.fire(eventType, options);
|
|
456
|
+
}
|
|
457
|
+
// propagate the event to subtargets
|
|
458
|
+
for (let i = 0; i < targets.length; i++) {
|
|
459
|
+
const subTarget = targets[i];
|
|
460
|
+
// accept event only if previous targets didn't (the accepting target calls `preventDefault` to inform that the event is taken)
|
|
461
|
+
// TODO: verify if those should loop in inverse order then?
|
|
462
|
+
// what is the order of subtargets?
|
|
463
|
+
if (subTarget.canDrop(e)) {
|
|
464
|
+
dropTarget = subTarget;
|
|
465
|
+
}
|
|
466
|
+
subTarget.fire(eventType, options);
|
|
467
|
+
}
|
|
468
|
+
// render drag effects now that relations between source and target is clear
|
|
469
|
+
this._renderDragEffects(e, dragSource, dropTarget);
|
|
470
|
+
this._dropTarget = dropTarget;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* fire `dragleave` on `dragover` targets
|
|
475
|
+
* @private
|
|
476
|
+
* @param {Event} [e] Event object fired on Event.js shake
|
|
477
|
+
*/
|
|
478
|
+
private _onDragEnter(e: DragEvent) {
|
|
479
|
+
const { target, targets } = this.findDragTargets(e);
|
|
480
|
+
const options = {
|
|
481
|
+
e,
|
|
482
|
+
target,
|
|
483
|
+
subTargets: targets,
|
|
484
|
+
dragSource: this._dragSource,
|
|
485
|
+
};
|
|
486
|
+
this.fire('dragenter', options);
|
|
487
|
+
// fire dragenter on targets
|
|
488
|
+
this._fireEnterLeaveEvents(target, options);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/**
|
|
492
|
+
* fire `dragleave` on `dragover` targets
|
|
493
|
+
* @private
|
|
494
|
+
* @param {Event} [e] Event object fired on Event.js shake
|
|
495
|
+
*/
|
|
496
|
+
private _onDragLeave(e: DragEvent) {
|
|
497
|
+
const options = {
|
|
498
|
+
e,
|
|
499
|
+
target: this._draggedoverTarget,
|
|
500
|
+
subTargets: this.targets,
|
|
501
|
+
dragSource: this._dragSource,
|
|
502
|
+
};
|
|
503
|
+
this.fire('dragleave', options);
|
|
504
|
+
|
|
505
|
+
// fire dragleave on targets
|
|
506
|
+
this._fireEnterLeaveEvents(undefined, options);
|
|
507
|
+
this._renderDragEffects(e, this._dragSource);
|
|
508
|
+
this._dropTarget = undefined;
|
|
509
|
+
// clear targets
|
|
510
|
+
this.targets = [];
|
|
511
|
+
this._hoveredTargets = [];
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/**
|
|
515
|
+
* `drop:before` is a an event that allows you to schedule logic
|
|
516
|
+
* before the `drop` event. Prefer `drop` event always, but if you need
|
|
517
|
+
* to run some drop-disabling logic on an event, since there is no way
|
|
518
|
+
* to handle event handlers ordering, use `drop:before`
|
|
519
|
+
* @private
|
|
520
|
+
* @param {Event} e
|
|
521
|
+
*/
|
|
522
|
+
private _onDrop(e: DragEvent) {
|
|
523
|
+
const { target, targets } = this.findDragTargets(e);
|
|
524
|
+
const options = this._basicEventHandler('drop:before', {
|
|
525
|
+
e,
|
|
526
|
+
target,
|
|
527
|
+
subTargets: targets,
|
|
528
|
+
dragSource: this._dragSource,
|
|
529
|
+
pointer: this.getPointer(e),
|
|
530
|
+
});
|
|
531
|
+
// will be set by the drop target
|
|
532
|
+
options.didDrop = false;
|
|
533
|
+
// will be set by the drop target, used in case options.target refuses the drop
|
|
534
|
+
options.dropTarget = undefined;
|
|
535
|
+
// fire `drop`
|
|
536
|
+
this._basicEventHandler('drop', options);
|
|
537
|
+
// inform canvas of the drop
|
|
538
|
+
// we do this because canvas was unaware of what happened at the time the `drop` event was fired on it
|
|
539
|
+
// use for side effects
|
|
540
|
+
this.fire('drop:after', options);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/**
|
|
544
|
+
* @private
|
|
545
|
+
* @param {Event} e Event object fired on mousedown
|
|
546
|
+
*/
|
|
547
|
+
private _onContextMenu(e: TPointerEvent): false {
|
|
548
|
+
const target = this.findTarget(e),
|
|
549
|
+
subTargets = this.targets || [];
|
|
550
|
+
const options = this._basicEventHandler('contextmenu:before', {
|
|
551
|
+
e,
|
|
552
|
+
target,
|
|
553
|
+
subTargets,
|
|
554
|
+
});
|
|
555
|
+
// TODO: this line is silly because the dev can subscribe to the event and prevent it themselves
|
|
556
|
+
this.stopContextMenu && stopEvent(e);
|
|
557
|
+
this._basicEventHandler('contextmenu', options);
|
|
558
|
+
return false;
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
/**
|
|
562
|
+
* @private
|
|
563
|
+
* @param {Event} e Event object fired on mousedown
|
|
564
|
+
*/
|
|
565
|
+
private _onDoubleClick(e: TPointerEvent) {
|
|
566
|
+
this._cacheTransformEventData(e);
|
|
567
|
+
this._handleEvent(e, 'dblclick');
|
|
568
|
+
this._resetTransformEventData();
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Return a the id of an event.
|
|
573
|
+
* returns either the pointerId or the identifier or 0 for the mouse event
|
|
574
|
+
* @private
|
|
575
|
+
* @param {Event} evt Event object
|
|
576
|
+
*/
|
|
577
|
+
getPointerId(evt: TouchEvent | PointerEvent): number {
|
|
578
|
+
const changedTouches = (evt as TouchEvent).changedTouches;
|
|
579
|
+
|
|
580
|
+
if (changedTouches) {
|
|
581
|
+
return changedTouches[0] && changedTouches[0].identifier;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (this.enablePointerEvents) {
|
|
585
|
+
return (evt as PointerEvent).pointerId;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return -1;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Determines if an event has the id of the event that is considered main
|
|
593
|
+
* @private
|
|
594
|
+
* @param {evt} event Event object
|
|
595
|
+
*/
|
|
596
|
+
_isMainEvent(evt: TPointerEvent): boolean {
|
|
597
|
+
if ((evt as PointerEvent).isPrimary === true) {
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
if ((evt as PointerEvent).isPrimary === false) {
|
|
601
|
+
return false;
|
|
602
|
+
}
|
|
603
|
+
if (evt.type === 'touchend' && (evt as TouchEvent).touches.length === 0) {
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
if ((evt as TouchEvent).changedTouches) {
|
|
607
|
+
return (
|
|
608
|
+
(evt as TouchEvent).changedTouches[0].identifier === this.mainTouchId
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
return true;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/**
|
|
615
|
+
* @private
|
|
616
|
+
* @param {Event} e Event object fired on mousedown
|
|
617
|
+
*/
|
|
618
|
+
_onTouchStart(e: TouchEvent) {
|
|
619
|
+
e.preventDefault();
|
|
620
|
+
if (this.mainTouchId === null) {
|
|
621
|
+
this.mainTouchId = this.getPointerId(e);
|
|
622
|
+
}
|
|
623
|
+
this.__onMouseDown(e);
|
|
624
|
+
this._resetTransformEventData();
|
|
625
|
+
const canvasElement = this.upperCanvasEl,
|
|
626
|
+
eventTypePrefix = this._getEventPrefix();
|
|
627
|
+
addListener(
|
|
628
|
+
getEnv().document,
|
|
629
|
+
'touchend',
|
|
630
|
+
this._onTouchEnd as EventListener,
|
|
631
|
+
addEventOptions
|
|
632
|
+
);
|
|
633
|
+
addListener(
|
|
634
|
+
getEnv().document,
|
|
635
|
+
'touchmove',
|
|
636
|
+
this._onMouseMove as EventListener,
|
|
637
|
+
addEventOptions
|
|
638
|
+
);
|
|
639
|
+
// Unbind mousedown to prevent double triggers from touch devices
|
|
640
|
+
removeListener(
|
|
641
|
+
canvasElement,
|
|
642
|
+
eventTypePrefix + 'down',
|
|
643
|
+
this._onMouseDown as EventListener
|
|
644
|
+
);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
/**
|
|
648
|
+
* @private
|
|
649
|
+
* @param {Event} e Event object fired on mousedown
|
|
650
|
+
*/
|
|
651
|
+
_onMouseDown(e: TPointerEvent) {
|
|
652
|
+
this.__onMouseDown(e);
|
|
653
|
+
this._resetTransformEventData();
|
|
654
|
+
const canvasElement = this.upperCanvasEl,
|
|
655
|
+
eventTypePrefix = this._getEventPrefix();
|
|
656
|
+
removeListener(
|
|
657
|
+
canvasElement,
|
|
658
|
+
`${eventTypePrefix}move`,
|
|
659
|
+
this._onMouseMove as EventListener,
|
|
660
|
+
addEventOptions
|
|
661
|
+
);
|
|
662
|
+
addListener(
|
|
663
|
+
getEnv().document,
|
|
664
|
+
`${eventTypePrefix}up`,
|
|
665
|
+
this._onMouseUp as EventListener
|
|
666
|
+
);
|
|
667
|
+
addListener(
|
|
668
|
+
getEnv().document,
|
|
669
|
+
`${eventTypePrefix}move`,
|
|
670
|
+
this._onMouseMove as EventListener,
|
|
671
|
+
addEventOptions
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* @private
|
|
677
|
+
* @param {Event} e Event object fired on mousedown
|
|
678
|
+
*/
|
|
679
|
+
_onTouchEnd(e: TouchEvent) {
|
|
680
|
+
if (e.touches.length > 0) {
|
|
681
|
+
// if there are still touches stop here
|
|
682
|
+
return;
|
|
683
|
+
}
|
|
684
|
+
this.__onMouseUp(e);
|
|
685
|
+
this._resetTransformEventData();
|
|
686
|
+
this.mainTouchId = null;
|
|
687
|
+
const eventTypePrefix = this._getEventPrefix();
|
|
688
|
+
removeListener(
|
|
689
|
+
getEnv().document,
|
|
690
|
+
'touchend',
|
|
691
|
+
this._onTouchEnd as EventListener,
|
|
692
|
+
addEventOptions
|
|
693
|
+
);
|
|
694
|
+
removeListener(
|
|
695
|
+
getEnv().document,
|
|
696
|
+
'touchmove',
|
|
697
|
+
this._onMouseMove as EventListener,
|
|
698
|
+
addEventOptions
|
|
699
|
+
);
|
|
700
|
+
if (this._willAddMouseDown) {
|
|
701
|
+
clearTimeout(this._willAddMouseDown);
|
|
702
|
+
}
|
|
703
|
+
this._willAddMouseDown = setTimeout(() => {
|
|
704
|
+
// Wait 400ms before rebinding mousedown to prevent double triggers
|
|
705
|
+
// from touch devices
|
|
706
|
+
addListener(
|
|
707
|
+
this.upperCanvasEl,
|
|
708
|
+
eventTypePrefix + 'down',
|
|
709
|
+
this._onMouseDown as EventListener
|
|
710
|
+
);
|
|
711
|
+
this._willAddMouseDown = 0;
|
|
712
|
+
}, 400) as unknown as number;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* @private
|
|
717
|
+
* @param {Event} e Event object fired on mouseup
|
|
718
|
+
*/
|
|
719
|
+
_onMouseUp(e: TPointerEvent) {
|
|
720
|
+
this.__onMouseUp(e);
|
|
721
|
+
this._resetTransformEventData();
|
|
722
|
+
const canvasElement = this.upperCanvasEl,
|
|
723
|
+
eventTypePrefix = this._getEventPrefix();
|
|
724
|
+
if (this._isMainEvent(e)) {
|
|
725
|
+
removeListener(
|
|
726
|
+
getEnv().document,
|
|
727
|
+
`${eventTypePrefix}up`,
|
|
728
|
+
this._onMouseUp as EventListener
|
|
729
|
+
);
|
|
730
|
+
removeListener(
|
|
731
|
+
getEnv().document,
|
|
732
|
+
`${eventTypePrefix}move`,
|
|
733
|
+
this._onMouseMove as EventListener,
|
|
734
|
+
addEventOptions
|
|
735
|
+
);
|
|
736
|
+
addListener(
|
|
737
|
+
canvasElement,
|
|
738
|
+
`${eventTypePrefix}move`,
|
|
739
|
+
this._onMouseMove as EventListener,
|
|
740
|
+
addEventOptions
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
* @private
|
|
747
|
+
* @param {Event} e Event object fired on mousemove
|
|
748
|
+
*/
|
|
749
|
+
_onMouseMove(e: TPointerEvent) {
|
|
750
|
+
const activeObject = this.getActiveObject();
|
|
751
|
+
!this.allowTouchScrolling &&
|
|
752
|
+
(!activeObject ||
|
|
753
|
+
// a drag event sequence is started by the active object flagging itself on mousedown / mousedown:before
|
|
754
|
+
// we must not prevent the event's default behavior in order for the window to start dragging
|
|
755
|
+
(isFabricObjectWithDragSupport(activeObject) &&
|
|
756
|
+
!activeObject.shouldStartDragging())) &&
|
|
757
|
+
e.preventDefault &&
|
|
758
|
+
e.preventDefault();
|
|
759
|
+
this.__onMouseMove(e);
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
/**
|
|
763
|
+
* @private
|
|
764
|
+
*/
|
|
765
|
+
_onResize() {
|
|
766
|
+
this.calcOffset();
|
|
767
|
+
this._resetTransformEventData();
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/**
|
|
771
|
+
* Decides whether the canvas should be redrawn in mouseup and mousedown events.
|
|
772
|
+
* @private
|
|
773
|
+
* @param {Object} target
|
|
774
|
+
*/
|
|
775
|
+
_shouldRender(target: FabricObject | undefined) {
|
|
776
|
+
const activeObject = this.getActiveObject();
|
|
777
|
+
|
|
778
|
+
// if just one of them is available or if they are both but are different objects
|
|
779
|
+
if (
|
|
780
|
+
!!activeObject !== !!target ||
|
|
781
|
+
(activeObject && target && activeObject !== target)
|
|
782
|
+
) {
|
|
783
|
+
// this covers: switch of target, from target to no target, selection of target
|
|
784
|
+
// multiSelection with key and mouse
|
|
785
|
+
return true;
|
|
786
|
+
} else if (isInteractiveTextObject(activeObject)) {
|
|
787
|
+
// if we mouse up/down over a editing textbox a cursor change,
|
|
788
|
+
// there is no need to re render
|
|
789
|
+
return false;
|
|
790
|
+
}
|
|
791
|
+
return false;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
/**
|
|
795
|
+
* Method that defines the actions when mouse is released on canvas.
|
|
796
|
+
* The method resets the currentTransform parameters, store the image corner
|
|
797
|
+
* position in the image object and render the canvas on top.
|
|
798
|
+
* @private
|
|
799
|
+
* @param {Event} e Event object fired on mouseup
|
|
800
|
+
*/
|
|
801
|
+
__onMouseUp(e: TPointerEvent) {
|
|
802
|
+
const transform = this._currentTransform;
|
|
803
|
+
this._cacheTransformEventData(e);
|
|
804
|
+
const target = this._target;
|
|
805
|
+
const isClick = this._isClick;
|
|
806
|
+
this._handleEvent(e, 'up:before');
|
|
807
|
+
// if right/middle click just fire events and return
|
|
808
|
+
// target undefined will make the _handleEvent search the target
|
|
809
|
+
if (checkClick(e, RIGHT_CLICK)) {
|
|
810
|
+
if (this.fireRightClick) {
|
|
811
|
+
this._handleEvent(e, 'up', RIGHT_CLICK, isClick);
|
|
812
|
+
}
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
if (checkClick(e, MIDDLE_CLICK)) {
|
|
817
|
+
if (this.fireMiddleClick) {
|
|
818
|
+
this._handleEvent(e, 'up', MIDDLE_CLICK, isClick);
|
|
819
|
+
}
|
|
820
|
+
this._resetTransformEventData();
|
|
821
|
+
return;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (this.isDrawingMode && this._isCurrentlyDrawing) {
|
|
825
|
+
this._onMouseUpInDrawingMode(e);
|
|
826
|
+
return;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
if (!this._isMainEvent(e)) {
|
|
830
|
+
return;
|
|
831
|
+
}
|
|
832
|
+
let shouldRender = false;
|
|
833
|
+
if (transform) {
|
|
834
|
+
this._finalizeCurrentTransform(e);
|
|
835
|
+
shouldRender = transform.actionPerformed;
|
|
836
|
+
}
|
|
837
|
+
if (!isClick) {
|
|
838
|
+
const targetWasActive = target === this._activeObject;
|
|
839
|
+
this._maybeGroupObjects(e);
|
|
840
|
+
if (!shouldRender) {
|
|
841
|
+
shouldRender =
|
|
842
|
+
this._shouldRender(target) ||
|
|
843
|
+
(!targetWasActive && target === this._activeObject);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
let pointer, corner;
|
|
847
|
+
if (target) {
|
|
848
|
+
corner = target._findTargetCorner(
|
|
849
|
+
this.getPointer(e, true),
|
|
850
|
+
isTouchEvent(e)
|
|
851
|
+
);
|
|
852
|
+
if (
|
|
853
|
+
target.selectable &&
|
|
854
|
+
target !== this._activeObject &&
|
|
855
|
+
target.activeOn === 'up'
|
|
856
|
+
) {
|
|
857
|
+
this.setActiveObject(target, e);
|
|
858
|
+
shouldRender = true;
|
|
859
|
+
} else {
|
|
860
|
+
const control = target.controls[corner as string];
|
|
861
|
+
const mouseUpHandler =
|
|
862
|
+
control && control.getMouseUpHandler(e, target, control);
|
|
863
|
+
if (mouseUpHandler) {
|
|
864
|
+
pointer = this.getPointer(e);
|
|
865
|
+
mouseUpHandler(e, transform!, pointer.x, pointer.y);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
target.isMoving = false;
|
|
869
|
+
}
|
|
870
|
+
// if we are ending up a transform on a different control or a new object
|
|
871
|
+
// fire the original mouse up from the corner that started the transform
|
|
872
|
+
if (
|
|
873
|
+
transform &&
|
|
874
|
+
(transform.target !== target || transform.corner !== corner)
|
|
875
|
+
) {
|
|
876
|
+
const originalControl =
|
|
877
|
+
transform.target && transform.target.controls[transform.corner],
|
|
878
|
+
originalMouseUpHandler =
|
|
879
|
+
originalControl &&
|
|
880
|
+
originalControl.getMouseUpHandler(
|
|
881
|
+
e,
|
|
882
|
+
transform.target,
|
|
883
|
+
originalControl
|
|
884
|
+
);
|
|
885
|
+
pointer = pointer || this.getPointer(e);
|
|
886
|
+
originalMouseUpHandler &&
|
|
887
|
+
originalMouseUpHandler(e, transform, pointer.x, pointer.y);
|
|
888
|
+
}
|
|
889
|
+
this._setCursorFromEvent(e, target);
|
|
890
|
+
this._handleEvent(e, 'up', LEFT_CLICK, isClick);
|
|
891
|
+
this._groupSelector = null;
|
|
892
|
+
this._currentTransform = null;
|
|
893
|
+
// reset the target information about which corner is selected
|
|
894
|
+
target && (target.__corner = undefined);
|
|
895
|
+
if (shouldRender) {
|
|
896
|
+
this.requestRenderAll();
|
|
897
|
+
} else if (
|
|
898
|
+
!isClick &&
|
|
899
|
+
!(
|
|
900
|
+
isInteractiveTextObject(this._activeObject) &&
|
|
901
|
+
this._activeObject.isEditing
|
|
902
|
+
)
|
|
903
|
+
) {
|
|
904
|
+
this.renderTop();
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
_basicEventHandler<T extends keyof (CanvasEvents | ObjectEvents)>(
|
|
909
|
+
eventType: T,
|
|
910
|
+
options: (CanvasEvents & ObjectEvents)[T]
|
|
911
|
+
) {
|
|
912
|
+
const { target, subTargets = [] } = options as {
|
|
913
|
+
target?: FabricObject;
|
|
914
|
+
subTargets: FabricObject[];
|
|
915
|
+
};
|
|
916
|
+
this.fire(eventType, options);
|
|
917
|
+
target && target.fire(eventType, options);
|
|
918
|
+
for (let i = 0; i < subTargets.length; i++) {
|
|
919
|
+
subTargets[i].fire(eventType, options);
|
|
920
|
+
}
|
|
921
|
+
return options;
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
/**
|
|
925
|
+
* @private
|
|
926
|
+
* Handle event firing for target and subtargets
|
|
927
|
+
* @param {Event} e event from mouse
|
|
928
|
+
* @param {String} eventType event to fire (up, down or move)
|
|
929
|
+
* @param {fabric.Object} targetObj receiving event
|
|
930
|
+
* @param {Number} [button] button used in the event 1 = left, 2 = middle, 3 = right
|
|
931
|
+
* @param {Boolean} isClick for left button only, indicates that the mouse up happened without move.
|
|
932
|
+
*/
|
|
933
|
+
_handleEvent(
|
|
934
|
+
e: TPointerEvent,
|
|
935
|
+
eventType: TPointerEventNames,
|
|
936
|
+
button = LEFT_CLICK,
|
|
937
|
+
isClick = false
|
|
938
|
+
) {
|
|
939
|
+
const target = this._target,
|
|
940
|
+
targets = this.targets || [],
|
|
941
|
+
options: TPointerEventInfo = {
|
|
942
|
+
e: e,
|
|
943
|
+
target: target,
|
|
944
|
+
subTargets: targets,
|
|
945
|
+
button,
|
|
946
|
+
isClick,
|
|
947
|
+
pointer: this.getPointer(e),
|
|
948
|
+
absolutePointer: this.getPointer(e, true),
|
|
949
|
+
transform: this._currentTransform,
|
|
950
|
+
};
|
|
951
|
+
if (eventType === 'up') {
|
|
952
|
+
options.currentTarget = this.findTarget(e);
|
|
953
|
+
options.currentSubTargets = this.targets;
|
|
954
|
+
}
|
|
955
|
+
this.fire(`mouse:${eventType}`, options);
|
|
956
|
+
// this may be a little be more complicated of what we want to handle
|
|
957
|
+
target && target.fire(`mouse${eventType}`, options);
|
|
958
|
+
for (let i = 0; i < targets.length; i++) {
|
|
959
|
+
targets[i].fire(`mouse${eventType}`, options);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* End the current transform.
|
|
965
|
+
* You don't usually need to call this method unless you are interrupting a user initiated transform
|
|
966
|
+
* because of some other event ( a press of key combination, or something that block the user UX )
|
|
967
|
+
* @param {Event} [e] send the mouse event that generate the finalize down, so it can be used in the event
|
|
968
|
+
*/
|
|
969
|
+
endCurrentTransform(e: TPointerEvent) {
|
|
970
|
+
const transform = this._currentTransform;
|
|
971
|
+
this._finalizeCurrentTransform(e);
|
|
972
|
+
if (transform && transform.target) {
|
|
973
|
+
// this could probably go inside _finalizeCurrentTransform
|
|
974
|
+
transform.target.isMoving = false;
|
|
975
|
+
}
|
|
976
|
+
this._currentTransform = null;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
/**
|
|
980
|
+
* @private
|
|
981
|
+
* @param {Event} e send the mouse event that generate the finalize down, so it can be used in the event
|
|
982
|
+
*/
|
|
983
|
+
_finalizeCurrentTransform(e: TPointerEvent) {
|
|
984
|
+
const transform = this._currentTransform!,
|
|
985
|
+
target = transform.target,
|
|
986
|
+
options = {
|
|
987
|
+
e,
|
|
988
|
+
target,
|
|
989
|
+
transform,
|
|
990
|
+
action: transform.action,
|
|
991
|
+
};
|
|
992
|
+
|
|
993
|
+
if (target._scaling) {
|
|
994
|
+
target._scaling = false;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
target.setCoords();
|
|
998
|
+
|
|
999
|
+
if (transform.actionPerformed) {
|
|
1000
|
+
this.fire('object:modified', options);
|
|
1001
|
+
target.fire('modified', options);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* @private
|
|
1007
|
+
* @param {Event} e Event object fired on mousedown
|
|
1008
|
+
*/
|
|
1009
|
+
_onMouseDownInDrawingMode(e: TPointerEvent) {
|
|
1010
|
+
this._isCurrentlyDrawing = true;
|
|
1011
|
+
if (this.getActiveObject()) {
|
|
1012
|
+
this.discardActiveObject(e);
|
|
1013
|
+
this.requestRenderAll();
|
|
1014
|
+
}
|
|
1015
|
+
const pointer = this.getPointer(e);
|
|
1016
|
+
this.freeDrawingBrush &&
|
|
1017
|
+
this.freeDrawingBrush.onMouseDown(pointer, { e, pointer });
|
|
1018
|
+
this._handleEvent(e, 'down');
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* @private
|
|
1023
|
+
* @param {Event} e Event object fired on mousemove
|
|
1024
|
+
*/
|
|
1025
|
+
_onMouseMoveInDrawingMode(e: TPointerEvent) {
|
|
1026
|
+
if (this._isCurrentlyDrawing) {
|
|
1027
|
+
const pointer = this.getPointer(e);
|
|
1028
|
+
this.freeDrawingBrush &&
|
|
1029
|
+
this.freeDrawingBrush.onMouseMove(pointer, {
|
|
1030
|
+
e,
|
|
1031
|
+
pointer,
|
|
1032
|
+
});
|
|
1033
|
+
}
|
|
1034
|
+
this.setCursor(this.freeDrawingCursor);
|
|
1035
|
+
this._handleEvent(e, 'move');
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
/**
|
|
1039
|
+
* @private
|
|
1040
|
+
* @param {Event} e Event object fired on mouseup
|
|
1041
|
+
*/
|
|
1042
|
+
_onMouseUpInDrawingMode(e: TPointerEvent) {
|
|
1043
|
+
const pointer = this.getPointer(e);
|
|
1044
|
+
if (this.freeDrawingBrush) {
|
|
1045
|
+
this._isCurrentlyDrawing = !!this.freeDrawingBrush.onMouseUp({
|
|
1046
|
+
e: e,
|
|
1047
|
+
pointer: pointer,
|
|
1048
|
+
});
|
|
1049
|
+
} else {
|
|
1050
|
+
this._isCurrentlyDrawing = false;
|
|
1051
|
+
}
|
|
1052
|
+
this._handleEvent(e, 'up');
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
/**
|
|
1056
|
+
* Method that defines the actions when mouse is clicked on canvas.
|
|
1057
|
+
* The method inits the currentTransform parameters and renders all the
|
|
1058
|
+
* canvas so the current image can be placed on the top canvas and the rest
|
|
1059
|
+
* in on the container one.
|
|
1060
|
+
* @private
|
|
1061
|
+
* @param {Event} e Event object fired on mousedown
|
|
1062
|
+
*/
|
|
1063
|
+
__onMouseDown(e: TPointerEvent) {
|
|
1064
|
+
this._isClick = true;
|
|
1065
|
+
this._cacheTransformEventData(e);
|
|
1066
|
+
this._handleEvent(e, 'down:before');
|
|
1067
|
+
let target: FabricObject | undefined = this._target;
|
|
1068
|
+
// if right click just fire events
|
|
1069
|
+
if (checkClick(e, RIGHT_CLICK)) {
|
|
1070
|
+
if (this.fireRightClick) {
|
|
1071
|
+
this._handleEvent(e, 'down', RIGHT_CLICK);
|
|
1072
|
+
}
|
|
1073
|
+
return;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
if (checkClick(e, MIDDLE_CLICK)) {
|
|
1077
|
+
if (this.fireMiddleClick) {
|
|
1078
|
+
this._handleEvent(e, 'down', MIDDLE_CLICK);
|
|
1079
|
+
}
|
|
1080
|
+
return;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
if (this.isDrawingMode) {
|
|
1084
|
+
this._onMouseDownInDrawingMode(e);
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
if (!this._isMainEvent(e)) {
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
// ignore if some object is being transformed at this moment
|
|
1093
|
+
if (this._currentTransform) {
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
const pointer = this.getPointer(e, true);
|
|
1098
|
+
// save pointer for check in __onMouseUp event
|
|
1099
|
+
this._previousPointer = pointer;
|
|
1100
|
+
const shouldRender = this._shouldRender(target),
|
|
1101
|
+
shouldGroup = this._shouldGroup(e, target);
|
|
1102
|
+
if (this._shouldClearSelection(e, target)) {
|
|
1103
|
+
this.discardActiveObject(e);
|
|
1104
|
+
} else if (shouldGroup) {
|
|
1105
|
+
// in order for shouldGroup to be true, target needs to be true
|
|
1106
|
+
this._handleGrouping(e, target!);
|
|
1107
|
+
target = this._activeObject;
|
|
1108
|
+
}
|
|
1109
|
+
// we start a group selector rectangle if
|
|
1110
|
+
// selection is enabled
|
|
1111
|
+
// and there is no target, or the following 3 condition both apply
|
|
1112
|
+
// target is not selectable ( otherwise we selected it )
|
|
1113
|
+
// target is not editing
|
|
1114
|
+
// target is not already selected ( otherwise we drage )
|
|
1115
|
+
if (
|
|
1116
|
+
this.selection &&
|
|
1117
|
+
(!target ||
|
|
1118
|
+
(!target.selectable &&
|
|
1119
|
+
// @ts-ignore
|
|
1120
|
+
!target.isEditing &&
|
|
1121
|
+
target !== this._activeObject))
|
|
1122
|
+
) {
|
|
1123
|
+
const p = this.getPointer(e);
|
|
1124
|
+
this._groupSelector = {
|
|
1125
|
+
ex: p.x,
|
|
1126
|
+
ey: p.y,
|
|
1127
|
+
top: 0,
|
|
1128
|
+
left: 0,
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
if (target) {
|
|
1133
|
+
const alreadySelected = target === this._activeObject;
|
|
1134
|
+
if (target.selectable && target.activeOn === 'down') {
|
|
1135
|
+
this.setActiveObject(target, e);
|
|
1136
|
+
}
|
|
1137
|
+
const corner = target._findTargetCorner(
|
|
1138
|
+
this.getPointer(e, true),
|
|
1139
|
+
isTouchEvent(e)
|
|
1140
|
+
);
|
|
1141
|
+
if (target === this._activeObject && (corner || !shouldGroup)) {
|
|
1142
|
+
this._setupCurrentTransform(e, target, alreadySelected);
|
|
1143
|
+
const control = target.controls[corner],
|
|
1144
|
+
pointer = this.getPointer(e),
|
|
1145
|
+
mouseDownHandler =
|
|
1146
|
+
control && control.getMouseDownHandler(e, target, control);
|
|
1147
|
+
if (mouseDownHandler) {
|
|
1148
|
+
mouseDownHandler(e, this._currentTransform!, pointer.x, pointer.y);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
}
|
|
1152
|
+
const invalidate = shouldRender || shouldGroup;
|
|
1153
|
+
// we clear `_objectsToRender` in case of a change in order to repopulate it at rendering
|
|
1154
|
+
// run before firing the `down` event to give the dev a chance to populate it themselves
|
|
1155
|
+
invalidate && (this._objectsToRender = undefined);
|
|
1156
|
+
this._handleEvent(e, 'down');
|
|
1157
|
+
// we must renderAll so that we update the visuals
|
|
1158
|
+
invalidate && this.requestRenderAll();
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
/**
|
|
1162
|
+
* reset cache form common information needed during event processing
|
|
1163
|
+
* @private
|
|
1164
|
+
*/
|
|
1165
|
+
_resetTransformEventData() {
|
|
1166
|
+
this._target = undefined;
|
|
1167
|
+
this._pointer = undefined;
|
|
1168
|
+
this._absolutePointer = undefined;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
/**
|
|
1172
|
+
* Cache common information needed during event processing
|
|
1173
|
+
* @private
|
|
1174
|
+
* @param {Event} e Event object fired on event
|
|
1175
|
+
*/
|
|
1176
|
+
_cacheTransformEventData(e: TPointerEvent) {
|
|
1177
|
+
// reset in order to avoid stale caching
|
|
1178
|
+
this._resetTransformEventData();
|
|
1179
|
+
this._pointer = this.getPointer(e, true);
|
|
1180
|
+
this._absolutePointer = this.restorePointerVpt(this._pointer);
|
|
1181
|
+
this._target = this._currentTransform
|
|
1182
|
+
? this._currentTransform.target
|
|
1183
|
+
: this.findTarget(e);
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* @private
|
|
1188
|
+
*/
|
|
1189
|
+
_beforeTransform(e: TPointerEvent) {
|
|
1190
|
+
const t = this._currentTransform!;
|
|
1191
|
+
this.fire('before:transform', {
|
|
1192
|
+
e,
|
|
1193
|
+
transform: t,
|
|
1194
|
+
});
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* Method that defines the actions when mouse is hovering the canvas.
|
|
1199
|
+
* The currentTransform parameter will define whether the user is rotating/scaling/translating
|
|
1200
|
+
* an image or neither of them (only hovering). A group selection is also possible and would cancel
|
|
1201
|
+
* all any other type of action.
|
|
1202
|
+
* In case of an image transformation only the top canvas will be rendered.
|
|
1203
|
+
* @private
|
|
1204
|
+
* @param {Event} e Event object fired on mousemove
|
|
1205
|
+
*/
|
|
1206
|
+
__onMouseMove(e: TPointerEvent) {
|
|
1207
|
+
this._isClick = false;
|
|
1208
|
+
this._handleEvent(e, 'move:before');
|
|
1209
|
+
this._cacheTransformEventData(e);
|
|
1210
|
+
|
|
1211
|
+
if (this.isDrawingMode) {
|
|
1212
|
+
this._onMouseMoveInDrawingMode(e);
|
|
1213
|
+
return;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
if (!this._isMainEvent(e)) {
|
|
1217
|
+
return;
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
const groupSelector = this._groupSelector;
|
|
1221
|
+
|
|
1222
|
+
// We initially clicked in an empty area, so we draw a box for multiple selection
|
|
1223
|
+
if (groupSelector) {
|
|
1224
|
+
const pointer = this.getPointer(e);
|
|
1225
|
+
|
|
1226
|
+
groupSelector.left = pointer.x - groupSelector.ex;
|
|
1227
|
+
groupSelector.top = pointer.y - groupSelector.ey;
|
|
1228
|
+
|
|
1229
|
+
this.renderTop();
|
|
1230
|
+
} else if (!this._currentTransform) {
|
|
1231
|
+
const target = this.findTarget(e);
|
|
1232
|
+
this._setCursorFromEvent(e, target);
|
|
1233
|
+
this._fireOverOutEvents(e, target);
|
|
1234
|
+
} else {
|
|
1235
|
+
this._transformObject(e);
|
|
1236
|
+
}
|
|
1237
|
+
this.textEditingManager.onMouseMove(e);
|
|
1238
|
+
this._handleEvent(e, 'move');
|
|
1239
|
+
this._resetTransformEventData();
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
/**
|
|
1243
|
+
* Manage the mouseout, mouseover events for the fabric object on the canvas
|
|
1244
|
+
* @param {Fabric.Object} target the target where the target from the mousemove event
|
|
1245
|
+
* @param {Event} e Event object fired on mousemove
|
|
1246
|
+
* @private
|
|
1247
|
+
*/
|
|
1248
|
+
_fireOverOutEvents(e: TPointerEvent, target?: FabricObject) {
|
|
1249
|
+
const _hoveredTarget = this._hoveredTarget,
|
|
1250
|
+
_hoveredTargets = this._hoveredTargets,
|
|
1251
|
+
targets = this.targets,
|
|
1252
|
+
length = Math.max(_hoveredTargets.length, targets.length);
|
|
1253
|
+
|
|
1254
|
+
this.fireSyntheticInOutEvents('mouse', {
|
|
1255
|
+
e,
|
|
1256
|
+
target,
|
|
1257
|
+
oldTarget: _hoveredTarget,
|
|
1258
|
+
fireCanvas: true,
|
|
1259
|
+
});
|
|
1260
|
+
for (let i = 0; i < length; i++) {
|
|
1261
|
+
this.fireSyntheticInOutEvents('mouse', {
|
|
1262
|
+
e,
|
|
1263
|
+
target: targets[i],
|
|
1264
|
+
oldTarget: _hoveredTargets[i],
|
|
1265
|
+
});
|
|
1266
|
+
}
|
|
1267
|
+
this._hoveredTarget = target;
|
|
1268
|
+
this._hoveredTargets = this.targets.concat();
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
/**
|
|
1272
|
+
* Manage the dragEnter, dragLeave events for the fabric objects on the canvas
|
|
1273
|
+
* @param {Fabric.Object} target the target where the target from the onDrag event
|
|
1274
|
+
* @param {Object} data Event object fired on dragover
|
|
1275
|
+
* @private
|
|
1276
|
+
*/
|
|
1277
|
+
_fireEnterLeaveEvents(target: FabricObject | undefined, data: DragEventData) {
|
|
1278
|
+
const draggedoverTarget = this._draggedoverTarget,
|
|
1279
|
+
_hoveredTargets = this._hoveredTargets,
|
|
1280
|
+
targets = this.targets,
|
|
1281
|
+
length = Math.max(_hoveredTargets.length, targets.length);
|
|
1282
|
+
|
|
1283
|
+
this.fireSyntheticInOutEvents('drag', {
|
|
1284
|
+
...data,
|
|
1285
|
+
target,
|
|
1286
|
+
oldTarget: draggedoverTarget,
|
|
1287
|
+
fireCanvas: true,
|
|
1288
|
+
});
|
|
1289
|
+
for (let i = 0; i < length; i++) {
|
|
1290
|
+
this.fireSyntheticInOutEvents('drag', {
|
|
1291
|
+
...data,
|
|
1292
|
+
target: targets[i],
|
|
1293
|
+
oldTarget: _hoveredTargets[i],
|
|
1294
|
+
});
|
|
1295
|
+
}
|
|
1296
|
+
this._draggedoverTarget = target;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Manage the synthetic in/out events for the fabric objects on the canvas
|
|
1301
|
+
* @param {Fabric.Object} target the target where the target from the supported events
|
|
1302
|
+
* @param {Object} data Event object fired
|
|
1303
|
+
* @param {Object} config configuration for the function to work
|
|
1304
|
+
* @param {String} config.targetName property on the canvas where the old target is stored
|
|
1305
|
+
* @param {String} [config.canvasEvtOut] name of the event to fire at canvas level for out
|
|
1306
|
+
* @param {String} config.evtOut name of the event to fire for out
|
|
1307
|
+
* @param {String} [config.canvasEvtIn] name of the event to fire at canvas level for in
|
|
1308
|
+
* @param {String} config.evtIn name of the event to fire for in
|
|
1309
|
+
* @private
|
|
1310
|
+
*/
|
|
1311
|
+
fireSyntheticInOutEvents<T extends keyof TSyntheticEventContext>(
|
|
1312
|
+
type: T,
|
|
1313
|
+
{
|
|
1314
|
+
target,
|
|
1315
|
+
oldTarget,
|
|
1316
|
+
fireCanvas,
|
|
1317
|
+
e,
|
|
1318
|
+
...data
|
|
1319
|
+
}: TSyntheticEventContext[T] & {
|
|
1320
|
+
target?: FabricObject;
|
|
1321
|
+
oldTarget?: FabricObject;
|
|
1322
|
+
fireCanvas?: boolean;
|
|
1323
|
+
}
|
|
1324
|
+
) {
|
|
1325
|
+
const { targetIn, targetOut, canvasIn, canvasOut } =
|
|
1326
|
+
syntheticEventConfig[type];
|
|
1327
|
+
const targetChanged = oldTarget !== target;
|
|
1328
|
+
|
|
1329
|
+
if (oldTarget && targetChanged) {
|
|
1330
|
+
const outOpt = {
|
|
1331
|
+
...data,
|
|
1332
|
+
e,
|
|
1333
|
+
target: oldTarget,
|
|
1334
|
+
nextTarget: target,
|
|
1335
|
+
isClick: false,
|
|
1336
|
+
pointer: this.getPointer(e),
|
|
1337
|
+
absolutePointer: this.getPointer(e, true),
|
|
1338
|
+
};
|
|
1339
|
+
fireCanvas && this.fire(canvasIn, outOpt);
|
|
1340
|
+
oldTarget.fire(targetOut, outOpt);
|
|
1341
|
+
}
|
|
1342
|
+
if (target && targetChanged) {
|
|
1343
|
+
const inOpt: TPointerEventInfo = {
|
|
1344
|
+
...data,
|
|
1345
|
+
e,
|
|
1346
|
+
target,
|
|
1347
|
+
previousTarget: oldTarget,
|
|
1348
|
+
isClick: false,
|
|
1349
|
+
pointer: this.getPointer(e),
|
|
1350
|
+
absolutePointer: this.getPointer(e, true),
|
|
1351
|
+
};
|
|
1352
|
+
fireCanvas && this.fire(canvasOut, inOpt);
|
|
1353
|
+
target.fire(targetIn, inOpt);
|
|
1354
|
+
}
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
/**
|
|
1358
|
+
* Method that defines actions when an Event Mouse Wheel
|
|
1359
|
+
* @param {Event} e Event object fired on mouseup
|
|
1360
|
+
*/
|
|
1361
|
+
__onMouseWheel(e: TPointerEvent) {
|
|
1362
|
+
this._cacheTransformEventData(e);
|
|
1363
|
+
this._handleEvent(e, 'wheel');
|
|
1364
|
+
this._resetTransformEventData();
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* @private
|
|
1369
|
+
* @param {Event} e Event fired on mousemove
|
|
1370
|
+
*/
|
|
1371
|
+
_transformObject(e: TPointerEvent) {
|
|
1372
|
+
const pointer = this.getPointer(e),
|
|
1373
|
+
transform = this._currentTransform!,
|
|
1374
|
+
target = transform.target,
|
|
1375
|
+
// transform pointer to target's containing coordinate plane
|
|
1376
|
+
// both pointer and object should agree on every point
|
|
1377
|
+
localPointer = target.group
|
|
1378
|
+
? sendPointToPlane(
|
|
1379
|
+
pointer,
|
|
1380
|
+
undefined,
|
|
1381
|
+
target.group.calcTransformMatrix()
|
|
1382
|
+
)
|
|
1383
|
+
: pointer;
|
|
1384
|
+
// seems used only here.
|
|
1385
|
+
// @TODO: investigate;
|
|
1386
|
+
// @ts-ignore
|
|
1387
|
+
transform.reset = false;
|
|
1388
|
+
transform.shiftKey = e.shiftKey;
|
|
1389
|
+
transform.altKey = !!this.centeredKey && e[this.centeredKey];
|
|
1390
|
+
|
|
1391
|
+
this._performTransformAction(e, transform, localPointer);
|
|
1392
|
+
transform.actionPerformed && this.requestRenderAll();
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
/**
|
|
1396
|
+
* @private
|
|
1397
|
+
*/
|
|
1398
|
+
_performTransformAction(
|
|
1399
|
+
e: TPointerEvent,
|
|
1400
|
+
transform: Transform,
|
|
1401
|
+
pointer: Point
|
|
1402
|
+
) {
|
|
1403
|
+
const x = pointer.x,
|
|
1404
|
+
y = pointer.y,
|
|
1405
|
+
action = transform.action,
|
|
1406
|
+
actionHandler = transform.actionHandler;
|
|
1407
|
+
let actionPerformed = false;
|
|
1408
|
+
// this object could be created from the function in the control handlers
|
|
1409
|
+
|
|
1410
|
+
if (actionHandler) {
|
|
1411
|
+
actionPerformed = actionHandler(e, transform, x, y);
|
|
1412
|
+
}
|
|
1413
|
+
if (action === 'drag' && actionPerformed) {
|
|
1414
|
+
transform.target.isMoving = true;
|
|
1415
|
+
this.setCursor(transform.target.moveCursor || this.moveCursor);
|
|
1416
|
+
}
|
|
1417
|
+
transform.actionPerformed = transform.actionPerformed || actionPerformed;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
/**
|
|
1421
|
+
* Sets the cursor depending on where the canvas is being hovered.
|
|
1422
|
+
* Note: very buggy in Opera
|
|
1423
|
+
* @param {Event} e Event object
|
|
1424
|
+
* @param {Object} target Object that the mouse is hovering, if so.
|
|
1425
|
+
*/
|
|
1426
|
+
_setCursorFromEvent(e: TPointerEvent, target?: FabricObject) {
|
|
1427
|
+
if (!target) {
|
|
1428
|
+
this.setCursor(this.defaultCursor);
|
|
1429
|
+
return;
|
|
1430
|
+
}
|
|
1431
|
+
let hoverCursor = target.hoverCursor || this.hoverCursor;
|
|
1432
|
+
const activeSelection = isActiveSelection(this._activeObject)
|
|
1433
|
+
? this._activeObject
|
|
1434
|
+
: null,
|
|
1435
|
+
// only show proper corner when group selection is not active
|
|
1436
|
+
corner =
|
|
1437
|
+
(!activeSelection || !activeSelection.contains(target)) &&
|
|
1438
|
+
// here we call findTargetCorner always with undefined for the touch parameter.
|
|
1439
|
+
// we assume that if you are using a cursor you do not need to interact with
|
|
1440
|
+
// the bigger touch area.
|
|
1441
|
+
target._findTargetCorner(this.getPointer(e, true));
|
|
1442
|
+
|
|
1443
|
+
if (!corner) {
|
|
1444
|
+
if ((target as Group).subTargetCheck) {
|
|
1445
|
+
// hoverCursor should come from top-most subTarget,
|
|
1446
|
+
// so we walk the array backwards
|
|
1447
|
+
this.targets
|
|
1448
|
+
.concat()
|
|
1449
|
+
.reverse()
|
|
1450
|
+
.map((_target) => {
|
|
1451
|
+
hoverCursor = _target.hoverCursor || hoverCursor;
|
|
1452
|
+
});
|
|
1453
|
+
}
|
|
1454
|
+
this.setCursor(hoverCursor);
|
|
1455
|
+
} else {
|
|
1456
|
+
const control = target.controls[corner];
|
|
1457
|
+
this.setCursor(control.cursorStyleHandler(e, control, target));
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
// Grouping objects mixin
|
|
1462
|
+
|
|
1463
|
+
/**
|
|
1464
|
+
* Return true if the current mouse event that generated a new selection should generate a group
|
|
1465
|
+
* @private
|
|
1466
|
+
* @param {TPointerEvent} e Event object
|
|
1467
|
+
* @param {FabricObject} target
|
|
1468
|
+
* @return {Boolean}
|
|
1469
|
+
*/
|
|
1470
|
+
_shouldGroup(e: TPointerEvent, target?: FabricObject): boolean {
|
|
1471
|
+
const activeObject = this._activeObject;
|
|
1472
|
+
// check if an active object exists on canvas and if the user is pressing the `selectionKey` while canvas supports multi selection.
|
|
1473
|
+
return (
|
|
1474
|
+
!!activeObject &&
|
|
1475
|
+
this._isSelectionKeyPressed(e) &&
|
|
1476
|
+
this.selection &&
|
|
1477
|
+
// on top of that the user also has to hit a target that is selectable.
|
|
1478
|
+
!!target &&
|
|
1479
|
+
target.selectable &&
|
|
1480
|
+
// if all pre-requisite pass, the target is either something different from the current
|
|
1481
|
+
// activeObject or if an activeSelection already exists
|
|
1482
|
+
// TODO at time of writing why `activeObject.type === 'activeSelection'` matter is unclear.
|
|
1483
|
+
// is a very old condition uncertain if still valid.
|
|
1484
|
+
(activeObject !== target || activeObject.type === 'activeSelection') &&
|
|
1485
|
+
// make sure `activeObject` and `target` aren't ancestors of each other
|
|
1486
|
+
!target.isDescendantOf(activeObject) &&
|
|
1487
|
+
!activeObject.isDescendantOf(target) &&
|
|
1488
|
+
// target accepts selection
|
|
1489
|
+
!target.onSelect({ e: e })
|
|
1490
|
+
);
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1493
|
+
/**
|
|
1494
|
+
* Handles active selection creation for user event
|
|
1495
|
+
* @private
|
|
1496
|
+
* @param {TPointerEvent} e Event object
|
|
1497
|
+
* @param {FabricObject} target
|
|
1498
|
+
*/
|
|
1499
|
+
_handleGrouping(e: TPointerEvent, target: FabricObject) {
|
|
1500
|
+
let groupingTarget: FabricObject | undefined = target;
|
|
1501
|
+
// Called always a shouldGroup, meaning that we can trust this._activeObject exists.
|
|
1502
|
+
const activeObject = this._activeObject!;
|
|
1503
|
+
// avoid multi select when shift click on a corner
|
|
1504
|
+
if (activeObject.__corner) {
|
|
1505
|
+
return;
|
|
1506
|
+
}
|
|
1507
|
+
if (groupingTarget === activeObject) {
|
|
1508
|
+
// if it's a group, find target again, using activeGroup objects
|
|
1509
|
+
groupingTarget = this.findTarget(e, true);
|
|
1510
|
+
// if even object is not found or we are on activeObjectCorner, bail out
|
|
1511
|
+
if (!groupingTarget || !groupingTarget.selectable) {
|
|
1512
|
+
return;
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
if (activeObject && activeObject.type === 'activeSelection') {
|
|
1516
|
+
this._updateActiveSelection(e, groupingTarget);
|
|
1517
|
+
} else {
|
|
1518
|
+
this._createActiveSelection(e, groupingTarget);
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
/**
|
|
1523
|
+
* @private
|
|
1524
|
+
*/
|
|
1525
|
+
_updateActiveSelection(e: TPointerEvent, target: FabricObject) {
|
|
1526
|
+
const activeSelection = this._activeObject! as ActiveSelection,
|
|
1527
|
+
currentActiveObjects = activeSelection.getObjects();
|
|
1528
|
+
if (target.group === activeSelection) {
|
|
1529
|
+
activeSelection.remove(target);
|
|
1530
|
+
this._hoveredTarget = target;
|
|
1531
|
+
this._hoveredTargets = this.targets.concat();
|
|
1532
|
+
if (activeSelection.size() === 1) {
|
|
1533
|
+
// activate last remaining object
|
|
1534
|
+
this._setActiveObject(activeSelection.item(0) as FabricObject, e);
|
|
1535
|
+
}
|
|
1536
|
+
} else {
|
|
1537
|
+
activeSelection.add(target);
|
|
1538
|
+
this._hoveredTarget = activeSelection;
|
|
1539
|
+
this._hoveredTargets = this.targets.concat();
|
|
1540
|
+
}
|
|
1541
|
+
this._fireSelectionEvents(currentActiveObjects as FabricObject[], e);
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1544
|
+
/**
|
|
1545
|
+
* Generates and set as active the active selection from user events
|
|
1546
|
+
* @private
|
|
1547
|
+
*/
|
|
1548
|
+
_createActiveSelection(e: TPointerEvent, target: FabricObject) {
|
|
1549
|
+
const currentActive = this.getActiveObject()!;
|
|
1550
|
+
const groupObjects = target.isInFrontOf(currentActive)
|
|
1551
|
+
? [currentActive, target]
|
|
1552
|
+
: [target, currentActive];
|
|
1553
|
+
// @ts-ignore
|
|
1554
|
+
currentActive.isEditing && currentActive.exitEditing();
|
|
1555
|
+
// handle case: target is nested
|
|
1556
|
+
const newActiveSelection = new ActiveSelection(groupObjects, {
|
|
1557
|
+
canvas: this,
|
|
1558
|
+
});
|
|
1559
|
+
this._hoveredTarget = newActiveSelection;
|
|
1560
|
+
// ISSUE 4115: should we consider subTargets here?
|
|
1561
|
+
// this._hoveredTargets = [];
|
|
1562
|
+
// this._hoveredTargets = this.targets.concat();
|
|
1563
|
+
this._setActiveObject(newActiveSelection, e);
|
|
1564
|
+
this._fireSelectionEvents([currentActive], e);
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
/**
|
|
1568
|
+
* Finds objects inside the selection rectangle and group them
|
|
1569
|
+
* @private
|
|
1570
|
+
* @param {Event} e mouse event
|
|
1571
|
+
*/
|
|
1572
|
+
_groupSelectedObjects(e: TPointerEvent) {
|
|
1573
|
+
const group = this._collectObjects(e);
|
|
1574
|
+
// do not create group for 1 element only
|
|
1575
|
+
if (group.length === 1) {
|
|
1576
|
+
this.setActiveObject(group[0], e);
|
|
1577
|
+
} else if (group.length > 1) {
|
|
1578
|
+
const aGroup = new ActiveSelection(group.reverse(), {
|
|
1579
|
+
canvas: this,
|
|
1580
|
+
});
|
|
1581
|
+
this.setActiveObject(aGroup, e);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
/**
|
|
1586
|
+
* @private
|
|
1587
|
+
*/
|
|
1588
|
+
_collectObjects(e: TPointerEvent) {
|
|
1589
|
+
const group: FabricObject[] = [],
|
|
1590
|
+
_groupSelector = this._groupSelector,
|
|
1591
|
+
point1 = new Point(_groupSelector.ex, _groupSelector.ey),
|
|
1592
|
+
point2 = point1.add(new Point(_groupSelector.left, _groupSelector.top)),
|
|
1593
|
+
selectionX1Y1 = point1.min(point2),
|
|
1594
|
+
selectionX2Y2 = point1.max(point2),
|
|
1595
|
+
allowIntersect = !this.selectionFullyContained,
|
|
1596
|
+
isClick = point1.eq(point2);
|
|
1597
|
+
// we iterate reverse order to collect top first in case of click.
|
|
1598
|
+
for (let i = this._objects.length; i--; ) {
|
|
1599
|
+
const currentObject = this._objects[i];
|
|
1600
|
+
|
|
1601
|
+
if (
|
|
1602
|
+
!currentObject ||
|
|
1603
|
+
!currentObject.selectable ||
|
|
1604
|
+
!currentObject.visible
|
|
1605
|
+
) {
|
|
1606
|
+
continue;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
if (
|
|
1610
|
+
(allowIntersect &&
|
|
1611
|
+
currentObject.intersectsWithRect(
|
|
1612
|
+
selectionX1Y1,
|
|
1613
|
+
selectionX2Y2,
|
|
1614
|
+
true
|
|
1615
|
+
)) ||
|
|
1616
|
+
currentObject.isContainedWithinRect(
|
|
1617
|
+
selectionX1Y1,
|
|
1618
|
+
selectionX2Y2,
|
|
1619
|
+
true
|
|
1620
|
+
) ||
|
|
1621
|
+
(allowIntersect &&
|
|
1622
|
+
currentObject.containsPoint(selectionX1Y1, undefined, true)) ||
|
|
1623
|
+
(allowIntersect &&
|
|
1624
|
+
currentObject.containsPoint(selectionX2Y2, undefined, true))
|
|
1625
|
+
) {
|
|
1626
|
+
group.push(currentObject);
|
|
1627
|
+
// only add one object if it's a click
|
|
1628
|
+
if (isClick) {
|
|
1629
|
+
break;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
|
|
1634
|
+
if (group.length > 1) {
|
|
1635
|
+
return group.filter((object) => !object.onSelect({ e }));
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
return group;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
/**
|
|
1642
|
+
* @private
|
|
1643
|
+
*/
|
|
1644
|
+
_maybeGroupObjects(e: TPointerEvent) {
|
|
1645
|
+
if (this.selection && this._groupSelector) {
|
|
1646
|
+
this._groupSelectedObjects(e);
|
|
1647
|
+
}
|
|
1648
|
+
this.setCursor(this.defaultCursor);
|
|
1649
|
+
// clear selection and current transformation
|
|
1650
|
+
this._groupSelector = null;
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
exitTextEditing() {
|
|
1654
|
+
this.textEditingManager.exitTextEditing();
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
/**
|
|
1658
|
+
* @override clear {@link textEditingManager}
|
|
1659
|
+
*/
|
|
1660
|
+
clear() {
|
|
1661
|
+
this.textEditingManager.dispose();
|
|
1662
|
+
super.clear();
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
/**
|
|
1666
|
+
* @override clear {@link textEditingManager}
|
|
1667
|
+
*/
|
|
1668
|
+
destroy() {
|
|
1669
|
+
super.destroy();
|
|
1670
|
+
this.textEditingManager.dispose();
|
|
1671
|
+
}
|
|
1672
|
+
}
|