@nasser-sw/fabric 7.0.1-beta17 → 7.0.1-beta18
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/.history/package_20251226051014.json +164 -0
- package/dist/fabric.d.ts +2 -0
- package/dist/fabric.d.ts.map +1 -1
- package/dist/fabric.min.mjs +1 -1
- package/dist/fabric.mjs +2 -0
- package/dist/fabric.mjs.map +1 -1
- package/dist/index.js +1742 -368
- 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 +1741 -369
- package/dist/index.mjs.map +1 -1
- package/dist/index.node.cjs +1742 -368
- package/dist/index.node.cjs.map +1 -1
- package/dist/index.node.mjs +1741 -369
- 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/LayoutManager/LayoutStrategies/FrameLayout.d.ts +31 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts.map +1 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.min.mjs +2 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.min.mjs.map +1 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.mjs +81 -0
- package/dist/src/LayoutManager/LayoutStrategies/FrameLayout.mjs.map +1 -0
- package/dist/src/LayoutManager/index.d.ts +1 -0
- package/dist/src/LayoutManager/index.d.ts.map +1 -1
- package/dist/src/controls/commonControls.d.ts.map +1 -1
- package/dist/src/controls/commonControls.mjs +25 -6
- package/dist/src/controls/commonControls.mjs.map +1 -1
- package/dist/src/controls/controlRendering.d.ts +20 -0
- package/dist/src/controls/controlRendering.d.ts.map +1 -1
- package/dist/src/controls/controlRendering.mjs +63 -1
- package/dist/src/controls/controlRendering.mjs.map +1 -1
- package/dist/src/shapes/Frame.d.ts +298 -0
- package/dist/src/shapes/Frame.d.ts.map +1 -0
- package/dist/src/shapes/Frame.min.mjs +2 -0
- package/dist/src/shapes/Frame.min.mjs.map +1 -0
- package/dist/src/shapes/Frame.mjs +1236 -0
- package/dist/src/shapes/Frame.mjs.map +1 -0
- package/dist/src/shapes/Object/defaultValues.d.ts.map +1 -1
- package/dist/src/shapes/Object/defaultValues.mjs +8 -7
- package/dist/src/shapes/Object/defaultValues.mjs.map +1 -1
- package/dist-extensions/fabric.d.ts +2 -0
- package/dist-extensions/fabric.d.ts.map +1 -1
- package/dist-extensions/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts +31 -0
- package/dist-extensions/src/LayoutManager/LayoutStrategies/FrameLayout.d.ts.map +1 -0
- package/dist-extensions/src/LayoutManager/index.d.ts +1 -0
- package/dist-extensions/src/LayoutManager/index.d.ts.map +1 -1
- package/dist-extensions/src/controls/commonControls.d.ts.map +1 -1
- package/dist-extensions/src/controls/controlRendering.d.ts +20 -0
- package/dist-extensions/src/controls/controlRendering.d.ts.map +1 -1
- package/dist-extensions/src/shapes/Frame.d.ts +298 -0
- package/dist-extensions/src/shapes/Frame.d.ts.map +1 -0
- package/dist-extensions/src/shapes/Object/defaultValues.d.ts.map +1 -1
- package/fabric.ts +8 -0
- package/package.json +1 -1
- package/src/LayoutManager/LayoutStrategies/FrameLayout.ts +80 -0
- package/src/LayoutManager/index.ts +1 -0
- package/src/controls/commonControls.ts +22 -0
- package/src/controls/controlRendering.ts +83 -0
- package/src/shapes/Frame.ts +1361 -0
- package/src/shapes/Object/defaultValues.ts +8 -7
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import type { TClassProperties, TOptions, Abortable, TCrossOrigin } from '../typedefs';
|
|
2
|
+
import type { FabricObject } from './Object/FabricObject';
|
|
3
|
+
import type { GroupProps, SerializedGroupProps } from './Group';
|
|
4
|
+
import { Group } from './Group';
|
|
5
|
+
import { FabricImage } from './Image';
|
|
6
|
+
/**
|
|
7
|
+
* Frame shape types supported out of the box
|
|
8
|
+
*/
|
|
9
|
+
export type FrameShapeType = 'rect' | 'circle' | 'rounded-rect' | 'custom';
|
|
10
|
+
/**
|
|
11
|
+
* Frame metadata for persistence and state management
|
|
12
|
+
*/
|
|
13
|
+
export interface FrameMeta {
|
|
14
|
+
/** Aspect ratio label (e.g., '16:9', '1:1', '4:5') */
|
|
15
|
+
aspect?: string;
|
|
16
|
+
/** Content scale factor for cover scaling */
|
|
17
|
+
contentScale?: number;
|
|
18
|
+
/** X offset of content within frame */
|
|
19
|
+
contentOffsetX?: number;
|
|
20
|
+
/** Y offset of content within frame */
|
|
21
|
+
contentOffsetY?: number;
|
|
22
|
+
/** Source URL of the current image */
|
|
23
|
+
imageSrc?: string;
|
|
24
|
+
/** Original image dimensions */
|
|
25
|
+
originalWidth?: number;
|
|
26
|
+
/** Original image dimensions */
|
|
27
|
+
originalHeight?: number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Frame-specific properties
|
|
31
|
+
*/
|
|
32
|
+
export interface FrameOwnProps {
|
|
33
|
+
/** Fixed width of the frame */
|
|
34
|
+
frameWidth: number;
|
|
35
|
+
/** Fixed height of the frame */
|
|
36
|
+
frameHeight: number;
|
|
37
|
+
/** Shape type for the clip mask */
|
|
38
|
+
frameShape: FrameShapeType;
|
|
39
|
+
/** Border radius for rounded-rect shape */
|
|
40
|
+
frameBorderRadius: number;
|
|
41
|
+
/** Custom SVG path for custom shape */
|
|
42
|
+
frameCustomPath?: string;
|
|
43
|
+
/** Frame metadata for content positioning */
|
|
44
|
+
frameMeta: FrameMeta;
|
|
45
|
+
/** Whether the frame is in edit mode (content can be repositioned) */
|
|
46
|
+
isEditMode: boolean;
|
|
47
|
+
/** Placeholder text shown when frame is empty */
|
|
48
|
+
placeholderText: string;
|
|
49
|
+
/** Placeholder background color */
|
|
50
|
+
placeholderColor: string;
|
|
51
|
+
}
|
|
52
|
+
export interface SerializedFrameProps extends SerializedGroupProps, FrameOwnProps {
|
|
53
|
+
}
|
|
54
|
+
export interface FrameProps extends GroupProps, FrameOwnProps {
|
|
55
|
+
}
|
|
56
|
+
export declare const frameDefaultValues: Partial<TClassProperties<Frame>>;
|
|
57
|
+
/**
|
|
58
|
+
* Frame class - A Canva-like frame container for images
|
|
59
|
+
*
|
|
60
|
+
* Features:
|
|
61
|
+
* - Fixed dimensions that don't change when content is added/removed
|
|
62
|
+
* - Multiple shape types (rect, circle, rounded-rect, custom SVG path)
|
|
63
|
+
* - Cover scaling: images fill the frame completely, overflow is clipped
|
|
64
|
+
* - Double-click edit mode: reposition/zoom content within frame
|
|
65
|
+
* - Drag & drop support for replacing images
|
|
66
|
+
* - Full serialization/deserialization support
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```ts
|
|
70
|
+
* // Create a rectangular frame
|
|
71
|
+
* const frame = new Frame([], {
|
|
72
|
+
* frameWidth: 300,
|
|
73
|
+
* frameHeight: 200,
|
|
74
|
+
* frameShape: 'rect',
|
|
75
|
+
* left: 100,
|
|
76
|
+
* top: 100,
|
|
77
|
+
* });
|
|
78
|
+
*
|
|
79
|
+
* // Add image with cover scaling
|
|
80
|
+
* await frame.setImage('https://example.com/image.jpg');
|
|
81
|
+
*
|
|
82
|
+
* canvas.add(frame);
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export declare class Frame extends Group {
|
|
86
|
+
static type: string;
|
|
87
|
+
frameWidth: number;
|
|
88
|
+
frameHeight: number;
|
|
89
|
+
frameShape: FrameShapeType;
|
|
90
|
+
frameBorderRadius: number;
|
|
91
|
+
frameCustomPath?: string;
|
|
92
|
+
frameMeta: FrameMeta;
|
|
93
|
+
isEditMode: boolean;
|
|
94
|
+
placeholderText: string;
|
|
95
|
+
placeholderColor: string;
|
|
96
|
+
/**
|
|
97
|
+
* Reference to the content image
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
private _contentImage;
|
|
101
|
+
/**
|
|
102
|
+
* Reference to the placeholder object
|
|
103
|
+
* @private
|
|
104
|
+
*/
|
|
105
|
+
private _placeholder;
|
|
106
|
+
static ownDefaults: Partial<TClassProperties<Frame>>;
|
|
107
|
+
static getDefaults(): Record<string, any>;
|
|
108
|
+
/**
|
|
109
|
+
* Constructor
|
|
110
|
+
* @param objects - Initial objects (typically empty for frames)
|
|
111
|
+
* @param options - Frame configuration options
|
|
112
|
+
*/
|
|
113
|
+
constructor(objects?: FabricObject[], options?: Partial<FrameProps>);
|
|
114
|
+
/**
|
|
115
|
+
* Sets up custom controls that resize instead of scale
|
|
116
|
+
* This is the key to Canva-like behavior - corners resize the frame dimensions
|
|
117
|
+
* instead of scaling the entire group (which would stretch the image)
|
|
118
|
+
* @private
|
|
119
|
+
*/
|
|
120
|
+
private _setupResizeControls;
|
|
121
|
+
/**
|
|
122
|
+
* Adjusts content after a resize operation (called from set override)
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
private _adjustContentAfterResize;
|
|
126
|
+
/**
|
|
127
|
+
* Updates the clip path based on the current frame shape
|
|
128
|
+
* @private
|
|
129
|
+
*/
|
|
130
|
+
private _updateClipPath;
|
|
131
|
+
/**
|
|
132
|
+
* Creates a placeholder element for empty frames
|
|
133
|
+
* Shows a colored rectangle - users can customize via placeholderColor
|
|
134
|
+
* @private
|
|
135
|
+
*/
|
|
136
|
+
private _createPlaceholder;
|
|
137
|
+
/**
|
|
138
|
+
* Removes the placeholder element
|
|
139
|
+
* @private
|
|
140
|
+
*/
|
|
141
|
+
private _removePlaceholder;
|
|
142
|
+
/**
|
|
143
|
+
* Restores the fixed frame dimensions
|
|
144
|
+
* @private
|
|
145
|
+
*/
|
|
146
|
+
private _restoreFixedDimensions;
|
|
147
|
+
/**
|
|
148
|
+
* Sets an image in the frame with cover scaling
|
|
149
|
+
*
|
|
150
|
+
* @param src - Image source URL
|
|
151
|
+
* @param options - Optional loading options
|
|
152
|
+
* @returns Promise that resolves when the image is loaded and set
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* ```ts
|
|
156
|
+
* await frame.setImage('https://example.com/photo.jpg');
|
|
157
|
+
* canvas.renderAll();
|
|
158
|
+
* ```
|
|
159
|
+
*/
|
|
160
|
+
setImage(src: string, options?: {
|
|
161
|
+
crossOrigin?: TCrossOrigin;
|
|
162
|
+
signal?: AbortSignal;
|
|
163
|
+
}): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Sets an image from an existing FabricImage object
|
|
166
|
+
*
|
|
167
|
+
* @param image - FabricImage instance
|
|
168
|
+
*/
|
|
169
|
+
setImageObject(image: FabricImage): void;
|
|
170
|
+
/**
|
|
171
|
+
* Calculates the cover scale factor for an image
|
|
172
|
+
* Cover scaling ensures the image fills the frame completely
|
|
173
|
+
*
|
|
174
|
+
* @param imageWidth - Original image width
|
|
175
|
+
* @param imageHeight - Original image height
|
|
176
|
+
* @returns Scale factor to apply
|
|
177
|
+
* @private
|
|
178
|
+
*/
|
|
179
|
+
private _calculateCoverScale;
|
|
180
|
+
/**
|
|
181
|
+
* Clears all content from the frame
|
|
182
|
+
* @private
|
|
183
|
+
*/
|
|
184
|
+
private _clearContent;
|
|
185
|
+
/**
|
|
186
|
+
* Clears the frame content and shows placeholder
|
|
187
|
+
*/
|
|
188
|
+
clearContent(): void;
|
|
189
|
+
/**
|
|
190
|
+
* Checks if the frame has image content
|
|
191
|
+
*/
|
|
192
|
+
hasContent(): boolean;
|
|
193
|
+
/**
|
|
194
|
+
* Gets the current content image
|
|
195
|
+
*/
|
|
196
|
+
getContentImage(): FabricImage | null;
|
|
197
|
+
/**
|
|
198
|
+
* Enters edit mode for repositioning content within the frame
|
|
199
|
+
* In edit mode, the content image can be dragged and scaled
|
|
200
|
+
*/
|
|
201
|
+
enterEditMode(): void;
|
|
202
|
+
/**
|
|
203
|
+
* Bound constraint handler references for cleanup
|
|
204
|
+
* @private
|
|
205
|
+
*/
|
|
206
|
+
private _boundConstrainMove?;
|
|
207
|
+
private _boundConstrainScale?;
|
|
208
|
+
/**
|
|
209
|
+
* Sets up constraints for edit mode - prevents gaps
|
|
210
|
+
* @private
|
|
211
|
+
*/
|
|
212
|
+
private _setupEditModeConstraints;
|
|
213
|
+
/**
|
|
214
|
+
* Removes edit mode constraint handlers
|
|
215
|
+
* @private
|
|
216
|
+
*/
|
|
217
|
+
private _removeEditModeConstraints;
|
|
218
|
+
/**
|
|
219
|
+
* Stored clip path before edit mode
|
|
220
|
+
* @private
|
|
221
|
+
*/
|
|
222
|
+
private _editModeClipPath?;
|
|
223
|
+
/**
|
|
224
|
+
* Custom render to show edit mode overlay
|
|
225
|
+
* @override
|
|
226
|
+
*/
|
|
227
|
+
render(ctx: CanvasRenderingContext2D): void;
|
|
228
|
+
/**
|
|
229
|
+
* Renders the edit mode overlay - dims area outside frame, shows frame border
|
|
230
|
+
* @private
|
|
231
|
+
*/
|
|
232
|
+
private _renderEditModeOverlay;
|
|
233
|
+
/**
|
|
234
|
+
* Exits edit mode and saves the content position
|
|
235
|
+
*/
|
|
236
|
+
exitEditMode(): void;
|
|
237
|
+
/**
|
|
238
|
+
* Toggles edit mode
|
|
239
|
+
*/
|
|
240
|
+
toggleEditMode(): void;
|
|
241
|
+
/**
|
|
242
|
+
* Resizes the frame to new dimensions (Canva-like behavior)
|
|
243
|
+
*
|
|
244
|
+
* Canva behavior:
|
|
245
|
+
* - When frame shrinks: crops more of image (no scale change)
|
|
246
|
+
* - When frame grows: uncrops to show more, preserving position
|
|
247
|
+
* - Only scales up when image can't cover the frame anymore
|
|
248
|
+
*
|
|
249
|
+
* @param width - New frame width
|
|
250
|
+
* @param height - New frame height
|
|
251
|
+
* @param options - Resize options
|
|
252
|
+
*/
|
|
253
|
+
resizeFrame(width: number, height: number, options?: {
|
|
254
|
+
maintainAspect?: boolean;
|
|
255
|
+
}): void;
|
|
256
|
+
/**
|
|
257
|
+
* Sets the frame shape
|
|
258
|
+
*
|
|
259
|
+
* @param shape - Shape type
|
|
260
|
+
* @param customPath - Custom SVG path for 'custom' shape type
|
|
261
|
+
*/
|
|
262
|
+
setFrameShape(shape: FrameShapeType, customPath?: string): void;
|
|
263
|
+
/**
|
|
264
|
+
* Sets the border radius for rounded-rect shape
|
|
265
|
+
*
|
|
266
|
+
* @param radius - Border radius in pixels
|
|
267
|
+
*/
|
|
268
|
+
setBorderRadius(radius: number): void;
|
|
269
|
+
/**
|
|
270
|
+
* Override add to maintain fixed dimensions
|
|
271
|
+
*/
|
|
272
|
+
add(...objects: FabricObject[]): number;
|
|
273
|
+
/**
|
|
274
|
+
* Override remove to maintain fixed dimensions
|
|
275
|
+
*/
|
|
276
|
+
remove(...objects: FabricObject[]): FabricObject[];
|
|
277
|
+
/**
|
|
278
|
+
* Override insertAt to maintain fixed dimensions
|
|
279
|
+
*/
|
|
280
|
+
insertAt(index: number, ...objects: FabricObject[]): number;
|
|
281
|
+
/**
|
|
282
|
+
* Serializes the frame to a plain object
|
|
283
|
+
*/
|
|
284
|
+
toObject(propertiesToInclude?: string[]): any;
|
|
285
|
+
/**
|
|
286
|
+
* Creates a Frame instance from a serialized object
|
|
287
|
+
*/
|
|
288
|
+
static fromObject<T extends TOptions<SerializedFrameProps>>(object: T, abortable?: Abortable): Promise<Frame>;
|
|
289
|
+
/**
|
|
290
|
+
* Creates a Frame with a specific aspect ratio preset
|
|
291
|
+
*
|
|
292
|
+
* @param aspect - Aspect ratio preset (e.g., '16:9', '1:1', '4:5', '9:16')
|
|
293
|
+
* @param size - Base size in pixels
|
|
294
|
+
* @param options - Additional frame options
|
|
295
|
+
*/
|
|
296
|
+
static createWithAspect(aspect: string, size?: number, options?: Partial<FrameProps>): Frame;
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=Frame.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Frame.d.ts","sourceRoot":"","sources":["../../../src/shapes/Frame.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaultValues.d.ts","sourceRoot":"","sources":["../../../../src/shapes/Object/defaultValues.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,eAAe,UAgB3B,CAAC;AAEF,eAAO,MAAM,eAAe,UAe3B,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,OAAO,CAC7C,gBAAgB,CAAC,YAAY,CAAC,CA2CtB,CAAC;AAEX,eAAO,MAAM,8BAA8B,EAAE,OAAO,CAClD,gBAAgB,CAAC,uBAAuB,CAAC,
|
|
1
|
+
{"version":3,"file":"defaultValues.d.ts","sourceRoot":"","sources":["../../../../src/shapes/Object/defaultValues.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,eAAO,MAAM,eAAe,UAgB3B,CAAC;AAEF,eAAO,MAAM,eAAe,UAe3B,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,OAAO,CAC7C,gBAAgB,CAAC,YAAY,CAAC,CA2CtB,CAAC;AAEX,eAAO,MAAM,8BAA8B,EAAE,OAAO,CAClD,gBAAgB,CAAC,uBAAuB,CAAC,CAgC1C,CAAC"}
|
package/fabric.ts
CHANGED
|
@@ -141,6 +141,14 @@ export type {
|
|
|
141
141
|
SerializedGroupProps,
|
|
142
142
|
} from './src/shapes/Group';
|
|
143
143
|
export { Group } from './src/shapes/Group';
|
|
144
|
+
export type {
|
|
145
|
+
FrameProps,
|
|
146
|
+
FrameOwnProps,
|
|
147
|
+
FrameMeta,
|
|
148
|
+
FrameShapeType,
|
|
149
|
+
SerializedFrameProps,
|
|
150
|
+
} from './src/shapes/Frame';
|
|
151
|
+
export { Frame } from './src/shapes/Frame';
|
|
144
152
|
export * from './src/LayoutManager';
|
|
145
153
|
export type { SerializedLayoutManager } from './src/LayoutManager';
|
|
146
154
|
export type {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@nasser-sw/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.0.1-
|
|
5
|
+
"version": "7.0.1-beta18",
|
|
6
6
|
"author": "Juriy Zaytsev <kangax@gmail.com>",
|
|
7
7
|
"contributors": [
|
|
8
8
|
{
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Point } from '../../Point';
|
|
2
|
+
import type { FabricObject } from '../../shapes/Object/FabricObject';
|
|
3
|
+
import { classRegistry } from '../../ClassRegistry';
|
|
4
|
+
import { LayoutStrategy } from './LayoutStrategy';
|
|
5
|
+
import type { LayoutStrategyResult, StrictLayoutContext } from '../types';
|
|
6
|
+
import { LAYOUT_TYPE_INITIALIZATION } from '../constants';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* FrameLayout is a layout strategy that maintains fixed dimensions
|
|
10
|
+
* regardless of the content inside the group.
|
|
11
|
+
*
|
|
12
|
+
* This is essential for Frame objects where:
|
|
13
|
+
* - The frame size should never change when images are added/removed
|
|
14
|
+
* - Content is clipped to the frame boundaries
|
|
15
|
+
* - The frame acts as a container with fixed dimensions
|
|
16
|
+
*/
|
|
17
|
+
export class FrameLayout extends LayoutStrategy {
|
|
18
|
+
static readonly type = 'frame-layout';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Override to prevent layout recalculation on content changes.
|
|
22
|
+
* Only perform layout during initialization or imperative calls.
|
|
23
|
+
*/
|
|
24
|
+
shouldPerformLayout({ type }: StrictLayoutContext): boolean {
|
|
25
|
+
// Only perform layout during initialization
|
|
26
|
+
// After that, the frame maintains its fixed size
|
|
27
|
+
return type === LAYOUT_TYPE_INITIALIZATION;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Calculate the bounding box for frame objects.
|
|
32
|
+
* Returns the fixed frame dimensions instead of calculating from contents.
|
|
33
|
+
*/
|
|
34
|
+
calcBoundingBox(
|
|
35
|
+
objects: FabricObject[],
|
|
36
|
+
context: StrictLayoutContext
|
|
37
|
+
): LayoutStrategyResult | undefined {
|
|
38
|
+
const { type, target } = context;
|
|
39
|
+
|
|
40
|
+
// Get fixed dimensions from frame properties
|
|
41
|
+
const frameWidth = (target as any).frameWidth ?? target.width ?? 200;
|
|
42
|
+
const frameHeight = (target as any).frameHeight ?? target.height ?? 200;
|
|
43
|
+
|
|
44
|
+
const size = new Point(frameWidth, frameHeight);
|
|
45
|
+
|
|
46
|
+
if (type === LAYOUT_TYPE_INITIALIZATION) {
|
|
47
|
+
// During initialization, use the frame's position or calculate center
|
|
48
|
+
const center = new Point(0, 0);
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
center,
|
|
52
|
+
size,
|
|
53
|
+
relativeCorrection: new Point(0, 0),
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// For any other layout triggers, return the fixed size
|
|
58
|
+
// This shouldn't normally be called due to shouldPerformLayout override
|
|
59
|
+
const center = target.getRelativeCenterPoint();
|
|
60
|
+
return {
|
|
61
|
+
center,
|
|
62
|
+
size,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Override to always return fixed frame dimensions during initialization.
|
|
68
|
+
*/
|
|
69
|
+
getInitialSize(
|
|
70
|
+
context: StrictLayoutContext,
|
|
71
|
+
result: Pick<LayoutStrategyResult, 'center' | 'size'>
|
|
72
|
+
): Point {
|
|
73
|
+
const { target } = context;
|
|
74
|
+
const frameWidth = (target as any).frameWidth ?? target.width ?? 200;
|
|
75
|
+
const frameHeight = (target as any).frameHeight ?? target.height ?? 200;
|
|
76
|
+
return new Point(frameWidth, frameHeight);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
classRegistry.setClass(FrameLayout);
|
|
@@ -2,5 +2,6 @@ export * from './LayoutManager';
|
|
|
2
2
|
export * from './LayoutStrategies/ClipPathLayout';
|
|
3
3
|
export * from './LayoutStrategies/FitContentLayout';
|
|
4
4
|
export * from './LayoutStrategies/FixedLayout';
|
|
5
|
+
export * from './LayoutStrategies/FrameLayout';
|
|
5
6
|
export * from './LayoutStrategies/LayoutStrategy';
|
|
6
7
|
export type * from './types';
|
|
@@ -2,6 +2,10 @@ import { RESIZING, ROTATE } from '../constants';
|
|
|
2
2
|
import { changeWidth } from './changeWidth';
|
|
3
3
|
import { changeHeight } from './changeHeight';
|
|
4
4
|
import { Control } from './Control';
|
|
5
|
+
import {
|
|
6
|
+
renderHorizontalPillControl,
|
|
7
|
+
renderVerticalPillControl,
|
|
8
|
+
} from './controlRendering';
|
|
5
9
|
import { rotationStyleHandler, rotationWithSnapping } from './rotate';
|
|
6
10
|
import { scaleCursorStyleHandler, scalingEqually } from './scale';
|
|
7
11
|
import {
|
|
@@ -19,6 +23,9 @@ export const createObjectDefaultControls = () => ({
|
|
|
19
23
|
cursorStyleHandler: scaleSkewCursorStyleHandler,
|
|
20
24
|
actionHandler: scalingXOrSkewingY,
|
|
21
25
|
getActionName: scaleOrSkewActionName,
|
|
26
|
+
render: renderHorizontalPillControl,
|
|
27
|
+
sizeX: 6,
|
|
28
|
+
sizeY: 20,
|
|
22
29
|
}),
|
|
23
30
|
|
|
24
31
|
mr: new Control({
|
|
@@ -27,6 +34,9 @@ export const createObjectDefaultControls = () => ({
|
|
|
27
34
|
cursorStyleHandler: scaleSkewCursorStyleHandler,
|
|
28
35
|
actionHandler: scalingXOrSkewingY,
|
|
29
36
|
getActionName: scaleOrSkewActionName,
|
|
37
|
+
render: renderHorizontalPillControl,
|
|
38
|
+
sizeX: 6,
|
|
39
|
+
sizeY: 20,
|
|
30
40
|
}),
|
|
31
41
|
|
|
32
42
|
mb: new Control({
|
|
@@ -35,6 +45,9 @@ export const createObjectDefaultControls = () => ({
|
|
|
35
45
|
cursorStyleHandler: scaleSkewCursorStyleHandler,
|
|
36
46
|
actionHandler: scalingYOrSkewingX,
|
|
37
47
|
getActionName: scaleOrSkewActionName,
|
|
48
|
+
render: renderVerticalPillControl,
|
|
49
|
+
sizeX: 20,
|
|
50
|
+
sizeY: 6,
|
|
38
51
|
}),
|
|
39
52
|
|
|
40
53
|
mt: new Control({
|
|
@@ -43,6 +56,9 @@ export const createObjectDefaultControls = () => ({
|
|
|
43
56
|
cursorStyleHandler: scaleSkewCursorStyleHandler,
|
|
44
57
|
actionHandler: scalingYOrSkewingX,
|
|
45
58
|
getActionName: scaleOrSkewActionName,
|
|
59
|
+
render: renderVerticalPillControl,
|
|
60
|
+
sizeX: 20,
|
|
61
|
+
sizeY: 6,
|
|
46
62
|
}),
|
|
47
63
|
|
|
48
64
|
tl: new Control({
|
|
@@ -91,6 +107,9 @@ export const createResizeControls = () => ({
|
|
|
91
107
|
actionHandler: changeWidth,
|
|
92
108
|
cursorStyleHandler: scaleSkewCursorStyleHandler,
|
|
93
109
|
actionName: RESIZING,
|
|
110
|
+
render: renderHorizontalPillControl,
|
|
111
|
+
sizeX: 6,
|
|
112
|
+
sizeY: 20,
|
|
94
113
|
}),
|
|
95
114
|
ml: new Control({
|
|
96
115
|
x: -0.5,
|
|
@@ -98,6 +117,9 @@ export const createResizeControls = () => ({
|
|
|
98
117
|
actionHandler: changeWidth,
|
|
99
118
|
cursorStyleHandler: scaleSkewCursorStyleHandler,
|
|
100
119
|
actionName: RESIZING,
|
|
120
|
+
render: renderHorizontalPillControl,
|
|
121
|
+
sizeX: 6,
|
|
122
|
+
sizeY: 20,
|
|
101
123
|
}),
|
|
102
124
|
});
|
|
103
125
|
|
|
@@ -3,6 +3,13 @@ import type { InteractiveFabricObject } from '../shapes/Object/InteractiveObject
|
|
|
3
3
|
import { degreesToRadians } from '../util/misc/radiansDegreesConversion';
|
|
4
4
|
import type { Control } from './Control';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Pill dimensions for side controls (Canva-style)
|
|
8
|
+
*/
|
|
9
|
+
const PILL_WIDTH = 6;
|
|
10
|
+
const PILL_HEIGHT = 20;
|
|
11
|
+
const PILL_RADIUS = 3;
|
|
12
|
+
|
|
6
13
|
export type ControlRenderingStyleOverride = Partial<
|
|
7
14
|
Pick<
|
|
8
15
|
InteractiveFabricObject,
|
|
@@ -134,3 +141,79 @@ export function renderSquareControl(
|
|
|
134
141
|
}
|
|
135
142
|
ctx.restore();
|
|
136
143
|
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Render a horizontal pill control (for left/right side handles).
|
|
147
|
+
* Modern Canva-style appearance.
|
|
148
|
+
* @param {CanvasRenderingContext2D} ctx context to render on
|
|
149
|
+
* @param {Number} left x coordinate where the control center should be
|
|
150
|
+
* @param {Number} top y coordinate where the control center should be
|
|
151
|
+
* @param {Object} styleOverride override for FabricObject controls style
|
|
152
|
+
* @param {FabricObject} fabricObject the fabric object for which we are rendering controls
|
|
153
|
+
*/
|
|
154
|
+
export function renderHorizontalPillControl(
|
|
155
|
+
this: Control,
|
|
156
|
+
ctx: CanvasRenderingContext2D,
|
|
157
|
+
left: number,
|
|
158
|
+
top: number,
|
|
159
|
+
styleOverride: ControlRenderingStyleOverride,
|
|
160
|
+
fabricObject: InteractiveFabricObject,
|
|
161
|
+
) {
|
|
162
|
+
styleOverride = styleOverride || {};
|
|
163
|
+
const width = PILL_WIDTH;
|
|
164
|
+
const height = PILL_HEIGHT;
|
|
165
|
+
const radius = PILL_RADIUS;
|
|
166
|
+
|
|
167
|
+
ctx.save();
|
|
168
|
+
ctx.translate(left, top);
|
|
169
|
+
const angle = fabricObject.getTotalAngle();
|
|
170
|
+
ctx.rotate(degreesToRadians(angle));
|
|
171
|
+
|
|
172
|
+
ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';
|
|
173
|
+
ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';
|
|
174
|
+
ctx.lineWidth = 1.5;
|
|
175
|
+
|
|
176
|
+
ctx.beginPath();
|
|
177
|
+
ctx.roundRect(-width / 2, -height / 2, width, height, radius);
|
|
178
|
+
ctx.fill();
|
|
179
|
+
ctx.stroke();
|
|
180
|
+
ctx.restore();
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Render a vertical pill control (for top/bottom side handles).
|
|
185
|
+
* Modern Canva-style appearance.
|
|
186
|
+
* @param {CanvasRenderingContext2D} ctx context to render on
|
|
187
|
+
* @param {Number} left x coordinate where the control center should be
|
|
188
|
+
* @param {Number} top y coordinate where the control center should be
|
|
189
|
+
* @param {Object} styleOverride override for FabricObject controls style
|
|
190
|
+
* @param {FabricObject} fabricObject the fabric object for which we are rendering controls
|
|
191
|
+
*/
|
|
192
|
+
export function renderVerticalPillControl(
|
|
193
|
+
this: Control,
|
|
194
|
+
ctx: CanvasRenderingContext2D,
|
|
195
|
+
left: number,
|
|
196
|
+
top: number,
|
|
197
|
+
styleOverride: ControlRenderingStyleOverride,
|
|
198
|
+
fabricObject: InteractiveFabricObject,
|
|
199
|
+
) {
|
|
200
|
+
styleOverride = styleOverride || {};
|
|
201
|
+
const width = PILL_HEIGHT; // Swapped for vertical
|
|
202
|
+
const height = PILL_WIDTH;
|
|
203
|
+
const radius = PILL_RADIUS;
|
|
204
|
+
|
|
205
|
+
ctx.save();
|
|
206
|
+
ctx.translate(left, top);
|
|
207
|
+
const angle = fabricObject.getTotalAngle();
|
|
208
|
+
ctx.rotate(degreesToRadians(angle));
|
|
209
|
+
|
|
210
|
+
ctx.fillStyle = styleOverride.cornerColor || fabricObject.cornerColor || '#ffffff';
|
|
211
|
+
ctx.strokeStyle = styleOverride.cornerStrokeColor || fabricObject.cornerStrokeColor || '#0d99ff';
|
|
212
|
+
ctx.lineWidth = 1.5;
|
|
213
|
+
|
|
214
|
+
ctx.beginPath();
|
|
215
|
+
ctx.roundRect(-width / 2, -height / 2, width, height, radius);
|
|
216
|
+
ctx.fill();
|
|
217
|
+
ctx.stroke();
|
|
218
|
+
ctx.restore();
|
|
219
|
+
}
|