fabric 7.0.0 → 7.2.0
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/.husky/pre-commit +1 -0
- package/CHANGELOG.md +21 -0
- package/dist/extensions/cropping_controls/croppingControls.d.ts +16 -0
- package/dist/extensions/cropping_controls/croppingControls.d.ts.map +1 -0
- package/dist/extensions/cropping_controls/croppingHandlers.d.ts +39 -0
- package/dist/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -0
- package/dist/extensions/cropping_controls/enterCropMode.d.ts +7 -0
- package/dist/extensions/cropping_controls/enterCropMode.d.ts.map +1 -0
- package/dist/extensions/cropping_controls/renderCornerControl.d.ts +14 -0
- package/dist/extensions/cropping_controls/renderCornerControl.d.ts.map +1 -0
- package/dist/extensions/index.d.ts +3 -0
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/fabric.d.ts +1 -0
- package/dist/fabric.d.ts.map +1 -1
- package/dist/index.js +628 -537
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/index.min.mjs +1 -1
- package/dist/index.min.mjs.map +1 -1
- package/dist/index.mjs +628 -537
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +628 -537
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +628 -537
- package/dist/index.node.mjs.map +1 -1
- package/dist/package.json.min.mjs +1 -1
- package/dist/package.json.mjs +1 -1
- package/dist/src/EventTypeDefs.d.ts +5 -0
- package/dist/src/EventTypeDefs.d.ts.map +1 -1
- package/dist/src/Pattern/Pattern.d.ts.map +1 -1
- package/dist/src/Pattern/Pattern.min.mjs +1 -1
- package/dist/src/Pattern/Pattern.min.mjs.map +1 -1
- package/dist/src/Pattern/Pattern.mjs +2 -1
- package/dist/src/Pattern/Pattern.mjs.map +1 -1
- package/dist/src/Shadow.d.ts +1 -1
- package/dist/src/Shadow.d.ts.map +1 -1
- package/dist/src/Shadow.min.mjs +1 -1
- package/dist/src/Shadow.min.mjs.map +1 -1
- package/dist/src/Shadow.mjs +5 -4
- package/dist/src/Shadow.mjs.map +1 -1
- package/dist/src/canvas/CanvasOptions.d.ts.map +1 -1
- package/dist/src/canvas/CanvasOptions.min.mjs.map +1 -1
- package/dist/src/canvas/CanvasOptions.mjs.map +1 -1
- package/dist/src/canvas/SelectableCanvas.d.ts +2 -0
- package/dist/src/canvas/SelectableCanvas.d.ts.map +1 -1
- package/dist/src/canvas/SelectableCanvas.min.mjs +1 -1
- package/dist/src/canvas/SelectableCanvas.min.mjs.map +1 -1
- package/dist/src/canvas/SelectableCanvas.mjs +33 -13
- package/dist/src/canvas/SelectableCanvas.mjs.map +1 -1
- package/dist/src/canvas/StaticCanvas.d.ts.map +1 -1
- package/dist/src/canvas/StaticCanvas.min.mjs +1 -1
- package/dist/src/canvas/StaticCanvas.min.mjs.map +1 -1
- package/dist/src/canvas/StaticCanvas.mjs +3 -1
- package/dist/src/canvas/StaticCanvas.mjs.map +1 -1
- package/dist/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
- package/dist/src/canvas/StaticCanvasOptions.min.mjs.map +1 -1
- package/dist/src/canvas/StaticCanvasOptions.mjs.map +1 -1
- package/dist/src/constants.d.ts +1 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.min.mjs.map +1 -1
- package/dist/src/constants.mjs.map +1 -1
- package/dist/src/controls/Control.d.ts +22 -1
- package/dist/src/controls/Control.d.ts.map +1 -1
- package/dist/src/controls/Control.min.mjs +1 -1
- package/dist/src/controls/Control.min.mjs.map +1 -1
- package/dist/src/controls/Control.mjs +45 -1
- package/dist/src/controls/Control.mjs.map +1 -1
- package/dist/src/controls/changeWidth.d.ts +22 -0
- package/dist/src/controls/changeWidth.d.ts.map +1 -1
- package/dist/src/controls/changeWidth.min.mjs +1 -1
- package/dist/src/controls/changeWidth.min.mjs.map +1 -1
- package/dist/src/controls/changeWidth.mjs +46 -18
- package/dist/src/controls/changeWidth.mjs.map +1 -1
- package/dist/src/controls/controlRendering.d.ts.map +1 -1
- package/dist/src/controls/controlRendering.min.mjs +1 -1
- package/dist/src/controls/controlRendering.min.mjs.map +1 -1
- package/dist/src/controls/controlRendering.mjs +18 -34
- package/dist/src/controls/controlRendering.mjs.map +1 -1
- package/dist/src/controls/index.d.ts +2 -1
- package/dist/src/controls/index.d.ts.map +1 -1
- package/dist/src/controls/index.min.mjs +1 -1
- package/dist/src/controls/index.mjs +1 -1
- package/dist/src/gradient/Gradient.d.ts.map +1 -1
- package/dist/src/gradient/Gradient.min.mjs +1 -1
- package/dist/src/gradient/Gradient.min.mjs.map +1 -1
- package/dist/src/gradient/Gradient.mjs +19 -6
- package/dist/src/gradient/Gradient.mjs.map +1 -1
- package/dist/src/shapes/Circle.d.ts.map +1 -1
- package/dist/src/shapes/Circle.min.mjs +1 -1
- package/dist/src/shapes/Circle.min.mjs.map +1 -1
- package/dist/src/shapes/Circle.mjs +10 -7
- package/dist/src/shapes/Circle.mjs.map +1 -1
- package/dist/src/shapes/Ellipse.d.ts.map +1 -1
- package/dist/src/shapes/Ellipse.min.mjs +1 -1
- package/dist/src/shapes/Ellipse.min.mjs.map +1 -1
- package/dist/src/shapes/Ellipse.mjs +2 -1
- package/dist/src/shapes/Ellipse.mjs.map +1 -1
- package/dist/src/shapes/Group.d.ts.map +1 -1
- package/dist/src/shapes/Group.min.mjs +1 -1
- package/dist/src/shapes/Group.min.mjs.map +1 -1
- package/dist/src/shapes/Group.mjs +2 -1
- package/dist/src/shapes/Group.mjs.map +1 -1
- package/dist/src/shapes/IText/IText.d.ts.map +1 -1
- package/dist/src/shapes/IText/IText.min.mjs.map +1 -1
- package/dist/src/shapes/IText/IText.mjs.map +1 -1
- package/dist/src/shapes/Image.d.ts +1 -1
- package/dist/src/shapes/Image.d.ts.map +1 -1
- package/dist/src/shapes/Image.min.mjs +1 -1
- package/dist/src/shapes/Image.min.mjs.map +1 -1
- package/dist/src/shapes/Image.mjs +4 -3
- package/dist/src/shapes/Image.mjs.map +1 -1
- package/dist/src/shapes/Line.d.ts.map +1 -1
- package/dist/src/shapes/Line.min.mjs +1 -1
- package/dist/src/shapes/Line.min.mjs.map +1 -1
- package/dist/src/shapes/Line.mjs +6 -10
- package/dist/src/shapes/Line.mjs.map +1 -1
- package/dist/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
- package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs +1 -1
- package/dist/src/shapes/Object/FabricObjectSVGExportMixin.min.mjs.map +1 -1
- package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs +5 -4
- package/dist/src/shapes/Object/FabricObjectSVGExportMixin.mjs.map +1 -1
- package/dist/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
- package/dist/src/shapes/Object/InteractiveObject.min.mjs.map +1 -1
- package/dist/src/shapes/Object/InteractiveObject.mjs.map +1 -1
- package/dist/src/shapes/Object/Object.d.ts.map +1 -1
- package/dist/src/shapes/Object/Object.min.mjs +1 -1
- package/dist/src/shapes/Object/Object.min.mjs.map +1 -1
- package/dist/src/shapes/Object/Object.mjs +3 -0
- package/dist/src/shapes/Object/Object.mjs.map +1 -1
- package/dist/src/shapes/Object/ObjectGeometry.min.mjs +1 -1
- package/dist/src/shapes/Object/ObjectGeometry.min.mjs.map +1 -1
- package/dist/src/shapes/Object/ObjectGeometry.mjs +1 -1
- package/dist/src/shapes/Object/ObjectGeometry.mjs.map +1 -1
- package/dist/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
- package/dist/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
- package/dist/src/shapes/Path.d.ts.map +1 -1
- package/dist/src/shapes/Path.min.mjs.map +1 -1
- package/dist/src/shapes/Path.mjs +1 -2
- package/dist/src/shapes/Path.mjs.map +1 -1
- package/dist/src/shapes/Polyline.d.ts.map +1 -1
- package/dist/src/shapes/Polyline.min.mjs +1 -1
- package/dist/src/shapes/Polyline.min.mjs.map +1 -1
- package/dist/src/shapes/Polyline.mjs +10 -6
- package/dist/src/shapes/Polyline.mjs.map +1 -1
- package/dist/src/shapes/Rect.d.ts.map +1 -1
- package/dist/src/shapes/Rect.min.mjs +1 -1
- package/dist/src/shapes/Rect.min.mjs.map +1 -1
- package/dist/src/shapes/Rect.mjs +2 -1
- package/dist/src/shapes/Rect.mjs.map +1 -1
- package/dist/src/shapes/Text/StyledText.d.ts.map +1 -1
- package/dist/src/shapes/Text/StyledText.min.mjs.map +1 -1
- package/dist/src/shapes/Text/StyledText.mjs +0 -3
- package/dist/src/shapes/Text/StyledText.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist/src/shapes/Text/Text.min.mjs.map +1 -1
- package/dist/src/shapes/Text/Text.mjs.map +1 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.d.ts.map +1 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs +1 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.min.mjs.map +1 -1
- package/dist/src/shapes/Text/TextSVGExportMixin.mjs +5 -6
- package/dist/src/shapes/Text/TextSVGExportMixin.mjs.map +1 -1
- package/dist/src/shapes/Textbox.d.ts.map +1 -1
- package/dist/src/shapes/Textbox.min.mjs.map +1 -1
- package/dist/src/shapes/Textbox.mjs.map +1 -1
- package/dist/src/shapes/Triangle.d.ts.map +1 -1
- package/dist/src/shapes/Triangle.min.mjs.map +1 -1
- package/dist/src/shapes/Triangle.mjs.map +1 -1
- package/dist/src/util/lang_string.d.ts +1 -1
- package/dist/src/util/lang_string.d.ts.map +1 -1
- package/dist/src/util/lang_string.min.mjs +1 -1
- package/dist/src/util/lang_string.min.mjs.map +1 -1
- package/dist/src/util/lang_string.mjs +1 -1
- package/dist/src/util/lang_string.mjs.map +1 -1
- package/dist/src/util/misc/svgParsing.d.ts.map +1 -1
- package/dist/src/util/misc/svgParsing.min.mjs +1 -1
- package/dist/src/util/misc/svgParsing.min.mjs.map +1 -1
- package/dist/src/util/misc/svgParsing.mjs +2 -1
- package/dist/src/util/misc/svgParsing.mjs.map +1 -1
- package/dist-extensions/cropping_controls/croppingControls.mjs +140 -0
- package/dist-extensions/cropping_controls/croppingControls.mjs.map +1 -0
- package/dist-extensions/cropping_controls/croppingHandlers.mjs +228 -0
- package/dist-extensions/cropping_controls/croppingHandlers.mjs.map +1 -0
- package/dist-extensions/cropping_controls/enterCropMode.mjs +38 -0
- package/dist-extensions/cropping_controls/enterCropMode.mjs.map +1 -0
- package/dist-extensions/cropping_controls/renderCornerControl.mjs +45 -0
- package/dist-extensions/cropping_controls/renderCornerControl.mjs.map +1 -0
- package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts +16 -0
- package/dist-extensions/extensions/cropping_controls/croppingControls.d.ts.map +1 -0
- package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts +39 -0
- package/dist-extensions/extensions/cropping_controls/croppingHandlers.d.ts.map +1 -0
- package/dist-extensions/extensions/cropping_controls/enterCropMode.d.ts +7 -0
- package/dist-extensions/extensions/cropping_controls/enterCropMode.d.ts.map +1 -0
- package/dist-extensions/extensions/cropping_controls/renderCornerControl.d.ts +14 -0
- package/dist-extensions/extensions/cropping_controls/renderCornerControl.d.ts.map +1 -0
- package/dist-extensions/extensions/index.d.ts +3 -0
- package/dist-extensions/extensions/index.d.ts.map +1 -1
- package/dist-extensions/fabric-extensions.min.js +1 -1
- package/dist-extensions/fabric-extensions.min.js.map +1 -1
- package/dist-extensions/fabric.d.ts +1 -0
- package/dist-extensions/fabric.d.ts.map +1 -1
- package/dist-extensions/index.mjs +3 -0
- package/dist-extensions/index.mjs.map +1 -1
- package/dist-extensions/src/EventTypeDefs.d.ts +5 -0
- package/dist-extensions/src/EventTypeDefs.d.ts.map +1 -1
- package/dist-extensions/src/Pattern/Pattern.d.ts.map +1 -1
- package/dist-extensions/src/Shadow.d.ts +1 -1
- package/dist-extensions/src/Shadow.d.ts.map +1 -1
- package/dist-extensions/src/canvas/CanvasOptions.d.ts.map +1 -1
- package/dist-extensions/src/canvas/SelectableCanvas.d.ts +2 -0
- package/dist-extensions/src/canvas/SelectableCanvas.d.ts.map +1 -1
- package/dist-extensions/src/canvas/StaticCanvas.d.ts.map +1 -1
- package/dist-extensions/src/canvas/StaticCanvasOptions.d.ts.map +1 -1
- package/dist-extensions/src/constants.d.ts +1 -0
- package/dist-extensions/src/constants.d.ts.map +1 -1
- package/dist-extensions/src/controls/Control.d.ts +22 -1
- package/dist-extensions/src/controls/Control.d.ts.map +1 -1
- package/dist-extensions/src/controls/changeWidth.d.ts +22 -0
- package/dist-extensions/src/controls/changeWidth.d.ts.map +1 -1
- package/dist-extensions/src/controls/controlRendering.d.ts.map +1 -1
- package/dist-extensions/src/controls/index.d.ts +2 -1
- package/dist-extensions/src/controls/index.d.ts.map +1 -1
- package/dist-extensions/src/gradient/Gradient.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Circle.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Ellipse.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Group.d.ts.map +1 -1
- package/dist-extensions/src/shapes/IText/IText.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Image.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Line.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Object/FabricObjectSVGExportMixin.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Object/InteractiveObject.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Object/Object.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Object/types/FabricObjectProps.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Object/types/ObjectProps.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Path.d.ts +1 -1
- package/dist-extensions/src/shapes/Path.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Polyline.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Rect.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/StyledText.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/Text.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Text/TextSVGExportMixin.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Textbox.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Triangle.d.ts.map +1 -1
- package/dist-extensions/src/util/lang_string.d.ts +1 -1
- package/dist-extensions/src/util/lang_string.d.ts.map +1 -1
- package/dist-extensions/src/util/misc/svgParsing.d.ts.map +1 -1
- package/eslint.config.mjs +2 -0
- package/extensions/cropping_controls/croppingControls.spec.ts +115 -0
- package/extensions/cropping_controls/croppingControls.ts +150 -0
- package/extensions/cropping_controls/croppingHandlers.spec.ts +579 -0
- package/extensions/cropping_controls/croppingHandlers.ts +285 -0
- package/extensions/cropping_controls/enterCropMode.ts +30 -0
- package/extensions/cropping_controls/renderCornerControl.ts +53 -0
- package/extensions/index.ts +9 -0
- package/fabric.ts +1 -0
- package/package.json +17 -8
- package/src/ClassRegistry.spec.ts +18 -19
- package/src/EventTypeDefs.ts +15 -11
- package/src/Pattern/Pattern.spec.ts +12 -0
- package/src/Pattern/Pattern.ts +3 -2
- package/src/Shadow.ts +9 -8
- package/src/brushes/PencilBrush.spec.ts +11 -11
- package/src/canvas/Canvas-dispose.spec.ts +8 -7
- package/src/canvas/Canvas.spec.ts +27 -29
- package/src/canvas/CanvasOptions.ts +2 -1
- package/src/canvas/SelectableCanvas.ts +38 -15
- package/src/canvas/StaticCanvas.spec.ts +20 -0
- package/src/canvas/StaticCanvas.ts +7 -4
- package/src/canvas/StaticCanvasOptions.ts +1 -3
- package/src/constants.ts +1 -0
- package/src/controls/Control.spec.ts +102 -0
- package/src/controls/Control.ts +71 -2
- package/src/controls/changeHeight.spec.ts +147 -0
- package/src/controls/changeWidth.ts +68 -35
- package/src/controls/controlRendering.ts +20 -48
- package/src/controls/index.ts +7 -1
- package/src/gradient/Gradient.spec.ts +101 -46
- package/src/gradient/Gradient.ts +27 -14
- package/src/shapes/Circle.spec.ts +10 -39
- package/src/shapes/Circle.ts +11 -11
- package/src/shapes/Ellipse.spec.ts +8 -37
- package/src/shapes/Ellipse.ts +7 -7
- package/src/shapes/Group.ts +3 -3
- package/src/shapes/IText/IText-click-behavior.spec.ts +36 -49
- package/src/shapes/IText/IText.ts +5 -6
- package/src/shapes/IText/ITextKeyBehavior.test.ts +0 -1
- package/src/shapes/IText/__snapshots__/ITextBehavior.test.ts.snap +6 -6
- package/src/shapes/Image.spec.ts +17 -33
- package/src/shapes/Image.ts +15 -11
- package/src/shapes/Line.spec.ts +4 -30
- package/src/shapes/Line.ts +11 -16
- package/src/shapes/Object/FabricObjectSVGExportMixin.ts +11 -4
- package/src/shapes/Object/InteractiveObject.ts +4 -4
- package/src/shapes/Object/Object.ts +6 -5
- package/src/shapes/Object/ObjectGeometry.spec.ts +15 -0
- package/src/shapes/Object/ObjectGeometry.ts +1 -1
- package/src/shapes/Object/objectSvgExport.spec.ts +112 -0
- package/src/shapes/Object/types/FabricObjectProps.ts +1 -4
- package/src/shapes/Object/types/ObjectProps.ts +1 -3
- package/src/shapes/Path.spec.ts +4 -27
- package/src/shapes/Path.ts +2 -4
- package/src/shapes/Polygon.spec.ts +4 -31
- package/src/shapes/Polyline.spec.ts +4 -31
- package/src/shapes/Polyline.ts +11 -12
- package/src/shapes/Rect.spec.ts +25 -33
- package/src/shapes/Rect.ts +7 -7
- package/src/shapes/Text/StyledText.ts +0 -3
- package/src/shapes/Text/Text.spec.ts +3 -32
- package/src/shapes/Text/Text.ts +5 -6
- package/src/shapes/Text/TextSVGExportMixin.spec.ts +9 -0
- package/src/shapes/Text/TextSVGExportMixin.ts +14 -16
- package/src/shapes/Text/__snapshots__/Text.spec.ts.snap +1 -1
- package/src/shapes/Text/__snapshots__/TextSVGExportMixin.spec.ts.snap +1 -1
- package/src/shapes/Textbox.spec.ts +5 -5
- package/src/shapes/Textbox.ts +6 -5
- package/src/shapes/Triangle.ts +4 -4
- package/src/shapes/__snapshots__/Image.spec.ts.snap +4 -4
- package/src/shapes/__snapshots__/Textbox.spec.ts.snap +5 -5
- package/src/util/lang_string.ts +3 -2
- package/src/util/misc/svgParsing.ts +2 -1
- package/tsconfig.spec.json +1 -0
- package/vitest.config.ts +12 -2
- package/vitest.extend.ts +6 -2
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { getFabricDocument } from '../env';
|
|
2
2
|
import { FabricObject } from '../shapes/Object/FabricObject';
|
|
3
3
|
import { Gradient } from './Gradient';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
GradientUnits,
|
|
6
|
+
RadialGradientCoords,
|
|
7
|
+
SVGOptions,
|
|
8
|
+
} from './typedefs';
|
|
5
9
|
import { classRegistry } from '../ClassRegistry';
|
|
6
10
|
|
|
7
|
-
import { describe, expect, it, test
|
|
11
|
+
import { describe, expect, it, test } from 'vitest';
|
|
8
12
|
import { StaticCanvas } from '../canvas/StaticCanvas';
|
|
9
13
|
|
|
10
|
-
vi.mock('../util/internals/uid', () => ({
|
|
11
|
-
uid: () => 0,
|
|
12
|
-
}));
|
|
13
|
-
|
|
14
14
|
function createLinearGradient(units: GradientUnits = 'pixels', id?: string) {
|
|
15
15
|
return new Gradient({
|
|
16
16
|
type: 'linear',
|
|
@@ -85,17 +85,17 @@ function createRadialGradientSwapped() {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
const SVG_LINEAR =
|
|
88
|
-
'<linearGradient id="
|
|
88
|
+
'<linearGradient id="SVGID" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" x1="0" y1="10" x2="100" y2="200">\n<stop offset="0%" style="stop-color:rgba(255,0,0,0);"/>\n<stop offset="100%" style="stop-color:green;"/>\n</linearGradient>\n';
|
|
89
89
|
const SVG_RADIAL =
|
|
90
|
-
'<radialGradient id="
|
|
90
|
+
'<radialGradient id="SVGID" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" cx="100" cy="200" r="50" fx="0" fy="10">\n<stop offset="0%" style="stop-color:red;"/>\n<stop offset="100%" style="stop-color:rgba(0,255,0,0);"/>\n</radialGradient>\n';
|
|
91
91
|
const SVG_INTERNALRADIUS =
|
|
92
|
-
'<radialGradient id="
|
|
92
|
+
'<radialGradient id="SVGID" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" cx="100" cy="200" r="50" fx="0" fy="10">\n<stop offset="20%" style="stop-color:red;"/>\n<stop offset="100%" style="stop-color:rgba(0,255,0,0);"/>\n</radialGradient>\n';
|
|
93
93
|
const SVG_SWAPPED =
|
|
94
|
-
'<radialGradient id="
|
|
94
|
+
'<radialGradient id="SVGID" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -50 -50)" cx="0" cy="10" r="50" fx="100" fy="200">\n<stop offset="20%" style="stop-color:rgba(0,255,0,0);"/>\n<stop offset="100%" style="stop-color:red;"/>\n</radialGradient>\n';
|
|
95
95
|
const SVG_LINEAR_PERCENTAGE =
|
|
96
|
-
'<linearGradient id="
|
|
96
|
+
'<linearGradient id="SVGID" gradientUnits="objectBoundingBox" gradientTransform="matrix(1 0 0 1 0 0)" x1="0" y1="10" x2="100" y2="200">\n<stop offset="0%" style="stop-color:rgba(255,0,0,0);"/>\n<stop offset="100%" style="stop-color:green;"/>\n</linearGradient>\n';
|
|
97
97
|
const SVG_RADIAL_PERCENTAGE =
|
|
98
|
-
'<radialGradient id="
|
|
98
|
+
'<radialGradient id="SVGID" gradientUnits="objectBoundingBox" gradientTransform="matrix(1 0 0 1 0 0)" cx="100" cy="200" r="50" fx="0" fy="10">\n<stop offset="0%" style="stop-color:red;"/>\n<stop offset="100%" style="stop-color:rgba(0,255,0,0);"/>\n</radialGradient>\n';
|
|
99
99
|
|
|
100
100
|
describe('Gradient', () => {
|
|
101
101
|
function fromElement(
|
|
@@ -149,30 +149,73 @@ describe('Gradient', () => {
|
|
|
149
149
|
test('toSVG linear', () => {
|
|
150
150
|
const gradient = createLinearGradient();
|
|
151
151
|
const baseObj = new FabricObject({ width: 100, height: 100 });
|
|
152
|
-
expect(gradient.toSVG(baseObj)).
|
|
152
|
+
expect(gradient.toSVG(baseObj)).toEqualSVG(SVG_LINEAR);
|
|
153
153
|
});
|
|
154
154
|
|
|
155
155
|
test('toSVG radial', () => {
|
|
156
156
|
const gradient = createRadialGradient();
|
|
157
157
|
const baseObj = new FabricObject({ width: 100, height: 100 });
|
|
158
|
-
expect(gradient.toSVG(baseObj)).
|
|
158
|
+
expect(gradient.toSVG(baseObj)).toEqualSVG(SVG_RADIAL);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
test('toSVG linear sanitizes coord injection', () => {
|
|
162
|
+
const gradient = new Gradient({
|
|
163
|
+
type: 'linear',
|
|
164
|
+
coords: {
|
|
165
|
+
x1: '0" /><script>alert(1)</script>' as unknown as number,
|
|
166
|
+
y1: '0" /><script>alert(1)</script>' as unknown as number,
|
|
167
|
+
x2: '0" /><script>alert(1)</script>' as unknown as number,
|
|
168
|
+
y2: '0" /><script>alert(1)</script>' as unknown as number,
|
|
169
|
+
},
|
|
170
|
+
colorStops: [
|
|
171
|
+
{ offset: 0, color: 'rgba(255,0,0,0)' },
|
|
172
|
+
{ offset: 1, color: 'green' },
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
const baseObj = new FabricObject({ width: 100, height: 100 });
|
|
176
|
+
const svg = gradient.toSVG(baseObj);
|
|
177
|
+
expect(svg).not.toContain('<script>');
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test('toSVG radial sanitizes coord injection', () => {
|
|
181
|
+
const gradient = new Gradient({
|
|
182
|
+
type: 'radial',
|
|
183
|
+
coords: {
|
|
184
|
+
x1: '0" /><script>alert(1)</script>' as unknown as number,
|
|
185
|
+
y1: '0" /><script>alert(1)</script>' as unknown as number,
|
|
186
|
+
x2: '0" /><script>alert(1)</script>' as unknown as number,
|
|
187
|
+
y2: '0" /><script>alert(1)</script>' as unknown as number,
|
|
188
|
+
r1: '0" /><script>alert(1)</script>' as unknown as number,
|
|
189
|
+
r2: '50" /><script>alert(1)</script>' as unknown as number,
|
|
190
|
+
},
|
|
191
|
+
colorStops: [
|
|
192
|
+
{ offset: 0, color: 'red' },
|
|
193
|
+
{ offset: 1, color: 'rgba(0,255,0,0)' },
|
|
194
|
+
],
|
|
195
|
+
});
|
|
196
|
+
const baseObj = new FabricObject({ width: 100, height: 100 });
|
|
197
|
+
const svg = gradient.toSVG(baseObj);
|
|
198
|
+
expect(svg).not.toContain('<script>');
|
|
159
199
|
});
|
|
160
200
|
|
|
161
201
|
test('toSVG radial with r1 > 0', () => {
|
|
162
202
|
const gradient = createRadialGradientWithInternalRadius();
|
|
163
203
|
const obj = new FabricObject({ width: 100, height: 100 });
|
|
164
|
-
expect(gradient.toSVG(obj)).
|
|
204
|
+
expect(gradient.toSVG(obj)).toEqualSVG(SVG_INTERNALRADIUS);
|
|
165
205
|
});
|
|
166
206
|
|
|
167
207
|
test('toSVG radial with r1 > 0 swapped', () => {
|
|
168
208
|
const gradient = createRadialGradientSwapped();
|
|
169
209
|
const obj = new FabricObject({ width: 100, height: 100 });
|
|
170
210
|
const gradientColorStops = JSON.stringify(gradient.colorStops);
|
|
171
|
-
expect(gradient.toSVG(obj), 'it exports as expected').
|
|
172
|
-
const gradientColorStopsAfterExport = JSON.stringify(gradient.colorStops);
|
|
173
|
-
expect(gradient.toSVG(obj), 'it exports as expected a second time').toBe(
|
|
211
|
+
expect(gradient.toSVG(obj), 'it exports as expected').toEqualSVG(
|
|
174
212
|
SVG_SWAPPED,
|
|
175
213
|
);
|
|
214
|
+
const gradientColorStopsAfterExport = JSON.stringify(gradient.colorStops);
|
|
215
|
+
expect(
|
|
216
|
+
gradient.toSVG(obj),
|
|
217
|
+
'it exports as expected a second time',
|
|
218
|
+
).toEqualSVG(SVG_SWAPPED);
|
|
176
219
|
expect(gradientColorStops, 'colorstops do not change').toBe(
|
|
177
220
|
gradientColorStopsAfterExport,
|
|
178
221
|
);
|
|
@@ -181,13 +224,13 @@ describe('Gradient', () => {
|
|
|
181
224
|
test('toSVG linear objectBoundingBox', () => {
|
|
182
225
|
const gradient = createLinearGradient('percentage');
|
|
183
226
|
const obj = new FabricObject({ width: 100, height: 100 });
|
|
184
|
-
expect(gradient.toSVG(obj)).
|
|
227
|
+
expect(gradient.toSVG(obj)).toEqualSVG(SVG_LINEAR_PERCENTAGE);
|
|
185
228
|
});
|
|
186
229
|
|
|
187
230
|
test('toSVG radial objectBoundingBox', () => {
|
|
188
231
|
const gradient = createRadialGradient('percentage');
|
|
189
232
|
const obj = new FabricObject({ width: 100, height: 100 });
|
|
190
|
-
expect(gradient.toSVG(obj)).
|
|
233
|
+
expect(gradient.toSVG(obj)).toEqualSVG(SVG_RADIAL_PERCENTAGE);
|
|
191
234
|
});
|
|
192
235
|
});
|
|
193
236
|
|
|
@@ -235,8 +278,8 @@ describe('Gradient', () => {
|
|
|
235
278
|
|
|
236
279
|
test('toObject with custom props', () => {
|
|
237
280
|
const gradient = createLinearGradient('pixels', 'myId');
|
|
238
|
-
const object = gradient.toObject(['id']);
|
|
239
|
-
expect(object.id).
|
|
281
|
+
const object = gradient.toObject(['id']) as { id: string };
|
|
282
|
+
expect(object.id).toMatch(/^myId_\d+$/);
|
|
240
283
|
});
|
|
241
284
|
|
|
242
285
|
test('toObject radialGradient', () => {
|
|
@@ -535,23 +578,25 @@ describe('Gradient', () => {
|
|
|
535
578
|
let object = new FabricObject({ width: 200, height: 200 });
|
|
536
579
|
let gradient = fromElement(element, object, { opacity: '' });
|
|
537
580
|
it('should not change with width height', () => {
|
|
538
|
-
|
|
539
|
-
expect(
|
|
540
|
-
expect(
|
|
541
|
-
expect(
|
|
542
|
-
expect(
|
|
543
|
-
expect(
|
|
581
|
+
const coords = gradient.coords as RadialGradientCoords<number>;
|
|
582
|
+
expect(coords.x1).toEqual(0.3);
|
|
583
|
+
expect(coords.y1).toEqual(0.2);
|
|
584
|
+
expect(coords.x2).toEqual(0.1);
|
|
585
|
+
expect(coords.y2).toEqual(1);
|
|
586
|
+
expect(coords.r1).toEqual(0);
|
|
587
|
+
expect(coords.r2).toEqual(1);
|
|
544
588
|
});
|
|
545
589
|
|
|
546
590
|
it('should not change with top left', () => {
|
|
547
591
|
object = new FabricObject({ width: 200, height: 200, top: 10, left: 10 });
|
|
548
592
|
gradient = fromElement(element, object, { opacity: '' });
|
|
549
|
-
|
|
550
|
-
expect(
|
|
551
|
-
expect(
|
|
552
|
-
expect(
|
|
553
|
-
expect(
|
|
554
|
-
expect(
|
|
593
|
+
const coords = gradient.coords as RadialGradientCoords<number>;
|
|
594
|
+
expect(coords.x1).toEqual(0.3);
|
|
595
|
+
expect(coords.y1).toEqual(0.2);
|
|
596
|
+
expect(coords.x2).toEqual(0.1);
|
|
597
|
+
expect(coords.y2).toEqual(1);
|
|
598
|
+
expect(coords.r1).toEqual(0);
|
|
599
|
+
expect(coords.r2).toEqual(1);
|
|
555
600
|
});
|
|
556
601
|
});
|
|
557
602
|
|
|
@@ -572,12 +617,13 @@ describe('Gradient', () => {
|
|
|
572
617
|
it('should not change with width height', () => {
|
|
573
618
|
const object = new FabricObject({ width: 200, height: 200 });
|
|
574
619
|
const gradient = fromElement(element, object, { opacity: '' });
|
|
575
|
-
|
|
576
|
-
expect(
|
|
577
|
-
expect(
|
|
578
|
-
expect(
|
|
579
|
-
expect(
|
|
580
|
-
expect(
|
|
620
|
+
const coords = gradient.coords as RadialGradientCoords<number>;
|
|
621
|
+
expect(coords.x1).toEqual(30);
|
|
622
|
+
expect(coords.y1).toEqual(20);
|
|
623
|
+
expect(coords.x2).toEqual(15);
|
|
624
|
+
expect(coords.y2).toEqual(18);
|
|
625
|
+
expect(coords.r1).toEqual(0);
|
|
626
|
+
expect(coords.r2).toEqual(100);
|
|
581
627
|
});
|
|
582
628
|
|
|
583
629
|
it('should not change with top left', () => {
|
|
@@ -588,12 +634,13 @@ describe('Gradient', () => {
|
|
|
588
634
|
left: 60,
|
|
589
635
|
});
|
|
590
636
|
const gradient = fromElement(element, object, { opacity: '' });
|
|
591
|
-
|
|
592
|
-
expect(
|
|
593
|
-
expect(
|
|
594
|
-
expect(
|
|
595
|
-
expect(
|
|
596
|
-
expect(
|
|
637
|
+
const coords = gradient.coords as RadialGradientCoords<number>;
|
|
638
|
+
expect(coords.x1).toEqual(30);
|
|
639
|
+
expect(coords.y1).toEqual(20);
|
|
640
|
+
expect(coords.x2).toEqual(15);
|
|
641
|
+
expect(coords.y2).toEqual(18);
|
|
642
|
+
expect(coords.r1).toEqual(0);
|
|
643
|
+
expect(coords.r2).toEqual(100);
|
|
597
644
|
});
|
|
598
645
|
});
|
|
599
646
|
|
|
@@ -818,4 +865,12 @@ describe('Gradient', () => {
|
|
|
818
865
|
expect(gradient.colorStops[2].color).toEqual('rgba(0,0,0,1)');
|
|
819
866
|
expect(gradient.colorStops[3].color).toEqual('rgba(0,0,0,1)');
|
|
820
867
|
});
|
|
868
|
+
|
|
869
|
+
describe('Attrivbute injection', () => {
|
|
870
|
+
it('id injection', () => {
|
|
871
|
+
const gradient = new Gradient({ id: 'malicious"><script>' });
|
|
872
|
+
const svg = gradient.toSVG({} as any);
|
|
873
|
+
expect(svg).toContain('id="SVGID_malicious"><script>');
|
|
874
|
+
});
|
|
875
|
+
});
|
|
821
876
|
});
|
package/src/gradient/Gradient.ts
CHANGED
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
} from './typedefs';
|
|
21
21
|
import { classRegistry } from '../ClassRegistry';
|
|
22
22
|
import { isPath } from '../util/typeAssertions';
|
|
23
|
+
import { escapeXml } from '../util/lang_string';
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
26
|
* Gradient class
|
|
@@ -209,7 +210,7 @@ export class Gradient<
|
|
|
209
210
|
transform[5] -= offsetY;
|
|
210
211
|
|
|
211
212
|
const commonAttributes = [
|
|
212
|
-
`id="SVGID_${this.id}"`,
|
|
213
|
+
`id="SVGID_${escapeXml(String(this.id))}"`,
|
|
213
214
|
`gradientUnits="${gradientUnits}"`,
|
|
214
215
|
`gradientTransform="${
|
|
215
216
|
preTransform ? preTransform + ' ' : ''
|
|
@@ -217,39 +218,51 @@ export class Gradient<
|
|
|
217
218
|
'',
|
|
218
219
|
].join(' ');
|
|
219
220
|
|
|
221
|
+
const sanitizeCoord = (value: unknown) => parseFloat(String(value));
|
|
222
|
+
|
|
220
223
|
if (this.type === 'linear') {
|
|
221
224
|
const { x1, y1, x2, y2 } = this.coords;
|
|
225
|
+
const sx1 = sanitizeCoord(x1);
|
|
226
|
+
const sy1 = sanitizeCoord(y1);
|
|
227
|
+
const sx2 = sanitizeCoord(x2);
|
|
228
|
+
const sy2 = sanitizeCoord(y2);
|
|
222
229
|
markup.push(
|
|
223
230
|
'<linearGradient ',
|
|
224
231
|
commonAttributes,
|
|
225
232
|
' x1="',
|
|
226
|
-
|
|
233
|
+
sx1,
|
|
227
234
|
'" y1="',
|
|
228
|
-
|
|
235
|
+
sy1,
|
|
229
236
|
'" x2="',
|
|
230
|
-
|
|
237
|
+
sx2,
|
|
231
238
|
'" y2="',
|
|
232
|
-
|
|
239
|
+
sy2,
|
|
233
240
|
'">\n',
|
|
234
241
|
);
|
|
235
242
|
} else if (this.type === 'radial') {
|
|
236
243
|
const { x1, y1, x2, y2, r1, r2 } = this
|
|
237
244
|
.coords as GradientCoords<'radial'>;
|
|
238
|
-
const
|
|
245
|
+
const sx1 = sanitizeCoord(x1);
|
|
246
|
+
const sy1 = sanitizeCoord(y1);
|
|
247
|
+
const sx2 = sanitizeCoord(x2);
|
|
248
|
+
const sy2 = sanitizeCoord(y2);
|
|
249
|
+
const sr1 = sanitizeCoord(r1);
|
|
250
|
+
const sr2 = sanitizeCoord(r2);
|
|
251
|
+
const needsSwap = sr1 > sr2;
|
|
239
252
|
// svg radial gradient has just 1 radius. the biggest.
|
|
240
253
|
markup.push(
|
|
241
254
|
'<radialGradient ',
|
|
242
255
|
commonAttributes,
|
|
243
256
|
' cx="',
|
|
244
|
-
needsSwap ?
|
|
257
|
+
needsSwap ? sx1 : sx2,
|
|
245
258
|
'" cy="',
|
|
246
|
-
needsSwap ?
|
|
259
|
+
needsSwap ? sy1 : sy2,
|
|
247
260
|
'" r="',
|
|
248
|
-
needsSwap ?
|
|
261
|
+
needsSwap ? sr1 : sr2,
|
|
249
262
|
'" fx="',
|
|
250
|
-
needsSwap ?
|
|
263
|
+
needsSwap ? sx2 : sx1,
|
|
251
264
|
'" fy="',
|
|
252
|
-
needsSwap ?
|
|
265
|
+
needsSwap ? sy2 : sy1,
|
|
253
266
|
'">\n',
|
|
254
267
|
);
|
|
255
268
|
if (needsSwap) {
|
|
@@ -259,17 +272,17 @@ export class Gradient<
|
|
|
259
272
|
colorStop.offset = 1 - colorStop.offset;
|
|
260
273
|
});
|
|
261
274
|
}
|
|
262
|
-
const minRadius = Math.min(
|
|
275
|
+
const minRadius = Math.min(sr1, sr2);
|
|
263
276
|
if (minRadius > 0) {
|
|
264
277
|
// i have to shift all colorStops and add new one in 0.
|
|
265
|
-
const maxRadius = Math.max(
|
|
278
|
+
const maxRadius = Math.max(sr1, sr2),
|
|
266
279
|
percentageShift = minRadius / maxRadius;
|
|
267
280
|
colorStops.forEach((colorStop) => {
|
|
268
281
|
colorStop.offset += percentageShift * (1 - colorStop.offset);
|
|
269
282
|
});
|
|
270
283
|
}
|
|
271
284
|
}
|
|
272
|
-
|
|
285
|
+
// todo make a malicious script tag injection test with color and also apply a fix with escapeXml
|
|
273
286
|
colorStops.forEach(({ color, offset }) => {
|
|
274
287
|
markup.push(
|
|
275
288
|
`<stop offset="${offset * 100}%" style="stop-color:${color};"/>\n`,
|
|
@@ -2,6 +2,14 @@ import { describe, expect, it } from 'vitest';
|
|
|
2
2
|
import { Circle } from './Circle';
|
|
3
3
|
import { FabricObject } from './Object/FabricObject';
|
|
4
4
|
import { getFabricDocument, version } from '../../fabric';
|
|
5
|
+
import { createReferenceObject } from '../../test/utils';
|
|
6
|
+
|
|
7
|
+
const REFERENCE_CIRCLE = createReferenceObject('Circle', {
|
|
8
|
+
radius: 0,
|
|
9
|
+
startAngle: 0,
|
|
10
|
+
endAngle: 360,
|
|
11
|
+
counterClockwise: false,
|
|
12
|
+
});
|
|
5
13
|
|
|
6
14
|
describe('Circle', () => {
|
|
7
15
|
it('constructor', () => {
|
|
@@ -86,52 +94,15 @@ describe('Circle', () => {
|
|
|
86
94
|
|
|
87
95
|
it('toObject', () => {
|
|
88
96
|
const circle = new Circle();
|
|
89
|
-
const defaultProperties = {
|
|
90
|
-
version: version,
|
|
91
|
-
type: 'Circle',
|
|
92
|
-
originX: 'center',
|
|
93
|
-
originY: 'center',
|
|
94
|
-
left: 0,
|
|
95
|
-
top: 0,
|
|
96
|
-
width: 0,
|
|
97
|
-
height: 0,
|
|
98
|
-
fill: 'rgb(0,0,0)',
|
|
99
|
-
stroke: null,
|
|
100
|
-
strokeWidth: 1,
|
|
101
|
-
strokeDashArray: null,
|
|
102
|
-
strokeLineCap: 'butt',
|
|
103
|
-
strokeDashOffset: 0,
|
|
104
|
-
strokeLineJoin: 'miter',
|
|
105
|
-
strokeMiterLimit: 4,
|
|
106
|
-
scaleX: 1,
|
|
107
|
-
scaleY: 1,
|
|
108
|
-
angle: 0,
|
|
109
|
-
flipX: false,
|
|
110
|
-
flipY: false,
|
|
111
|
-
opacity: 1,
|
|
112
|
-
shadow: null,
|
|
113
|
-
visible: true,
|
|
114
|
-
backgroundColor: '',
|
|
115
|
-
fillRule: 'nonzero',
|
|
116
|
-
paintFirst: 'fill',
|
|
117
|
-
globalCompositeOperation: 'source-over',
|
|
118
|
-
radius: 0,
|
|
119
|
-
startAngle: 0,
|
|
120
|
-
endAngle: 360,
|
|
121
|
-
counterClockwise: false,
|
|
122
|
-
skewX: 0,
|
|
123
|
-
skewY: 0,
|
|
124
|
-
strokeUniform: false,
|
|
125
|
-
};
|
|
126
97
|
expect(circle.toObject).toBeTypeOf('function');
|
|
127
|
-
expect(circle.toObject()).toStrictEqual(
|
|
98
|
+
expect(circle.toObject()).toStrictEqual(REFERENCE_CIRCLE);
|
|
128
99
|
|
|
129
100
|
circle.set('left', 100);
|
|
130
101
|
circle.set('top', 200);
|
|
131
102
|
circle.set('radius', 15);
|
|
132
103
|
|
|
133
104
|
expect(circle.toObject()).toStrictEqual({
|
|
134
|
-
...
|
|
105
|
+
...REFERENCE_CIRCLE,
|
|
135
106
|
left: 100,
|
|
136
107
|
top: 200,
|
|
137
108
|
width: 30,
|
package/src/shapes/Circle.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type { Abortable, TClassProperties, TOptions } from '../typedefs';
|
|
|
10
10
|
import type { FabricObjectProps, SerializedObjectProps } from './Object/types';
|
|
11
11
|
import type { CSSRules } from '../parser/typedefs';
|
|
12
12
|
import { SCALE_X, SCALE_Y } from '../constants';
|
|
13
|
+
import { escapeXml } from '../util/lang_string';
|
|
13
14
|
|
|
14
15
|
interface UniqueCircleProps {
|
|
15
16
|
/**
|
|
@@ -43,8 +44,7 @@ interface UniqueCircleProps {
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export interface SerializedCircleProps
|
|
46
|
-
extends SerializedObjectProps,
|
|
47
|
-
UniqueCircleProps {}
|
|
47
|
+
extends SerializedObjectProps, UniqueCircleProps {}
|
|
48
48
|
|
|
49
49
|
export interface CircleProps extends FabricObjectProps, UniqueCircleProps {}
|
|
50
50
|
|
|
@@ -63,10 +63,10 @@ export const circleDefaultValues: Partial<TClassProperties<Circle>> = {
|
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
export class Circle<
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
Props extends TOptions<CircleProps> = Partial<CircleProps>,
|
|
67
|
+
SProps extends SerializedCircleProps = SerializedCircleProps,
|
|
68
|
+
EventSpec extends ObjectEvents = ObjectEvents,
|
|
69
|
+
>
|
|
70
70
|
extends FabricObject<Props, SProps, EventSpec>
|
|
71
71
|
implements UniqueCircleProps
|
|
72
72
|
{
|
|
@@ -174,7 +174,8 @@ export class Circle<
|
|
|
174
174
|
* of the instance
|
|
175
175
|
*/
|
|
176
176
|
_toSVG(): string[] {
|
|
177
|
-
const
|
|
177
|
+
const { radius, startAngle, endAngle } = this;
|
|
178
|
+
const angle = (endAngle - startAngle) % 360;
|
|
178
179
|
|
|
179
180
|
if (angle === 0) {
|
|
180
181
|
return [
|
|
@@ -182,13 +183,12 @@ export class Circle<
|
|
|
182
183
|
'COMMON_PARTS',
|
|
183
184
|
'cx="0" cy="0" ',
|
|
184
185
|
'r="',
|
|
185
|
-
`${
|
|
186
|
+
`${escapeXml(radius)}`,
|
|
186
187
|
'" />\n',
|
|
187
188
|
];
|
|
188
189
|
} else {
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
end = degreesToRadians(this.endAngle),
|
|
190
|
+
const start = degreesToRadians(startAngle),
|
|
191
|
+
end = degreesToRadians(endAngle),
|
|
192
192
|
startX = cos(start) * radius,
|
|
193
193
|
startY = sin(start) * radius,
|
|
194
194
|
endX = cos(end) * radius,
|
|
@@ -3,6 +3,12 @@ import { Ellipse } from './Ellipse';
|
|
|
3
3
|
import { FabricObject } from './Object/Object';
|
|
4
4
|
import { getFabricDocument, version } from '../../fabric';
|
|
5
5
|
import { sanitizeSVG } from '../../vitest.extend';
|
|
6
|
+
import { createReferenceObject } from '../../test/utils';
|
|
7
|
+
|
|
8
|
+
const REFERENCE_ELLIPSE = createReferenceObject('Ellipse', {
|
|
9
|
+
rx: 0,
|
|
10
|
+
ry: 0,
|
|
11
|
+
});
|
|
6
12
|
|
|
7
13
|
describe('Ellipse', () => {
|
|
8
14
|
it('initializes constructor correctly', () => {
|
|
@@ -24,43 +30,8 @@ describe('Ellipse', () => {
|
|
|
24
30
|
|
|
25
31
|
it('converts to object with correct properties', () => {
|
|
26
32
|
const ellipse = new Ellipse();
|
|
27
|
-
const defaultProperties = {
|
|
28
|
-
version: version,
|
|
29
|
-
type: 'Ellipse',
|
|
30
|
-
originX: 'center',
|
|
31
|
-
originY: 'center',
|
|
32
|
-
left: 0,
|
|
33
|
-
top: 0,
|
|
34
|
-
width: 0,
|
|
35
|
-
height: 0,
|
|
36
|
-
fill: 'rgb(0,0,0)',
|
|
37
|
-
stroke: null,
|
|
38
|
-
strokeWidth: 1,
|
|
39
|
-
strokeDashArray: null,
|
|
40
|
-
strokeLineCap: 'butt',
|
|
41
|
-
strokeDashOffset: 0,
|
|
42
|
-
strokeLineJoin: 'miter',
|
|
43
|
-
strokeMiterLimit: 4,
|
|
44
|
-
scaleX: 1,
|
|
45
|
-
scaleY: 1,
|
|
46
|
-
angle: 0,
|
|
47
|
-
flipX: false,
|
|
48
|
-
flipY: false,
|
|
49
|
-
opacity: 1,
|
|
50
|
-
skewX: 0,
|
|
51
|
-
skewY: 0,
|
|
52
|
-
rx: 0,
|
|
53
|
-
ry: 0,
|
|
54
|
-
shadow: null,
|
|
55
|
-
visible: true,
|
|
56
|
-
backgroundColor: '',
|
|
57
|
-
fillRule: 'nonzero',
|
|
58
|
-
paintFirst: 'fill',
|
|
59
|
-
globalCompositeOperation: 'source-over',
|
|
60
|
-
strokeUniform: false,
|
|
61
|
-
};
|
|
62
33
|
expect(ellipse.toObject).toBeTypeOf('function');
|
|
63
|
-
expect(ellipse.toObject()).toEqual(
|
|
34
|
+
expect(ellipse.toObject()).toEqual(REFERENCE_ELLIPSE);
|
|
64
35
|
|
|
65
36
|
ellipse.set('left', 100);
|
|
66
37
|
ellipse.set('top', 200);
|
|
@@ -68,7 +39,7 @@ describe('Ellipse', () => {
|
|
|
68
39
|
ellipse.set('ry', 25);
|
|
69
40
|
|
|
70
41
|
expect(ellipse.toObject()).toEqual({
|
|
71
|
-
...
|
|
42
|
+
...REFERENCE_ELLIPSE,
|
|
72
43
|
left: 100,
|
|
73
44
|
top: 200,
|
|
74
45
|
rx: 15,
|
package/src/shapes/Ellipse.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { FabricObject, cacheProperties } from './Object/FabricObject';
|
|
|
7
7
|
import type { FabricObjectProps, SerializedObjectProps } from './Object/types';
|
|
8
8
|
import type { ObjectEvents } from '../EventTypeDefs';
|
|
9
9
|
import type { CSSRules } from '../parser/typedefs';
|
|
10
|
+
import { escapeXml } from '../util/lang_string';
|
|
10
11
|
|
|
11
12
|
export const ellipseDefaultValues: Partial<TClassProperties<Ellipse>> = {
|
|
12
13
|
rx: 0,
|
|
@@ -19,18 +20,17 @@ interface UniqueEllipseProps {
|
|
|
19
20
|
}
|
|
20
21
|
|
|
21
22
|
export interface SerializedEllipseProps
|
|
22
|
-
extends SerializedObjectProps,
|
|
23
|
-
UniqueEllipseProps {}
|
|
23
|
+
extends SerializedObjectProps, UniqueEllipseProps {}
|
|
24
24
|
|
|
25
25
|
export interface EllipseProps extends FabricObjectProps, UniqueEllipseProps {}
|
|
26
26
|
|
|
27
27
|
const ELLIPSE_PROPS = ['rx', 'ry'] as const;
|
|
28
28
|
|
|
29
29
|
export class Ellipse<
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
Props extends TOptions<EllipseProps> = Partial<EllipseProps>,
|
|
31
|
+
SProps extends SerializedEllipseProps = SerializedEllipseProps,
|
|
32
|
+
EventSpec extends ObjectEvents = ObjectEvents,
|
|
33
|
+
>
|
|
34
34
|
extends FabricObject<Props, SProps, EventSpec>
|
|
35
35
|
implements EllipseProps
|
|
36
36
|
{
|
|
@@ -128,7 +128,7 @@ export class Ellipse<
|
|
|
128
128
|
return [
|
|
129
129
|
'<ellipse ',
|
|
130
130
|
'COMMON_PARTS',
|
|
131
|
-
`cx="0" cy="0" rx="${this.rx}" ry="${this.ry}" />\n`,
|
|
131
|
+
`cx="0" cy="0" rx="${escapeXml(this.rx)}" ry="${escapeXml(this.ry)}" />\n`,
|
|
132
132
|
];
|
|
133
133
|
}
|
|
134
134
|
|
package/src/shapes/Group.ts
CHANGED
|
@@ -35,6 +35,7 @@ import {
|
|
|
35
35
|
import type { SerializedLayoutManager } from '../LayoutManager/LayoutManager';
|
|
36
36
|
import type { FitContentLayout } from '../LayoutManager';
|
|
37
37
|
import type { DrawContext } from './Object/Object';
|
|
38
|
+
import { escapeXml } from '../util/lang_string';
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* This class handles the specific case of creating a group using {@link Group#fromObject} and is not meant to be used in any other case.
|
|
@@ -57,8 +58,7 @@ export interface GroupOwnProps {
|
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
export interface SerializedGroupProps
|
|
60
|
-
extends SerializedObjectProps,
|
|
61
|
-
GroupOwnProps {
|
|
61
|
+
extends SerializedObjectProps, GroupOwnProps {
|
|
62
62
|
objects: SerializedObjectProps[];
|
|
63
63
|
layoutManager: SerializedLayoutManager;
|
|
64
64
|
}
|
|
@@ -650,7 +650,7 @@ export class Group
|
|
|
650
650
|
getSvgStyles(): string {
|
|
651
651
|
const opacity =
|
|
652
652
|
typeof this.opacity !== 'undefined' && this.opacity !== 1
|
|
653
|
-
? `opacity: ${this.opacity};`
|
|
653
|
+
? `opacity: ${escapeXml(this.opacity)};`
|
|
654
654
|
: '',
|
|
655
655
|
visibility = this.visible ? '' : ' visibility: hidden;';
|
|
656
656
|
return [opacity, this.getSvgFilter(), visibility].join('');
|