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
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
TModificationEvents,
|
|
3
|
+
Transform,
|
|
4
|
+
TransformActionHandler,
|
|
5
|
+
FabricImage,
|
|
6
|
+
ObjectEvents,
|
|
7
|
+
Control,
|
|
8
|
+
TMat2D,
|
|
9
|
+
} from 'fabric';
|
|
10
|
+
import { controlsUtils, Point, util } from 'fabric';
|
|
11
|
+
|
|
12
|
+
const { wrapWithFixedAnchor, wrapWithFireEvent } = controlsUtils;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Wrap controlsUtils.changeObjectWidth with image constrains
|
|
16
|
+
*/
|
|
17
|
+
export const changeImageWidth: TransformActionHandler = (
|
|
18
|
+
eventData,
|
|
19
|
+
transform,
|
|
20
|
+
x,
|
|
21
|
+
y,
|
|
22
|
+
) => {
|
|
23
|
+
const { target } = transform;
|
|
24
|
+
const { width } = target;
|
|
25
|
+
const image = target as FabricImage;
|
|
26
|
+
const modified = controlsUtils.changeObjectWidth(eventData, transform, x, y);
|
|
27
|
+
const availableWidth = image._element.width - image.cropX;
|
|
28
|
+
if (modified) {
|
|
29
|
+
if (image.width > availableWidth) {
|
|
30
|
+
image.width = availableWidth;
|
|
31
|
+
}
|
|
32
|
+
if (image.width < 1) {
|
|
33
|
+
image.width = 1;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return width !== image.width;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export const changeCropWidth = wrapWithFireEvent(
|
|
40
|
+
'CROPPING' as TModificationEvents,
|
|
41
|
+
wrapWithFixedAnchor(changeImageWidth),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Wrap controlsUtils.changeObjectHeight with image constrains
|
|
46
|
+
*/
|
|
47
|
+
export const changeImageHeight: TransformActionHandler = (
|
|
48
|
+
eventData,
|
|
49
|
+
transform,
|
|
50
|
+
x,
|
|
51
|
+
y,
|
|
52
|
+
) => {
|
|
53
|
+
const { target } = transform;
|
|
54
|
+
const { height } = target;
|
|
55
|
+
const image = target as FabricImage;
|
|
56
|
+
const modified = controlsUtils.changeObjectHeight(eventData, transform, x, y);
|
|
57
|
+
const availableHeight = image._element.height - image.cropY;
|
|
58
|
+
if (modified) {
|
|
59
|
+
if (image.height > availableHeight) {
|
|
60
|
+
image.height = availableHeight;
|
|
61
|
+
}
|
|
62
|
+
if (image.height < 1) {
|
|
63
|
+
image.height = 1;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return height !== image.height;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const changeCropHeight = wrapWithFireEvent(
|
|
70
|
+
'CROPPING' as TModificationEvents,
|
|
71
|
+
wrapWithFixedAnchor(changeImageHeight),
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
export const changeImageCropX: TransformActionHandler = (
|
|
75
|
+
eventData,
|
|
76
|
+
transform,
|
|
77
|
+
x,
|
|
78
|
+
y,
|
|
79
|
+
) => {
|
|
80
|
+
const { target } = transform;
|
|
81
|
+
const image = target as FabricImage;
|
|
82
|
+
const { width, cropX } = image;
|
|
83
|
+
const modified = controlsUtils.changeObjectWidth(eventData, transform, x, y);
|
|
84
|
+
let newCropX = cropX + width - image.width;
|
|
85
|
+
image.width = width;
|
|
86
|
+
if (modified) {
|
|
87
|
+
if (newCropX < 0) {
|
|
88
|
+
newCropX = 0;
|
|
89
|
+
}
|
|
90
|
+
image.cropX = newCropX;
|
|
91
|
+
// calculate new width on the base of how much crop we have now
|
|
92
|
+
image.width += cropX - newCropX;
|
|
93
|
+
}
|
|
94
|
+
return newCropX !== cropX;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const changeImageCropY: TransformActionHandler = (
|
|
98
|
+
eventData,
|
|
99
|
+
transform,
|
|
100
|
+
x,
|
|
101
|
+
y,
|
|
102
|
+
) => {
|
|
103
|
+
const { target } = transform;
|
|
104
|
+
const image = target as FabricImage;
|
|
105
|
+
const { height, cropY } = image;
|
|
106
|
+
const modified = controlsUtils.changeObjectHeight(eventData, transform, x, y);
|
|
107
|
+
let newCropY = cropY + height - image.height;
|
|
108
|
+
image.height = height;
|
|
109
|
+
if (modified) {
|
|
110
|
+
if (newCropY < 0) {
|
|
111
|
+
newCropY = 0;
|
|
112
|
+
}
|
|
113
|
+
image.cropY = newCropY;
|
|
114
|
+
image.height += cropY - newCropY;
|
|
115
|
+
}
|
|
116
|
+
return newCropY !== cropY;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
export const changeCropX = wrapWithFireEvent(
|
|
120
|
+
'CROPPING' as TModificationEvents,
|
|
121
|
+
wrapWithFixedAnchor(changeImageCropX),
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
export const changeCropY = wrapWithFireEvent(
|
|
125
|
+
'CROPPING' as TModificationEvents,
|
|
126
|
+
wrapWithFixedAnchor(changeImageCropY),
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* A function to counter the move action and change cropX/cropY of an image
|
|
131
|
+
* Keep the image steady, but moves it inside its own cropping rectangle
|
|
132
|
+
*/
|
|
133
|
+
export const cropPanMoveHandler = ({ transform }: ObjectEvents['moving']) => {
|
|
134
|
+
// this makes the image pan too fast.
|
|
135
|
+
const { target, original } = transform as Transform;
|
|
136
|
+
const fabricImage = target as FabricImage;
|
|
137
|
+
const p = new Point(
|
|
138
|
+
target.left - original.left,
|
|
139
|
+
target.top - original.top,
|
|
140
|
+
).transform(
|
|
141
|
+
util.invertTransform(
|
|
142
|
+
util.createRotateMatrix({ angle: fabricImage.getTotalAngle() }),
|
|
143
|
+
),
|
|
144
|
+
);
|
|
145
|
+
let cropX = original.cropX! - p.x / fabricImage.scaleX;
|
|
146
|
+
let cropY = original.cropY! - p.y / fabricImage.scaleY;
|
|
147
|
+
const { width, height, _element } = fabricImage;
|
|
148
|
+
if (cropX < 0) {
|
|
149
|
+
cropX = 0;
|
|
150
|
+
}
|
|
151
|
+
if (cropY < 0) {
|
|
152
|
+
cropY = 0;
|
|
153
|
+
}
|
|
154
|
+
if (cropX + width > _element.width) {
|
|
155
|
+
cropX = _element.width - width;
|
|
156
|
+
}
|
|
157
|
+
if (cropY + height > _element.height) {
|
|
158
|
+
cropY = _element.height - height;
|
|
159
|
+
}
|
|
160
|
+
fabricImage.cropX = cropX;
|
|
161
|
+
fabricImage.cropY = cropY;
|
|
162
|
+
fabricImage.left = original.left;
|
|
163
|
+
fabricImage.top = original.top;
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* This position handler works only for this specific use case.
|
|
168
|
+
* It does not support padding nor offset, and it reduces all possible positions
|
|
169
|
+
* to the main 4 corners only.
|
|
170
|
+
* Any position that is < 0 is the extreme left/top, the rest are right/bottom
|
|
171
|
+
*/
|
|
172
|
+
export function ghostScalePositionHandler(
|
|
173
|
+
this: Control,
|
|
174
|
+
dim: Point, // currentDimension
|
|
175
|
+
finalMatrix: TMat2D,
|
|
176
|
+
fabricObject: FabricImage,
|
|
177
|
+
// currentControl: Control,
|
|
178
|
+
) {
|
|
179
|
+
const matrix = fabricObject.calcTransformMatrix();
|
|
180
|
+
const vpt = fabricObject.getViewportTransform();
|
|
181
|
+
const _finalMatrix = util.multiplyTransformMatrices(vpt, matrix);
|
|
182
|
+
|
|
183
|
+
let x = 0;
|
|
184
|
+
let y = 0;
|
|
185
|
+
if (this.x < 0) {
|
|
186
|
+
x = -fabricObject.width / 2 - fabricObject.cropX;
|
|
187
|
+
} else {
|
|
188
|
+
x =
|
|
189
|
+
fabricObject.getElement().width -
|
|
190
|
+
fabricObject.width / 2 -
|
|
191
|
+
fabricObject.cropX;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (this.y < 0) {
|
|
195
|
+
y = -fabricObject.height / 2 - fabricObject.cropY;
|
|
196
|
+
} else {
|
|
197
|
+
y =
|
|
198
|
+
fabricObject.getElement().height -
|
|
199
|
+
fabricObject.height / 2 -
|
|
200
|
+
fabricObject.cropY;
|
|
201
|
+
}
|
|
202
|
+
return new Point(x, y).transform(_finalMatrix);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const calcScale = (currentPoint: Point, height: number, width: number) =>
|
|
206
|
+
Math.min(Math.abs(currentPoint.x / width), Math.abs(currentPoint.y / height));
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Action handler generator that handles scaling of an image in crop mode.
|
|
210
|
+
* The goal is to keep the current bounding box steady.
|
|
211
|
+
* So this action handler has its own calculations for a dynamic anchor point
|
|
212
|
+
*/
|
|
213
|
+
export const scaleEquallyCropGenerator =
|
|
214
|
+
(cx: number, cy: number): TransformActionHandler =>
|
|
215
|
+
(eventData, transform, x, y) => {
|
|
216
|
+
const { target } = transform as unknown as { target: FabricImage };
|
|
217
|
+
const { width: fullWidth, height: fullHeight } = target.getElement();
|
|
218
|
+
const remainderX = fullWidth - target.width - target.cropX;
|
|
219
|
+
const remainderY = fullHeight - target.height - target.cropY;
|
|
220
|
+
const anchorOriginX =
|
|
221
|
+
cx < 0 ? 1 + remainderX / target.width : -target.cropX / target.width;
|
|
222
|
+
const anchorOriginY =
|
|
223
|
+
cy < 0 ? 1 + remainderY / target.height : -target.cropY / target.height;
|
|
224
|
+
const constraint = target.translateToOriginPoint(
|
|
225
|
+
target.getCenterPoint(),
|
|
226
|
+
anchorOriginX,
|
|
227
|
+
anchorOriginY,
|
|
228
|
+
);
|
|
229
|
+
const newPoint = controlsUtils.getLocalPoint(
|
|
230
|
+
transform,
|
|
231
|
+
anchorOriginX,
|
|
232
|
+
anchorOriginY,
|
|
233
|
+
x,
|
|
234
|
+
y,
|
|
235
|
+
);
|
|
236
|
+
const scale = calcScale(newPoint, fullHeight, fullWidth);
|
|
237
|
+
const scaleChangeX = scale / target.scaleX;
|
|
238
|
+
const scaleChangeY = scale / target.scaleY;
|
|
239
|
+
const scaledRemainderX = remainderX / scaleChangeX;
|
|
240
|
+
const scaledRemainderY = remainderY / scaleChangeY;
|
|
241
|
+
const newWidth = target.width / scaleChangeX;
|
|
242
|
+
const newHeight = target.height / scaleChangeY;
|
|
243
|
+
const newCropX =
|
|
244
|
+
cx < 0
|
|
245
|
+
? fullWidth - newWidth - scaledRemainderX
|
|
246
|
+
: target.cropX / scaleChangeX;
|
|
247
|
+
const newCropY =
|
|
248
|
+
cy < 0
|
|
249
|
+
? fullHeight - newHeight - scaledRemainderY
|
|
250
|
+
: target.cropY / scaleChangeY;
|
|
251
|
+
|
|
252
|
+
if (
|
|
253
|
+
(cx < 0 ? scaledRemainderX : newCropX) + newWidth > fullWidth ||
|
|
254
|
+
(cy < 0 ? scaledRemainderY : newCropY) + newHeight > fullHeight
|
|
255
|
+
) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
target.scaleX = scale;
|
|
260
|
+
target.scaleY = scale;
|
|
261
|
+
target.width = newWidth;
|
|
262
|
+
target.height = newHeight;
|
|
263
|
+
target.cropX = newCropX;
|
|
264
|
+
target.cropY = newCropY;
|
|
265
|
+
const newAnchorOriginX =
|
|
266
|
+
cx < 0 ? 1 + scaledRemainderX / newWidth : -newCropX / newWidth;
|
|
267
|
+
const newAnchorOriginY =
|
|
268
|
+
cy < 0 ? 1 + scaledRemainderY / newHeight : -newCropY / newHeight;
|
|
269
|
+
target.setPositionByOrigin(constraint, newAnchorOriginX, newAnchorOriginY);
|
|
270
|
+
return true;
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
export function renderGhostImage(
|
|
274
|
+
this: FabricImage,
|
|
275
|
+
{ ctx }: { ctx: CanvasRenderingContext2D },
|
|
276
|
+
) {
|
|
277
|
+
const alpha = ctx.globalAlpha;
|
|
278
|
+
ctx.globalAlpha *= 0.5;
|
|
279
|
+
ctx.drawImage(
|
|
280
|
+
this._element,
|
|
281
|
+
-this.width / 2 - this.cropX,
|
|
282
|
+
-this.height / 2 - this.cropY,
|
|
283
|
+
);
|
|
284
|
+
ctx.globalAlpha = alpha;
|
|
285
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type FabricImage, type TPointerEventInfo } from 'fabric';
|
|
2
|
+
import { createImageCroppingControls } from './croppingControls';
|
|
3
|
+
import { cropPanMoveHandler, renderGhostImage } from './croppingHandlers';
|
|
4
|
+
/**
|
|
5
|
+
* Coordinates the change to image to enter crop mode and returns
|
|
6
|
+
* a function to exit crop mode
|
|
7
|
+
*/
|
|
8
|
+
export const enterCropMode = function enterCropMode(
|
|
9
|
+
this: (args: TPointerEventInfo) => void,
|
|
10
|
+
{ target }: TPointerEventInfo,
|
|
11
|
+
) {
|
|
12
|
+
const fabricImage = target as FabricImage;
|
|
13
|
+
const { controls, padding } = fabricImage;
|
|
14
|
+
fabricImage.padding = 0;
|
|
15
|
+
fabricImage.controls = createImageCroppingControls();
|
|
16
|
+
fabricImage.on('moving', cropPanMoveHandler);
|
|
17
|
+
fabricImage.on('before:render', renderGhostImage);
|
|
18
|
+
fabricImage.setCoords();
|
|
19
|
+
const exitCropMode = () => {
|
|
20
|
+
fabricImage.padding = padding;
|
|
21
|
+
fabricImage.off('moving', cropPanMoveHandler);
|
|
22
|
+
fabricImage.off('before:render', renderGhostImage);
|
|
23
|
+
fabricImage.controls = controls;
|
|
24
|
+
fabricImage.setCoords();
|
|
25
|
+
fabricImage.once('mousedblclick', enterCropMode);
|
|
26
|
+
fabricImage.canvas?.requestRenderAll();
|
|
27
|
+
};
|
|
28
|
+
fabricImage.once('mousedblclick', exitCropMode);
|
|
29
|
+
fabricImage.canvas?.requestRenderAll();
|
|
30
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ControlRenderingStyleOverride,
|
|
3
|
+
type InteractiveFabricObject,
|
|
4
|
+
util,
|
|
5
|
+
type Control,
|
|
6
|
+
} from 'fabric';
|
|
7
|
+
|
|
8
|
+
const { degreesToRadians } = util;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Render a control for the main corners of a cropping image
|
|
12
|
+
* This function is written to respect object properties like transparentCorners, cornerSize
|
|
13
|
+
* cornerColor, cornerStrokeColor
|
|
14
|
+
* plus the addition of offsetY and offsetX.
|
|
15
|
+
* @param {CanvasRenderingContext2D} ctx context to render on
|
|
16
|
+
* @param {Number} left x coordinate where the control center should be
|
|
17
|
+
* @param {Number} top y coordinate where the control center should be
|
|
18
|
+
* @param {Object} styleOverride override for FabricObject controls style
|
|
19
|
+
* @param {FabricObject} fabricObject the fabric object for which we are rendering controls
|
|
20
|
+
*/
|
|
21
|
+
export function renderCornerControl(
|
|
22
|
+
this: Control,
|
|
23
|
+
ctx: CanvasRenderingContext2D,
|
|
24
|
+
left: number,
|
|
25
|
+
top: number,
|
|
26
|
+
styleOverride: ControlRenderingStyleOverride,
|
|
27
|
+
fabricObject: InteractiveFabricObject,
|
|
28
|
+
) {
|
|
29
|
+
ctx.save();
|
|
30
|
+
const { stroke, xSize, ySize, opName } = this.commonRenderProps(
|
|
31
|
+
ctx,
|
|
32
|
+
left,
|
|
33
|
+
top,
|
|
34
|
+
fabricObject,
|
|
35
|
+
styleOverride,
|
|
36
|
+
),
|
|
37
|
+
xSizeBy2 = xSize / 2,
|
|
38
|
+
ySizeBy2 = ySize / 2;
|
|
39
|
+
// angle is relative to canvas plane
|
|
40
|
+
ctx.rotate(degreesToRadians(this.angle));
|
|
41
|
+
ctx.beginPath();
|
|
42
|
+
ctx.moveTo(-ySizeBy2, 0);
|
|
43
|
+
ctx.lineTo(-ySizeBy2, xSizeBy2);
|
|
44
|
+
ctx.lineTo(ySizeBy2, xSizeBy2);
|
|
45
|
+
ctx.lineTo(ySizeBy2, ySizeBy2);
|
|
46
|
+
ctx.lineTo(xSizeBy2, ySizeBy2);
|
|
47
|
+
ctx.lineTo(xSizeBy2, -ySizeBy2);
|
|
48
|
+
ctx.lineTo(-ySizeBy2, -ySizeBy2);
|
|
49
|
+
ctx.closePath();
|
|
50
|
+
ctx[opName]();
|
|
51
|
+
stroke && ctx.stroke();
|
|
52
|
+
ctx.restore();
|
|
53
|
+
}
|
package/extensions/index.ts
CHANGED
|
@@ -16,3 +16,12 @@ export {
|
|
|
16
16
|
pinchEventHandler,
|
|
17
17
|
rotateEventHandler,
|
|
18
18
|
} from './westures_integration';
|
|
19
|
+
|
|
20
|
+
export { createImageCroppingControls } from './cropping_controls/croppingControls';
|
|
21
|
+
export {
|
|
22
|
+
changeCropY,
|
|
23
|
+
changeCropX,
|
|
24
|
+
changeCropWidth,
|
|
25
|
+
changeCropHeight,
|
|
26
|
+
} from './cropping_controls/croppingHandlers';
|
|
27
|
+
export { enterCropMode } from './cropping_controls/enterCropMode';
|
package/fabric.ts
CHANGED
|
@@ -178,5 +178,6 @@ export { parseSVGDocument } from './src/parser/parseSVGDocument';
|
|
|
178
178
|
|
|
179
179
|
export { Control } from './src/controls/Control';
|
|
180
180
|
export * as controlsUtils from './src/controls';
|
|
181
|
+
export type { ControlRenderingStyleOverride } from './src/controls';
|
|
181
182
|
|
|
182
183
|
export * from './src/filters';
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "fabric",
|
|
3
3
|
"description": "Object model for HTML5 canvas, and SVG-to-canvas parser. Backed by jsdom and node-canvas.",
|
|
4
4
|
"homepage": "http://fabricjs.com/",
|
|
5
|
-
"version": "7.
|
|
5
|
+
"version": "7.2.0",
|
|
6
6
|
"author": "Juriy Zaytsev <kangax@gmail.com>",
|
|
7
7
|
"contributors": [
|
|
8
8
|
{
|
|
@@ -63,7 +63,8 @@
|
|
|
63
63
|
"local-server": "serve ./ -l tcp://localhost:8080",
|
|
64
64
|
"lint": "eslint src extensions",
|
|
65
65
|
"prettier:check": "prettier --check .",
|
|
66
|
-
"prettier:write": "prettier --write ."
|
|
66
|
+
"prettier:write": "prettier --write .",
|
|
67
|
+
"prepare": "husky install"
|
|
67
68
|
},
|
|
68
69
|
"devDependencies": {
|
|
69
70
|
"@babel/cli": "^7.28.3",
|
|
@@ -71,7 +72,7 @@
|
|
|
71
72
|
"@babel/preset-env": "^7.28.3",
|
|
72
73
|
"@babel/preset-typescript": "^7.27.1",
|
|
73
74
|
"@eslint/js": "^9.37.0",
|
|
74
|
-
"@playwright/test": "^1.
|
|
75
|
+
"@playwright/test": "^1.58.1",
|
|
75
76
|
"@rollup/plugin-babel": "^6.0.4",
|
|
76
77
|
"@rollup/plugin-json": "^6.1.0",
|
|
77
78
|
"@rollup/plugin-terser": "^0.4.4",
|
|
@@ -79,26 +80,29 @@
|
|
|
79
80
|
"@types/jsdom": "^21.1.7",
|
|
80
81
|
"@types/micromatch": "^4.0.9",
|
|
81
82
|
"@types/node": "^24.7.0",
|
|
82
|
-
"@vitest/browser-playwright": "^4.0.
|
|
83
|
-
"@vitest/coverage-v8": "^4.0.
|
|
84
|
-
"@vitest/ui": "^4.0.
|
|
83
|
+
"@vitest/browser-playwright": "^4.0.18",
|
|
84
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
85
|
+
"@vitest/ui": "^4.0.18",
|
|
85
86
|
"babel-plugin-transform-imports": "git+https://git@github.com/fabricjs/babel-plugin-transform-imports.git",
|
|
86
87
|
"commander": "^14.0.1",
|
|
87
88
|
"es-toolkit": "1.40.0",
|
|
88
89
|
"eslint-config-prettier": "^10.1.8",
|
|
90
|
+
"husky": "^9.1.7",
|
|
89
91
|
"inquirer": "^12.9.6",
|
|
92
|
+
"lint-staged": "^16.2.7",
|
|
90
93
|
"micromatch": "^4.0.8",
|
|
91
94
|
"nyc": "^17.1.0",
|
|
92
|
-
"prettier": "^3.
|
|
95
|
+
"prettier": "^3.8.1",
|
|
93
96
|
"ps-list": "^9.0.0",
|
|
94
97
|
"rollup": "^4.52.4",
|
|
95
98
|
"semver": "^7.7.3",
|
|
96
99
|
"serve": "^14.2.5",
|
|
100
|
+
"tsc-files": "^1.1.4",
|
|
97
101
|
"tslib": "^2.8.1",
|
|
98
102
|
"typescript": "^5.9.3",
|
|
99
103
|
"typescript-eslint": "^8.46.0",
|
|
100
104
|
"v8-to-istanbul": "^9.3.0",
|
|
101
|
-
"vitest": "^4.0.
|
|
105
|
+
"vitest": "^4.0.18",
|
|
102
106
|
"westures": "^1.1.1"
|
|
103
107
|
},
|
|
104
108
|
"engines": {
|
|
@@ -153,5 +157,10 @@
|
|
|
153
157
|
"optionalDependencies": {
|
|
154
158
|
"canvas": "^3.2.0",
|
|
155
159
|
"jsdom": "^26.1.0"
|
|
160
|
+
},
|
|
161
|
+
"lint-staged": {
|
|
162
|
+
"*.{js,md,css,ts,tsx,jsx,json}": "eslint --fix",
|
|
163
|
+
"*.{js,css,md,ts,tsx,jsx,json}": "prettier --write",
|
|
164
|
+
"**/*.ts !(**/*.spec.ts) !(**/*.test.ts) !(vitest*.ts)": "tsc-files --noEmit"
|
|
156
165
|
}
|
|
157
166
|
}
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ClassRegistry,
|
|
3
|
-
classRegistry as genericClassRegistryInstance,
|
|
4
|
-
JSON,
|
|
5
|
-
} from './ClassRegistry';
|
|
6
|
-
import './shapes/Object/FabricObject';
|
|
1
|
+
import type { ClassRegistry } from './ClassRegistry';
|
|
7
2
|
|
|
8
|
-
import { describe, expect, beforeEach, it } from 'vitest';
|
|
3
|
+
import { describe, expect, beforeEach, afterEach, it, vi } from 'vitest';
|
|
9
4
|
|
|
10
5
|
describe('ClassRegistry', () => {
|
|
11
6
|
let classRegistry: ClassRegistry;
|
|
12
|
-
beforeEach(() => {
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
const { ClassRegistry } = await import('./ClassRegistry');
|
|
13
9
|
classRegistry = new ClassRegistry();
|
|
14
10
|
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
vi.resetModules();
|
|
13
|
+
});
|
|
15
14
|
it('will error if a class is request that is not registered', () => {
|
|
16
15
|
expect(() => classRegistry.getClass('any')).toThrow(
|
|
17
16
|
'No class registered for any',
|
|
@@ -57,30 +56,30 @@ describe('ClassRegistry', () => {
|
|
|
57
56
|
expect(resolved, 'resolved different classes').not.toBe(resolvedSvg);
|
|
58
57
|
});
|
|
59
58
|
it('legacy resolution preparation', async () => {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
expect(
|
|
65
|
-
expect(
|
|
66
|
-
expect(
|
|
67
|
-
expect(genericClassRegistryInstance.has('object')).toBe(false);
|
|
59
|
+
const { classRegistry: freshRegistry } = await import('./ClassRegistry');
|
|
60
|
+
|
|
61
|
+
// Registry should be empty before any shape classes are imported
|
|
62
|
+
expect(freshRegistry.has('rect')).toBe(false);
|
|
63
|
+
expect(freshRegistry.has('i-text')).toBe(false);
|
|
64
|
+
expect(freshRegistry.has('activeSelection')).toBe(false);
|
|
65
|
+
expect(freshRegistry.has('object')).toBe(false);
|
|
68
66
|
});
|
|
69
67
|
it('legacy resolution', async () => {
|
|
68
|
+
const { classRegistry: freshRegistry } = await import('./ClassRegistry');
|
|
70
69
|
const { Rect } = await import('./shapes/Rect');
|
|
71
70
|
const { IText } = await import('./shapes/IText/IText');
|
|
72
71
|
const { ActiveSelection } = await import('./shapes/ActiveSelection');
|
|
73
72
|
// const { FabricObject } = await import('./shapes/Object/FabricObject');
|
|
74
73
|
expect(
|
|
75
|
-
|
|
74
|
+
freshRegistry.getClass('rect'),
|
|
76
75
|
'resolves Rect class correctly',
|
|
77
76
|
).toBe(Rect);
|
|
78
77
|
expect(
|
|
79
|
-
|
|
78
|
+
freshRegistry.getClass('i-text'),
|
|
80
79
|
'resolves IText class correctly',
|
|
81
80
|
).toBe(IText);
|
|
82
81
|
expect(
|
|
83
|
-
|
|
82
|
+
freshRegistry.getClass('activeSelection'),
|
|
84
83
|
'resolves ActiveSelection class correctly',
|
|
85
84
|
).toBe(ActiveSelection);
|
|
86
85
|
// expect(
|
package/src/EventTypeDefs.ts
CHANGED
|
@@ -94,6 +94,8 @@ export type Transform = {
|
|
|
94
94
|
original: ReturnType<typeof saveObjectTransform> & {
|
|
95
95
|
originX: TOriginX;
|
|
96
96
|
originY: TOriginY;
|
|
97
|
+
cropX?: number;
|
|
98
|
+
cropY?: number;
|
|
97
99
|
};
|
|
98
100
|
actionPerformed: boolean;
|
|
99
101
|
};
|
|
@@ -106,8 +108,9 @@ interface TEventWithTarget<E extends Event = TPointerEvent> extends TEvent<E> {
|
|
|
106
108
|
target: FabricObject;
|
|
107
109
|
}
|
|
108
110
|
|
|
109
|
-
export interface BasicTransformEvent<
|
|
110
|
-
extends
|
|
111
|
+
export interface BasicTransformEvent<
|
|
112
|
+
E extends Event = TPointerEvent,
|
|
113
|
+
> extends TEvent<E> {
|
|
111
114
|
transform: Transform;
|
|
112
115
|
/* This pointer is usually a scenePoint. It isn't in the case of actions inside groups,
|
|
113
116
|
* where it becomes a point relative to the group center
|
|
@@ -161,8 +164,9 @@ type CanvasModificationEvents = {
|
|
|
161
164
|
'object:modified': ModifiedEvent;
|
|
162
165
|
};
|
|
163
166
|
|
|
164
|
-
export interface TPointerEventInfo<
|
|
165
|
-
extends
|
|
167
|
+
export interface TPointerEventInfo<
|
|
168
|
+
E extends TPointerEvent = TPointerEvent,
|
|
169
|
+
> extends TEvent<E> {
|
|
166
170
|
target?: FabricObject;
|
|
167
171
|
subTargets?: FabricObject[];
|
|
168
172
|
transform?: Transform | null;
|
|
@@ -170,8 +174,9 @@ export interface TPointerEventInfo<E extends TPointerEvent = TPointerEvent>
|
|
|
170
174
|
viewportPoint: Point;
|
|
171
175
|
}
|
|
172
176
|
|
|
173
|
-
interface SimpleEventHandler<
|
|
174
|
-
extends
|
|
177
|
+
interface SimpleEventHandler<
|
|
178
|
+
T extends Event = TPointerEvent,
|
|
179
|
+
> extends TEvent<T> {
|
|
175
180
|
target?: FabricObject;
|
|
176
181
|
subTargets: FabricObject[];
|
|
177
182
|
}
|
|
@@ -286,10 +291,7 @@ export interface MiscEvents {
|
|
|
286
291
|
}
|
|
287
292
|
|
|
288
293
|
export interface ObjectEvents
|
|
289
|
-
extends ObjectPointerEvents,
|
|
290
|
-
DnDEvents,
|
|
291
|
-
MiscEvents,
|
|
292
|
-
ObjectModificationEvents {
|
|
294
|
+
extends ObjectPointerEvents, DnDEvents, MiscEvents, ObjectModificationEvents {
|
|
293
295
|
// selection
|
|
294
296
|
selected: Partial<TEvent> & {
|
|
295
297
|
target: FabricObject;
|
|
@@ -303,6 +305,7 @@ export interface ObjectEvents
|
|
|
303
305
|
|
|
304
306
|
// erasing
|
|
305
307
|
'erasing:end': { path: FabricObject };
|
|
308
|
+
'before:render': { ctx: CanvasRenderingContext2D };
|
|
306
309
|
}
|
|
307
310
|
|
|
308
311
|
export interface StaticCanvasEvents extends CollectionEvents {
|
|
@@ -317,7 +320,8 @@ export interface StaticCanvasEvents extends CollectionEvents {
|
|
|
317
320
|
}
|
|
318
321
|
|
|
319
322
|
export interface CanvasEvents
|
|
320
|
-
extends
|
|
323
|
+
extends
|
|
324
|
+
StaticCanvasEvents,
|
|
321
325
|
CanvasPointerEvents,
|
|
322
326
|
CanvasDnDEvents,
|
|
323
327
|
MiscEvents,
|
|
@@ -187,4 +187,16 @@ describe('Pattern', () => {
|
|
|
187
187
|
const obj = await Rect.fromObject(rectObj);
|
|
188
188
|
expect(obj.fill instanceof Pattern).toBeTruthy();
|
|
189
189
|
});
|
|
190
|
+
|
|
191
|
+
describe('attribute injection', () => {
|
|
192
|
+
it('escapes correctly the src', () => {
|
|
193
|
+
const pattern = new Pattern({
|
|
194
|
+
source: { src: '"><svg onload=alert(1)>', width: 10, height: 10 },
|
|
195
|
+
});
|
|
196
|
+
const svg = pattern.toSVG({ width: 100, height: 100 });
|
|
197
|
+
expect(svg).toContain(
|
|
198
|
+
'xlink:href=""><svg onload=alert(1)>"',
|
|
199
|
+
);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
190
202
|
});
|
package/src/Pattern/Pattern.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
SerializedPatternOptions,
|
|
13
13
|
} from './types';
|
|
14
14
|
import { log } from '../util/internals/console';
|
|
15
|
+
import { escapeXml } from '../util/lang_string';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* @see {@link http://fabric5.fabricjs.com/patterns demo}
|
|
@@ -177,12 +178,12 @@ export class Pattern {
|
|
|
177
178
|
: ifNaN((patternSource as HTMLImageElement).height / height, 0);
|
|
178
179
|
|
|
179
180
|
return [
|
|
180
|
-
`<pattern id="SVGID_${id}" x="${patternOffsetX}" y="${patternOffsetY}" width="${patternWidth}" height="${patternHeight}">`,
|
|
181
|
+
`<pattern id="SVGID_${escapeXml(id)}" x="${patternOffsetX}" y="${patternOffsetY}" width="${patternWidth}" height="${patternHeight}">`,
|
|
181
182
|
`<image x="0" y="0" width="${
|
|
182
183
|
(patternSource as HTMLImageElement).width
|
|
183
184
|
}" height="${
|
|
184
185
|
(patternSource as HTMLImageElement).height
|
|
185
|
-
}" xlink:href="${this.sourceToString()}"></image>`,
|
|
186
|
+
}" xlink:href="${escapeXml(this.sourceToString())}"></image>`,
|
|
186
187
|
`</pattern>`,
|
|
187
188
|
'',
|
|
188
189
|
].join('\n');
|