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
package/src/util/path.ts
ADDED
|
@@ -0,0 +1,941 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
|
|
3
|
+
import { cache } from '../cache';
|
|
4
|
+
import { config } from '../config';
|
|
5
|
+
import { halfPI, PiBy180 } from '../constants';
|
|
6
|
+
import { commaWsp, rePathCommand } from '../parser/constants';
|
|
7
|
+
import { Point } from '../Point';
|
|
8
|
+
import type { PathData, TMat2D } from '../typedefs';
|
|
9
|
+
import { cos } from './misc/cos';
|
|
10
|
+
import { multiplyTransformMatrices, transformPoint } from './misc/matrix';
|
|
11
|
+
import { sin } from './misc/sin';
|
|
12
|
+
|
|
13
|
+
type PathSegmentInfoCommon = {
|
|
14
|
+
x: number;
|
|
15
|
+
y: number;
|
|
16
|
+
command: string;
|
|
17
|
+
length: number;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type CurveInfo = PathSegmentInfoCommon & {
|
|
21
|
+
iterator: (pct: number) => Point;
|
|
22
|
+
angleFinder: (pct: number) => number;
|
|
23
|
+
length: number;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type PathSegmentInfo = {
|
|
27
|
+
M: PathSegmentInfoCommon;
|
|
28
|
+
L: PathSegmentInfoCommon;
|
|
29
|
+
C: CurveInfo;
|
|
30
|
+
Q: CurveInfo;
|
|
31
|
+
Z: PathSegmentInfoCommon & { destX: number; destY: number };
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export type TPathSegmentsInfo = PathSegmentInfo[keyof PathSegmentInfo];
|
|
35
|
+
|
|
36
|
+
const commandLengths = {
|
|
37
|
+
m: 2,
|
|
38
|
+
l: 2,
|
|
39
|
+
h: 1,
|
|
40
|
+
v: 1,
|
|
41
|
+
c: 6,
|
|
42
|
+
s: 4,
|
|
43
|
+
q: 4,
|
|
44
|
+
t: 2,
|
|
45
|
+
a: 7,
|
|
46
|
+
};
|
|
47
|
+
const repeatedCommands = {
|
|
48
|
+
m: 'l',
|
|
49
|
+
M: 'L',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const segmentToBezier = (
|
|
53
|
+
th2,
|
|
54
|
+
th3,
|
|
55
|
+
cosTh,
|
|
56
|
+
sinTh,
|
|
57
|
+
rx,
|
|
58
|
+
ry,
|
|
59
|
+
cx1,
|
|
60
|
+
cy1,
|
|
61
|
+
mT,
|
|
62
|
+
fromX,
|
|
63
|
+
fromY
|
|
64
|
+
) => {
|
|
65
|
+
const costh2 = cos(th2),
|
|
66
|
+
sinth2 = sin(th2),
|
|
67
|
+
costh3 = cos(th3),
|
|
68
|
+
sinth3 = sin(th3),
|
|
69
|
+
toX = cosTh * rx * costh3 - sinTh * ry * sinth3 + cx1,
|
|
70
|
+
toY = sinTh * rx * costh3 + cosTh * ry * sinth3 + cy1,
|
|
71
|
+
cp1X = fromX + mT * (-cosTh * rx * sinth2 - sinTh * ry * costh2),
|
|
72
|
+
cp1Y = fromY + mT * (-sinTh * rx * sinth2 + cosTh * ry * costh2),
|
|
73
|
+
cp2X = toX + mT * (cosTh * rx * sinth3 + sinTh * ry * costh3),
|
|
74
|
+
cp2Y = toY + mT * (sinTh * rx * sinth3 - cosTh * ry * costh3);
|
|
75
|
+
|
|
76
|
+
return ['C', cp1X, cp1Y, cp2X, cp2Y, toX, toY];
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/* Adapted from http://dxr.mozilla.org/mozilla-central/source/content/svg/content/src/nsSVGPathDataParser.cpp
|
|
80
|
+
* by Andrea Bogazzi code is under MPL. if you don't have a copy of the license you can take it here
|
|
81
|
+
* http://mozilla.org/MPL/2.0/
|
|
82
|
+
*/
|
|
83
|
+
const arcToSegments = (toX, toY, rx, ry, large, sweep, rotateX) => {
|
|
84
|
+
let fromX = 0,
|
|
85
|
+
fromY = 0,
|
|
86
|
+
root = 0;
|
|
87
|
+
const PI = Math.PI,
|
|
88
|
+
th = rotateX * PiBy180,
|
|
89
|
+
sinTh = sin(th),
|
|
90
|
+
cosTh = cos(th),
|
|
91
|
+
px = 0.5 * (-cosTh * toX - sinTh * toY),
|
|
92
|
+
py = 0.5 * (-cosTh * toY + sinTh * toX),
|
|
93
|
+
rx2 = rx ** 2,
|
|
94
|
+
ry2 = ry ** 2,
|
|
95
|
+
py2 = py ** 2,
|
|
96
|
+
px2 = px ** 2,
|
|
97
|
+
pl = rx2 * ry2 - rx2 * py2 - ry2 * px2;
|
|
98
|
+
let _rx = Math.abs(rx);
|
|
99
|
+
let _ry = Math.abs(ry);
|
|
100
|
+
|
|
101
|
+
if (pl < 0) {
|
|
102
|
+
const s = Math.sqrt(1 - pl / (rx2 * ry2));
|
|
103
|
+
_rx *= s;
|
|
104
|
+
_ry *= s;
|
|
105
|
+
} else {
|
|
106
|
+
root =
|
|
107
|
+
(large === sweep ? -1.0 : 1.0) * Math.sqrt(pl / (rx2 * py2 + ry2 * px2));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const cx = (root * _rx * py) / _ry,
|
|
111
|
+
cy = (-root * _ry * px) / _rx,
|
|
112
|
+
cx1 = cosTh * cx - sinTh * cy + toX * 0.5,
|
|
113
|
+
cy1 = sinTh * cx + cosTh * cy + toY * 0.5;
|
|
114
|
+
let mTheta = calcVectorAngle(1, 0, (px - cx) / _rx, (py - cy) / _ry);
|
|
115
|
+
let dtheta = calcVectorAngle(
|
|
116
|
+
(px - cx) / _rx,
|
|
117
|
+
(py - cy) / _ry,
|
|
118
|
+
(-px - cx) / _rx,
|
|
119
|
+
(-py - cy) / _ry
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
if (sweep === 0 && dtheta > 0) {
|
|
123
|
+
dtheta -= 2 * PI;
|
|
124
|
+
} else if (sweep === 1 && dtheta < 0) {
|
|
125
|
+
dtheta += 2 * PI;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Convert into cubic bezier segments <= 90deg
|
|
129
|
+
const segments = Math.ceil(Math.abs((dtheta / PI) * 2)),
|
|
130
|
+
result = new Array(segments),
|
|
131
|
+
mDelta = dtheta / segments,
|
|
132
|
+
mT =
|
|
133
|
+
((8 / 3) * Math.sin(mDelta / 4) * Math.sin(mDelta / 4)) /
|
|
134
|
+
Math.sin(mDelta / 2);
|
|
135
|
+
let th3 = mTheta + mDelta;
|
|
136
|
+
|
|
137
|
+
for (let i = 0; i < segments; i++) {
|
|
138
|
+
result[i] = segmentToBezier(
|
|
139
|
+
mTheta,
|
|
140
|
+
th3,
|
|
141
|
+
cosTh,
|
|
142
|
+
sinTh,
|
|
143
|
+
_rx,
|
|
144
|
+
_ry,
|
|
145
|
+
cx1,
|
|
146
|
+
cy1,
|
|
147
|
+
mT,
|
|
148
|
+
fromX,
|
|
149
|
+
fromY
|
|
150
|
+
);
|
|
151
|
+
fromX = result[i][5];
|
|
152
|
+
fromY = result[i][6];
|
|
153
|
+
mTheta = th3;
|
|
154
|
+
th3 += mDelta;
|
|
155
|
+
}
|
|
156
|
+
return result;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
/*
|
|
160
|
+
* Private
|
|
161
|
+
*/
|
|
162
|
+
const calcVectorAngle = (ux, uy, vx, vy) => {
|
|
163
|
+
const ta = Math.atan2(uy, ux),
|
|
164
|
+
tb = Math.atan2(vy, vx);
|
|
165
|
+
if (tb >= ta) {
|
|
166
|
+
return tb - ta;
|
|
167
|
+
} else {
|
|
168
|
+
return 2 * Math.PI - (ta - tb);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
// functions for the Cubic beizer
|
|
173
|
+
// taken from: https://github.com/konvajs/konva/blob/7.0.5/src/shapes/Path.ts#L350
|
|
174
|
+
const CB1 = (t) => t ** 3;
|
|
175
|
+
const CB2 = (t) => 3 * t ** 2 * (1 - t);
|
|
176
|
+
const CB3 = (t) => 3 * t * (1 - t) ** 2;
|
|
177
|
+
const CB4 = (t) => (1 - t) ** 3;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Calculate bounding box of a beziercurve
|
|
181
|
+
* @param {Number} x0 starting point
|
|
182
|
+
* @param {Number} y0
|
|
183
|
+
* @param {Number} x1 first control point
|
|
184
|
+
* @param {Number} y1
|
|
185
|
+
* @param {Number} x2 secondo control point
|
|
186
|
+
* @param {Number} y2
|
|
187
|
+
* @param {Number} x3 end of bezier
|
|
188
|
+
* @param {Number} y3
|
|
189
|
+
*/
|
|
190
|
+
// taken from http://jsbin.com/ivomiq/56/edit no credits available for that.
|
|
191
|
+
// TODO: can we normalize this with the starting points set at 0 and then translated the bbox?
|
|
192
|
+
export function getBoundsOfCurve(x0, y0, x1, y1, x2, y2, x3, y3) {
|
|
193
|
+
let argsString;
|
|
194
|
+
if (config.cachesBoundsOfCurve) {
|
|
195
|
+
// eslint-disable-next-line
|
|
196
|
+
argsString = [...arguments].join();
|
|
197
|
+
if (cache.boundsOfCurveCache[argsString]) {
|
|
198
|
+
return cache.boundsOfCurveCache[argsString];
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const sqrt = Math.sqrt,
|
|
203
|
+
abs = Math.abs,
|
|
204
|
+
tvalues = [],
|
|
205
|
+
bounds = [[], []];
|
|
206
|
+
|
|
207
|
+
let b = 6 * x0 - 12 * x1 + 6 * x2;
|
|
208
|
+
let a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
|
|
209
|
+
let c = 3 * x1 - 3 * x0;
|
|
210
|
+
|
|
211
|
+
for (let i = 0; i < 2; ++i) {
|
|
212
|
+
if (i > 0) {
|
|
213
|
+
b = 6 * y0 - 12 * y1 + 6 * y2;
|
|
214
|
+
a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
|
|
215
|
+
c = 3 * y1 - 3 * y0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (abs(a) < 1e-12) {
|
|
219
|
+
if (abs(b) < 1e-12) {
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
const t = -c / b;
|
|
223
|
+
if (0 < t && t < 1) {
|
|
224
|
+
tvalues.push(t);
|
|
225
|
+
}
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const b2ac = b * b - 4 * c * a;
|
|
229
|
+
if (b2ac < 0) {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
const sqrtb2ac = sqrt(b2ac);
|
|
233
|
+
const t1 = (-b + sqrtb2ac) / (2 * a);
|
|
234
|
+
if (0 < t1 && t1 < 1) {
|
|
235
|
+
tvalues.push(t1);
|
|
236
|
+
}
|
|
237
|
+
const t2 = (-b - sqrtb2ac) / (2 * a);
|
|
238
|
+
if (0 < t2 && t2 < 1) {
|
|
239
|
+
tvalues.push(t2);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
let j = tvalues.length;
|
|
244
|
+
const jlen = j;
|
|
245
|
+
const iterator = getPointOnCubicBezierIterator(
|
|
246
|
+
x0,
|
|
247
|
+
y0,
|
|
248
|
+
x1,
|
|
249
|
+
y1,
|
|
250
|
+
x2,
|
|
251
|
+
y2,
|
|
252
|
+
x3,
|
|
253
|
+
y3
|
|
254
|
+
);
|
|
255
|
+
while (j--) {
|
|
256
|
+
const { x, y } = iterator(tvalues[j]);
|
|
257
|
+
bounds[0][j] = x;
|
|
258
|
+
bounds[1][j] = y;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
bounds[0][jlen] = x0;
|
|
262
|
+
bounds[1][jlen] = y0;
|
|
263
|
+
bounds[0][jlen + 1] = x3;
|
|
264
|
+
bounds[1][jlen + 1] = y3;
|
|
265
|
+
const result = [
|
|
266
|
+
new Point(Math.min(...bounds[0]), Math.min(...bounds[1])),
|
|
267
|
+
new Point(Math.max(...bounds[0]), Math.max(...bounds[1])),
|
|
268
|
+
];
|
|
269
|
+
if (config.cachesBoundsOfCurve) {
|
|
270
|
+
cache.boundsOfCurveCache[argsString] = result;
|
|
271
|
+
}
|
|
272
|
+
return result;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Converts arc to a bunch of bezier curves
|
|
277
|
+
* @param {Number} fx starting point x
|
|
278
|
+
* @param {Number} fy starting point y
|
|
279
|
+
* @param {Array} coords Arc command
|
|
280
|
+
*/
|
|
281
|
+
export const fromArcToBeziers = (
|
|
282
|
+
fx,
|
|
283
|
+
fy,
|
|
284
|
+
[_, rx, ry, rot, large, sweep, tx, ty] = []
|
|
285
|
+
) => {
|
|
286
|
+
const segsNorm = arcToSegments(tx - fx, ty - fy, rx, ry, large, sweep, rot);
|
|
287
|
+
|
|
288
|
+
for (let i = 0, len = segsNorm.length; i < len; i++) {
|
|
289
|
+
segsNorm[i][1] += fx;
|
|
290
|
+
segsNorm[i][2] += fy;
|
|
291
|
+
segsNorm[i][3] += fx;
|
|
292
|
+
segsNorm[i][4] += fy;
|
|
293
|
+
segsNorm[i][5] += fx;
|
|
294
|
+
segsNorm[i][6] += fy;
|
|
295
|
+
}
|
|
296
|
+
return segsNorm;
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* This function take a parsed SVG path and make it simpler for fabricJS logic.
|
|
301
|
+
* simplification consist of: only UPPERCASE absolute commands ( relative converted to absolute )
|
|
302
|
+
* S converted in C, T converted in Q, A converted in C.
|
|
303
|
+
* @param {PathData} path the array of commands of a parsed svg path for `Path`
|
|
304
|
+
* @return {PathData} the simplified array of commands of a parsed svg path for `Path`
|
|
305
|
+
*/
|
|
306
|
+
export const makePathSimpler = (path: PathData): PathData => {
|
|
307
|
+
// x and y represent the last point of the path. the previous command point.
|
|
308
|
+
// we add them to each relative command to make it an absolute comment.
|
|
309
|
+
// we also swap the v V h H with L, because are easier to transform.
|
|
310
|
+
let x = 0,
|
|
311
|
+
y = 0;
|
|
312
|
+
const len = path.length;
|
|
313
|
+
// x1 and y1 represent the last point of the subpath. the subpath is started with
|
|
314
|
+
// m or M command. When a z or Z command is drawn, x and y need to be resetted to
|
|
315
|
+
// the last x1 and y1.
|
|
316
|
+
let x1 = 0,
|
|
317
|
+
y1 = 0;
|
|
318
|
+
// previous will host the letter of the previous command, to handle S and T.
|
|
319
|
+
// controlX and controlY will host the previous reflected control point
|
|
320
|
+
let destinationPath: PathData = [],
|
|
321
|
+
previous,
|
|
322
|
+
controlX,
|
|
323
|
+
controlY;
|
|
324
|
+
for (let i = 0; i < len; ++i) {
|
|
325
|
+
let converted = false;
|
|
326
|
+
const current = path[i].slice(0);
|
|
327
|
+
switch (
|
|
328
|
+
current[0] // first letter
|
|
329
|
+
) {
|
|
330
|
+
case 'l': // lineto, relative
|
|
331
|
+
current[0] = 'L';
|
|
332
|
+
current[1] += x;
|
|
333
|
+
current[2] += y;
|
|
334
|
+
// falls through
|
|
335
|
+
case 'L':
|
|
336
|
+
x = current[1];
|
|
337
|
+
y = current[2];
|
|
338
|
+
break;
|
|
339
|
+
case 'h': // horizontal lineto, relative
|
|
340
|
+
current[1] += x;
|
|
341
|
+
// falls through
|
|
342
|
+
case 'H':
|
|
343
|
+
current[0] = 'L';
|
|
344
|
+
current[2] = y;
|
|
345
|
+
x = current[1];
|
|
346
|
+
break;
|
|
347
|
+
case 'v': // vertical lineto, relative
|
|
348
|
+
current[1] += y;
|
|
349
|
+
// falls through
|
|
350
|
+
case 'V':
|
|
351
|
+
current[0] = 'L';
|
|
352
|
+
y = current[1];
|
|
353
|
+
current[1] = x;
|
|
354
|
+
current[2] = y;
|
|
355
|
+
break;
|
|
356
|
+
case 'm': // moveTo, relative
|
|
357
|
+
current[0] = 'M';
|
|
358
|
+
current[1] += x;
|
|
359
|
+
current[2] += y;
|
|
360
|
+
// falls through
|
|
361
|
+
case 'M':
|
|
362
|
+
x = current[1];
|
|
363
|
+
y = current[2];
|
|
364
|
+
x1 = current[1];
|
|
365
|
+
y1 = current[2];
|
|
366
|
+
break;
|
|
367
|
+
case 'c': // bezierCurveTo, relative
|
|
368
|
+
current[0] = 'C';
|
|
369
|
+
current[1] += x;
|
|
370
|
+
current[2] += y;
|
|
371
|
+
current[3] += x;
|
|
372
|
+
current[4] += y;
|
|
373
|
+
current[5] += x;
|
|
374
|
+
current[6] += y;
|
|
375
|
+
// falls through
|
|
376
|
+
case 'C':
|
|
377
|
+
controlX = current[3];
|
|
378
|
+
controlY = current[4];
|
|
379
|
+
x = current[5];
|
|
380
|
+
y = current[6];
|
|
381
|
+
break;
|
|
382
|
+
case 's': // shorthand cubic bezierCurveTo, relative
|
|
383
|
+
current[0] = 'S';
|
|
384
|
+
current[1] += x;
|
|
385
|
+
current[2] += y;
|
|
386
|
+
current[3] += x;
|
|
387
|
+
current[4] += y;
|
|
388
|
+
// falls through
|
|
389
|
+
case 'S':
|
|
390
|
+
// would be sScC but since we are swapping sSc for C, we check just that.
|
|
391
|
+
if (previous === 'C') {
|
|
392
|
+
// calculate reflection of previous control points
|
|
393
|
+
controlX = 2 * x - controlX;
|
|
394
|
+
controlY = 2 * y - controlY;
|
|
395
|
+
} else {
|
|
396
|
+
// If there is no previous command or if the previous command was not a C, c, S, or s,
|
|
397
|
+
// the control point is coincident with the current point
|
|
398
|
+
controlX = x;
|
|
399
|
+
controlY = y;
|
|
400
|
+
}
|
|
401
|
+
x = current[3];
|
|
402
|
+
y = current[4];
|
|
403
|
+
current[0] = 'C';
|
|
404
|
+
current[5] = current[3];
|
|
405
|
+
current[6] = current[4];
|
|
406
|
+
current[3] = current[1];
|
|
407
|
+
current[4] = current[2];
|
|
408
|
+
current[1] = controlX;
|
|
409
|
+
current[2] = controlY;
|
|
410
|
+
// current[3] and current[4] are NOW the second control point.
|
|
411
|
+
// we keep it for the next reflection.
|
|
412
|
+
controlX = current[3];
|
|
413
|
+
controlY = current[4];
|
|
414
|
+
break;
|
|
415
|
+
case 'q': // quadraticCurveTo, relative
|
|
416
|
+
current[0] = 'Q';
|
|
417
|
+
current[1] += x;
|
|
418
|
+
current[2] += y;
|
|
419
|
+
current[3] += x;
|
|
420
|
+
current[4] += y;
|
|
421
|
+
// falls through
|
|
422
|
+
case 'Q':
|
|
423
|
+
controlX = current[1];
|
|
424
|
+
controlY = current[2];
|
|
425
|
+
x = current[3];
|
|
426
|
+
y = current[4];
|
|
427
|
+
break;
|
|
428
|
+
case 't': // shorthand quadraticCurveTo, relative
|
|
429
|
+
current[0] = 'T';
|
|
430
|
+
current[1] += x;
|
|
431
|
+
current[2] += y;
|
|
432
|
+
// falls through
|
|
433
|
+
case 'T':
|
|
434
|
+
if (previous === 'Q') {
|
|
435
|
+
// calculate reflection of previous control point
|
|
436
|
+
controlX = 2 * x - controlX;
|
|
437
|
+
controlY = 2 * y - controlY;
|
|
438
|
+
} else {
|
|
439
|
+
// If there is no previous command or if the previous command was not a Q, q, T or t,
|
|
440
|
+
// assume the control point is coincident with the current point
|
|
441
|
+
controlX = x;
|
|
442
|
+
controlY = y;
|
|
443
|
+
}
|
|
444
|
+
current[0] = 'Q';
|
|
445
|
+
x = current[1];
|
|
446
|
+
y = current[2];
|
|
447
|
+
current[1] = controlX;
|
|
448
|
+
current[2] = controlY;
|
|
449
|
+
current[3] = x;
|
|
450
|
+
current[4] = y;
|
|
451
|
+
break;
|
|
452
|
+
case 'a':
|
|
453
|
+
current[0] = 'A';
|
|
454
|
+
current[6] += x;
|
|
455
|
+
current[7] += y;
|
|
456
|
+
// falls through
|
|
457
|
+
case 'A':
|
|
458
|
+
converted = true;
|
|
459
|
+
destinationPath = destinationPath.concat(
|
|
460
|
+
fromArcToBeziers(x, y, current)
|
|
461
|
+
);
|
|
462
|
+
x = current[6];
|
|
463
|
+
y = current[7];
|
|
464
|
+
break;
|
|
465
|
+
case 'z':
|
|
466
|
+
case 'Z':
|
|
467
|
+
x = x1;
|
|
468
|
+
y = y1;
|
|
469
|
+
break;
|
|
470
|
+
default:
|
|
471
|
+
}
|
|
472
|
+
if (!converted) {
|
|
473
|
+
destinationPath.push(current);
|
|
474
|
+
}
|
|
475
|
+
previous = current[0];
|
|
476
|
+
}
|
|
477
|
+
return destinationPath;
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
// todo verify if we can just use the point class here
|
|
481
|
+
/**
|
|
482
|
+
* Calc length from point x1,y1 to x2,y2
|
|
483
|
+
* @param {Number} x1 starting point x
|
|
484
|
+
* @param {Number} y1 starting point y
|
|
485
|
+
* @param {Number} x2 starting point x
|
|
486
|
+
* @param {Number} y2 starting point y
|
|
487
|
+
* @return {Number} length of segment
|
|
488
|
+
*/
|
|
489
|
+
const calcLineLength = (x1, y1, x2, y2) =>
|
|
490
|
+
Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
|
|
491
|
+
|
|
492
|
+
const getPointOnCubicBezierIterator =
|
|
493
|
+
(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) => (pct: number) => {
|
|
494
|
+
const c1 = CB1(pct),
|
|
495
|
+
c2 = CB2(pct),
|
|
496
|
+
c3 = CB3(pct),
|
|
497
|
+
c4 = CB4(pct);
|
|
498
|
+
return new Point(
|
|
499
|
+
p4x * c1 + p3x * c2 + p2x * c3 + p1x * c4,
|
|
500
|
+
p4y * c1 + p3y * c2 + p2y * c3 + p1y * c4
|
|
501
|
+
);
|
|
502
|
+
};
|
|
503
|
+
|
|
504
|
+
const QB1 = (t: number) => t ** 2;
|
|
505
|
+
const QB2 = (t: number) => 2 * t * (1 - t);
|
|
506
|
+
const QB3 = (t: number) => (1 - t) ** 2;
|
|
507
|
+
|
|
508
|
+
const getTangentCubicIterator =
|
|
509
|
+
(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) => (pct: number) => {
|
|
510
|
+
const qb1 = QB1(pct),
|
|
511
|
+
qb2 = QB2(pct),
|
|
512
|
+
qb3 = QB3(pct),
|
|
513
|
+
tangentX =
|
|
514
|
+
3 * (qb3 * (p2x - p1x) + qb2 * (p3x - p2x) + qb1 * (p4x - p3x)),
|
|
515
|
+
tangentY =
|
|
516
|
+
3 * (qb3 * (p2y - p1y) + qb2 * (p3y - p2y) + qb1 * (p4y - p3y));
|
|
517
|
+
return Math.atan2(tangentY, tangentX);
|
|
518
|
+
};
|
|
519
|
+
|
|
520
|
+
const getPointOnQuadraticBezierIterator =
|
|
521
|
+
(p1x, p1y, p2x, p2y, p3x, p3y) => (pct: number) => {
|
|
522
|
+
const c1 = QB1(pct),
|
|
523
|
+
c2 = QB2(pct),
|
|
524
|
+
c3 = QB3(pct);
|
|
525
|
+
return new Point(
|
|
526
|
+
p3x * c1 + p2x * c2 + p1x * c3,
|
|
527
|
+
p3y * c1 + p2y * c2 + p1y * c3
|
|
528
|
+
);
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
const getTangentQuadraticIterator = (p1x, p1y, p2x, p2y, p3x, p3y) => (pct) => {
|
|
532
|
+
const invT = 1 - pct,
|
|
533
|
+
tangentX = 2 * (invT * (p2x - p1x) + pct * (p3x - p2x)),
|
|
534
|
+
tangentY = 2 * (invT * (p2y - p1y) + pct * (p3y - p2y));
|
|
535
|
+
return Math.atan2(tangentY, tangentX);
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
// this will run over a path segment (a cubic or quadratic segment) and approximate it
|
|
539
|
+
// with 100 segments. This will good enough to calculate the length of the curve
|
|
540
|
+
const pathIterator = (
|
|
541
|
+
iterator: (pct: number) => Point,
|
|
542
|
+
x1: number,
|
|
543
|
+
y1: number
|
|
544
|
+
) => {
|
|
545
|
+
let tempP = new Point(x1, y1),
|
|
546
|
+
tmpLen = 0;
|
|
547
|
+
for (let perc = 1; perc <= 100; perc += 1) {
|
|
548
|
+
const p = iterator(perc / 100);
|
|
549
|
+
tmpLen += calcLineLength(tempP.x, tempP.y, p.x, p.y);
|
|
550
|
+
tempP = p;
|
|
551
|
+
}
|
|
552
|
+
return tmpLen;
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Given a pathInfo, and a distance in pixels, find the percentage from 0 to 1
|
|
557
|
+
* that correspond to that pixels run over the path.
|
|
558
|
+
* The percentage will be then used to find the correct point on the canvas for the path.
|
|
559
|
+
* @param {Array} segInfo fabricJS collection of information on a parsed path
|
|
560
|
+
* @param {Number} distance from starting point, in pixels.
|
|
561
|
+
* @return {Object} info object with x and y ( the point on canvas ) and angle, the tangent on that point;
|
|
562
|
+
*/
|
|
563
|
+
const findPercentageForDistance = (segInfo: CurveInfo, distance: number) => {
|
|
564
|
+
let perc = 0,
|
|
565
|
+
tmpLen = 0,
|
|
566
|
+
tempP = { x: segInfo.x, y: segInfo.y },
|
|
567
|
+
p,
|
|
568
|
+
nextLen,
|
|
569
|
+
nextStep = 0.01,
|
|
570
|
+
lastPerc;
|
|
571
|
+
// nextStep > 0.0001 covers 0.00015625 that 1/64th of 1/100
|
|
572
|
+
// the path
|
|
573
|
+
const iterator = segInfo.iterator,
|
|
574
|
+
angleFinder = segInfo.angleFinder;
|
|
575
|
+
while (tmpLen < distance && nextStep > 0.0001) {
|
|
576
|
+
p = iterator(perc);
|
|
577
|
+
lastPerc = perc;
|
|
578
|
+
nextLen = calcLineLength(tempP.x, tempP.y, p.x, p.y);
|
|
579
|
+
// compare tmpLen each cycle with distance, decide next perc to test.
|
|
580
|
+
if (nextLen + tmpLen > distance) {
|
|
581
|
+
// we discard this step and we make smaller steps.
|
|
582
|
+
perc -= nextStep;
|
|
583
|
+
nextStep /= 2;
|
|
584
|
+
} else {
|
|
585
|
+
tempP = p;
|
|
586
|
+
perc += nextStep;
|
|
587
|
+
tmpLen += nextLen;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
p.angle = angleFinder(lastPerc);
|
|
591
|
+
return p;
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Run over a parsed and simplified path and extract some information (length of each command and starting point)
|
|
596
|
+
* @param {PathData} path parsed path commands
|
|
597
|
+
* @return {Array} path commands information
|
|
598
|
+
*/
|
|
599
|
+
export const getPathSegmentsInfo = (path: PathData): TPathSegmentsInfo[] => {
|
|
600
|
+
let totalLength = 0,
|
|
601
|
+
current,
|
|
602
|
+
//x2 and y2 are the coords of segment start
|
|
603
|
+
//x1 and y1 are the coords of the current point
|
|
604
|
+
x1 = 0,
|
|
605
|
+
y1 = 0,
|
|
606
|
+
x2 = 0,
|
|
607
|
+
y2 = 0,
|
|
608
|
+
iterator,
|
|
609
|
+
tempInfo,
|
|
610
|
+
angleFinder;
|
|
611
|
+
const len = path.length,
|
|
612
|
+
info = [];
|
|
613
|
+
for (let i = 0; i < len; i++) {
|
|
614
|
+
current = path[i];
|
|
615
|
+
tempInfo = {
|
|
616
|
+
x: x1,
|
|
617
|
+
y: y1,
|
|
618
|
+
command: current[0] as string,
|
|
619
|
+
};
|
|
620
|
+
switch (
|
|
621
|
+
current[0] //first letter
|
|
622
|
+
) {
|
|
623
|
+
case 'M':
|
|
624
|
+
tempInfo.length = 0;
|
|
625
|
+
x2 = x1 = current[1];
|
|
626
|
+
y2 = y1 = current[2];
|
|
627
|
+
break;
|
|
628
|
+
case 'L':
|
|
629
|
+
tempInfo.length = calcLineLength(x1, y1, current[1], current[2]);
|
|
630
|
+
x1 = current[1];
|
|
631
|
+
y1 = current[2];
|
|
632
|
+
break;
|
|
633
|
+
case 'C':
|
|
634
|
+
iterator = getPointOnCubicBezierIterator(
|
|
635
|
+
x1,
|
|
636
|
+
y1,
|
|
637
|
+
current[1],
|
|
638
|
+
current[2],
|
|
639
|
+
current[3],
|
|
640
|
+
current[4],
|
|
641
|
+
current[5],
|
|
642
|
+
current[6]
|
|
643
|
+
);
|
|
644
|
+
angleFinder = getTangentCubicIterator(
|
|
645
|
+
x1,
|
|
646
|
+
y1,
|
|
647
|
+
current[1],
|
|
648
|
+
current[2],
|
|
649
|
+
current[3],
|
|
650
|
+
current[4],
|
|
651
|
+
current[5],
|
|
652
|
+
current[6]
|
|
653
|
+
);
|
|
654
|
+
tempInfo.iterator = iterator;
|
|
655
|
+
tempInfo.angleFinder = angleFinder;
|
|
656
|
+
tempInfo.length = pathIterator(iterator, x1, y1);
|
|
657
|
+
x1 = current[5];
|
|
658
|
+
y1 = current[6];
|
|
659
|
+
break;
|
|
660
|
+
case 'Q':
|
|
661
|
+
iterator = getPointOnQuadraticBezierIterator(
|
|
662
|
+
x1,
|
|
663
|
+
y1,
|
|
664
|
+
current[1],
|
|
665
|
+
current[2],
|
|
666
|
+
current[3],
|
|
667
|
+
current[4]
|
|
668
|
+
);
|
|
669
|
+
angleFinder = getTangentQuadraticIterator(
|
|
670
|
+
x1,
|
|
671
|
+
y1,
|
|
672
|
+
current[1],
|
|
673
|
+
current[2],
|
|
674
|
+
current[3],
|
|
675
|
+
current[4]
|
|
676
|
+
);
|
|
677
|
+
tempInfo.iterator = iterator;
|
|
678
|
+
tempInfo.angleFinder = angleFinder;
|
|
679
|
+
tempInfo.length = pathIterator(iterator, x1, y1);
|
|
680
|
+
x1 = current[3];
|
|
681
|
+
y1 = current[4];
|
|
682
|
+
break;
|
|
683
|
+
case 'Z':
|
|
684
|
+
case 'z':
|
|
685
|
+
// we add those in order to ease calculations later
|
|
686
|
+
tempInfo.destX = x2;
|
|
687
|
+
tempInfo.destY = y2;
|
|
688
|
+
tempInfo.length = calcLineLength(x1, y1, x2, y2);
|
|
689
|
+
x1 = x2;
|
|
690
|
+
y1 = y2;
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
totalLength += tempInfo.length;
|
|
694
|
+
info.push(tempInfo);
|
|
695
|
+
}
|
|
696
|
+
info.push({ length: totalLength, x: x1, y: y1 });
|
|
697
|
+
return info;
|
|
698
|
+
};
|
|
699
|
+
|
|
700
|
+
export const getPointOnPath = (
|
|
701
|
+
path: PathData,
|
|
702
|
+
distance: number,
|
|
703
|
+
infos: ReturnType<typeof getPathSegmentsInfo> = getPathSegmentsInfo(path)
|
|
704
|
+
) => {
|
|
705
|
+
let i = 0;
|
|
706
|
+
while (distance - infos[i].length > 0 && i < infos.length - 2) {
|
|
707
|
+
distance -= infos[i].length;
|
|
708
|
+
i++;
|
|
709
|
+
}
|
|
710
|
+
// var distance = infos[infos.length - 1] * perc;
|
|
711
|
+
const segInfo = infos[i],
|
|
712
|
+
segPercent = distance / segInfo.length,
|
|
713
|
+
command = segInfo.command,
|
|
714
|
+
segment = path[i];
|
|
715
|
+
let info;
|
|
716
|
+
|
|
717
|
+
switch (command) {
|
|
718
|
+
case 'M':
|
|
719
|
+
return { x: segInfo.x, y: segInfo.y, angle: 0 };
|
|
720
|
+
case 'Z':
|
|
721
|
+
case 'z':
|
|
722
|
+
info = new Point(segInfo.x, segInfo.y).lerp(
|
|
723
|
+
new Point(segInfo.destX, segInfo.destY),
|
|
724
|
+
segPercent
|
|
725
|
+
);
|
|
726
|
+
info.angle = Math.atan2(
|
|
727
|
+
segInfo.destY - segInfo.y,
|
|
728
|
+
segInfo.destX - segInfo.x
|
|
729
|
+
);
|
|
730
|
+
return info;
|
|
731
|
+
case 'L':
|
|
732
|
+
info = new Point(segInfo.x, segInfo.y).lerp(
|
|
733
|
+
new Point(segment[1], segment[2]),
|
|
734
|
+
segPercent
|
|
735
|
+
);
|
|
736
|
+
info.angle = Math.atan2(segment[2] - segInfo.y, segment[1] - segInfo.x);
|
|
737
|
+
return info;
|
|
738
|
+
case 'C':
|
|
739
|
+
return findPercentageForDistance(segInfo, distance);
|
|
740
|
+
case 'Q':
|
|
741
|
+
return findPercentageForDistance(segInfo, distance);
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
|
|
745
|
+
/**
|
|
746
|
+
*
|
|
747
|
+
* @param {string} pathString
|
|
748
|
+
* @return {(string|number)[][]} An array of SVG path commands
|
|
749
|
+
* @example <caption>Usage</caption>
|
|
750
|
+
* parsePath('M 3 4 Q 3 5 2 1 4 0 Q 9 12 2 1 4 0') === [
|
|
751
|
+
* ['M', 3, 4],
|
|
752
|
+
* ['Q', 3, 5, 2, 1, 4, 0],
|
|
753
|
+
* ['Q', 9, 12, 2, 1, 4, 0],
|
|
754
|
+
* ];
|
|
755
|
+
*
|
|
756
|
+
*/
|
|
757
|
+
export const parsePath = (pathString) => {
|
|
758
|
+
// one of commands (m,M,l,L,q,Q,c,C,etc.) followed by non-command characters (i.e. command values)
|
|
759
|
+
const re = rePathCommand,
|
|
760
|
+
rNumber = '[-+]?(?:\\d*\\.\\d+|\\d+\\.?)(?:[eE][-+]?\\d+)?\\s*',
|
|
761
|
+
rNumberCommaWsp = `(${rNumber})${commaWsp}`,
|
|
762
|
+
rFlagCommaWsp = `([01])${commaWsp}?`,
|
|
763
|
+
rArcSeq = `${rNumberCommaWsp}?${rNumberCommaWsp}?${rNumberCommaWsp}${rFlagCommaWsp}${rFlagCommaWsp}${rNumberCommaWsp}?(${rNumber})`,
|
|
764
|
+
regArcArgumentSequence = new RegExp(rArcSeq, 'g'),
|
|
765
|
+
result = [];
|
|
766
|
+
|
|
767
|
+
if (!pathString || !pathString.match) {
|
|
768
|
+
return result;
|
|
769
|
+
}
|
|
770
|
+
const path = pathString.match(/[mzlhvcsqta][^mzlhvcsqta]*/gi);
|
|
771
|
+
|
|
772
|
+
for (let i = 0, len = path.length; i < len; i++) {
|
|
773
|
+
const currentPath = path[i];
|
|
774
|
+
const coordsStr = currentPath.slice(1).trim();
|
|
775
|
+
const coords = [];
|
|
776
|
+
let command = currentPath.charAt(0);
|
|
777
|
+
const coordsParsed = [command];
|
|
778
|
+
|
|
779
|
+
if (command.toLowerCase() === 'a') {
|
|
780
|
+
// arcs have special flags that apparently don't require spaces so handle special
|
|
781
|
+
for (let args; (args = regArcArgumentSequence.exec(coordsStr)); ) {
|
|
782
|
+
for (let j = 1; j < args.length; j++) {
|
|
783
|
+
coords.push(args[j]);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
} else {
|
|
787
|
+
let match;
|
|
788
|
+
while ((match = re.exec(coordsStr))) {
|
|
789
|
+
coords.push(match[0]);
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
for (let j = 0, jlen = coords.length; j < jlen; j++) {
|
|
794
|
+
const parsed = parseFloat(coords[j]);
|
|
795
|
+
if (!isNaN(parsed)) {
|
|
796
|
+
coordsParsed.push(parsed);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
const commandLength = commandLengths[command.toLowerCase()],
|
|
801
|
+
repeatedCommand = repeatedCommands[command] || command;
|
|
802
|
+
|
|
803
|
+
if (coordsParsed.length - 1 > commandLength) {
|
|
804
|
+
for (
|
|
805
|
+
let k = 1, klen = coordsParsed.length;
|
|
806
|
+
k < klen;
|
|
807
|
+
k += commandLength
|
|
808
|
+
) {
|
|
809
|
+
result.push([command].concat(coordsParsed.slice(k, k + commandLength)));
|
|
810
|
+
command = repeatedCommand;
|
|
811
|
+
}
|
|
812
|
+
} else {
|
|
813
|
+
result.push(coordsParsed);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return result;
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
/**
|
|
820
|
+
*
|
|
821
|
+
* Converts points to a smooth SVG path
|
|
822
|
+
* @param {{ x: number,y: number }[]} points Array of points
|
|
823
|
+
* @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.
|
|
824
|
+
* @return {(string|number)[][]} An array of SVG path commands
|
|
825
|
+
*/
|
|
826
|
+
export const getSmoothPathFromPoints = (points, correction = 0) => {
|
|
827
|
+
let p1 = new Point(points[0]),
|
|
828
|
+
p2 = new Point(points[1]),
|
|
829
|
+
multSignX = 1,
|
|
830
|
+
multSignY = 0;
|
|
831
|
+
const path = [],
|
|
832
|
+
len = points.length,
|
|
833
|
+
manyPoints = len > 2;
|
|
834
|
+
|
|
835
|
+
if (manyPoints) {
|
|
836
|
+
multSignX = points[2].x < p2.x ? -1 : points[2].x === p2.x ? 0 : 1;
|
|
837
|
+
multSignY = points[2].y < p2.y ? -1 : points[2].y === p2.y ? 0 : 1;
|
|
838
|
+
}
|
|
839
|
+
path.push([
|
|
840
|
+
'M',
|
|
841
|
+
p1.x - multSignX * correction,
|
|
842
|
+
p1.y - multSignY * correction,
|
|
843
|
+
]);
|
|
844
|
+
let i;
|
|
845
|
+
for (i = 1; i < len; i++) {
|
|
846
|
+
if (!p1.eq(p2)) {
|
|
847
|
+
const midPoint = p1.midPointFrom(p2);
|
|
848
|
+
// p1 is our bezier control point
|
|
849
|
+
// midpoint is our endpoint
|
|
850
|
+
// start point is p(i-1) value.
|
|
851
|
+
path.push(['Q', p1.x, p1.y, midPoint.x, midPoint.y]);
|
|
852
|
+
}
|
|
853
|
+
p1 = points[i];
|
|
854
|
+
if (i + 1 < points.length) {
|
|
855
|
+
p2 = points[i + 1];
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
if (manyPoints) {
|
|
859
|
+
multSignX = p1.x > points[i - 2].x ? 1 : p1.x === points[i - 2].x ? 0 : -1;
|
|
860
|
+
multSignY = p1.y > points[i - 2].y ? 1 : p1.y === points[i - 2].y ? 0 : -1;
|
|
861
|
+
}
|
|
862
|
+
path.push([
|
|
863
|
+
'L',
|
|
864
|
+
p1.x + multSignX * correction,
|
|
865
|
+
p1.y + multSignY * correction,
|
|
866
|
+
]);
|
|
867
|
+
return path;
|
|
868
|
+
};
|
|
869
|
+
|
|
870
|
+
/**
|
|
871
|
+
* Transform a path by transforming each segment.
|
|
872
|
+
* it has to be a simplified path or it won't work.
|
|
873
|
+
* WARNING: this depends from pathOffset for correct operation
|
|
874
|
+
* @param {PathData} path fabricJS parsed and simplified path commands
|
|
875
|
+
* @param {TMat2D} transform matrix that represent the transformation
|
|
876
|
+
* @param {Point} [pathOffset] `Path.pathOffset`
|
|
877
|
+
* @returns {Array} the transformed path
|
|
878
|
+
*/
|
|
879
|
+
export const transformPath = (
|
|
880
|
+
path: PathData,
|
|
881
|
+
transform: TMat2D,
|
|
882
|
+
pathOffset: Point
|
|
883
|
+
) => {
|
|
884
|
+
if (pathOffset) {
|
|
885
|
+
transform = multiplyTransformMatrices(transform, [
|
|
886
|
+
1,
|
|
887
|
+
0,
|
|
888
|
+
0,
|
|
889
|
+
1,
|
|
890
|
+
-pathOffset.x,
|
|
891
|
+
-pathOffset.y,
|
|
892
|
+
]);
|
|
893
|
+
}
|
|
894
|
+
return path.map((pathSegment) => {
|
|
895
|
+
const newSegment = pathSegment.slice(0);
|
|
896
|
+
for (let i = 1; i < pathSegment.length - 1; i += 2) {
|
|
897
|
+
const { x, y } = transformPoint(
|
|
898
|
+
{
|
|
899
|
+
x: pathSegment[i],
|
|
900
|
+
y: pathSegment[i + 1],
|
|
901
|
+
},
|
|
902
|
+
transform
|
|
903
|
+
);
|
|
904
|
+
newSegment[i] = x;
|
|
905
|
+
newSegment[i + 1] = y;
|
|
906
|
+
}
|
|
907
|
+
return newSegment;
|
|
908
|
+
});
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
/**
|
|
912
|
+
* Returns an array of path commands to create a regular polygon
|
|
913
|
+
* @param {number} radius
|
|
914
|
+
* @param {number} numVertexes
|
|
915
|
+
* @returns {(string|number)[][]} An array of SVG path commands
|
|
916
|
+
*/
|
|
917
|
+
export const getRegularPolygonPath = (numVertexes, radius) => {
|
|
918
|
+
const interiorAngle = (Math.PI * 2) / numVertexes;
|
|
919
|
+
// rotationAdjustment rotates the path by 1/2 the interior angle so that the polygon always has a flat side on the bottom
|
|
920
|
+
// This isn't strictly necessary, but it's how we tend to think of and expect polygons to be drawn
|
|
921
|
+
let rotationAdjustment = -halfPI;
|
|
922
|
+
if (numVertexes % 2 === 0) {
|
|
923
|
+
rotationAdjustment += interiorAngle / 2;
|
|
924
|
+
}
|
|
925
|
+
const d = new Array(numVertexes + 1);
|
|
926
|
+
for (let i = 0; i < numVertexes; i++) {
|
|
927
|
+
const rad = i * interiorAngle + rotationAdjustment;
|
|
928
|
+
const { x, y } = new Point(cos(rad), sin(rad)).scalarMultiply(radius);
|
|
929
|
+
d[i] = [i === 0 ? 'M' : 'L', x, y];
|
|
930
|
+
}
|
|
931
|
+
d[numVertexes] = ['Z'];
|
|
932
|
+
return d;
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
/**
|
|
936
|
+
* Join path commands to go back to svg format
|
|
937
|
+
* @param {Array} pathData fabricJS parsed path commands
|
|
938
|
+
* @return {String} joined path 'M 0 0 L 20 30'
|
|
939
|
+
*/
|
|
940
|
+
export const joinPath = (pathData) =>
|
|
941
|
+
pathData.map((segment) => segment.join(' ')).join(' ');
|