@overtone-art/canvas-editor-core 0.1.0 → 0.2.1
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/dist/index.d.mts +214 -1
- package/dist/index.d.ts +214 -1
- package/dist/index.js +664 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +651 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -9,6 +9,12 @@ interface LayerData {
|
|
|
9
9
|
visible: boolean;
|
|
10
10
|
locked: boolean;
|
|
11
11
|
opacity: number;
|
|
12
|
+
/** Non-fabric metadata persisted with the layer (pattern config, etc). */
|
|
13
|
+
meta?: LayerMeta;
|
|
14
|
+
}
|
|
15
|
+
interface LayerMeta {
|
|
16
|
+
pattern?: PatternState;
|
|
17
|
+
[key: string]: unknown;
|
|
12
18
|
}
|
|
13
19
|
interface SerializedLayer extends LayerData {
|
|
14
20
|
fabricObject: Record<string, unknown>;
|
|
@@ -21,6 +27,7 @@ interface EditorState {
|
|
|
21
27
|
};
|
|
22
28
|
layers: SerializedLayer[];
|
|
23
29
|
background?: string;
|
|
30
|
+
mockup?: MockupConfig | null;
|
|
24
31
|
}
|
|
25
32
|
interface EditorConfig {
|
|
26
33
|
width: number;
|
|
@@ -71,6 +78,53 @@ interface PrintifyPositioning {
|
|
|
71
78
|
scale: number;
|
|
72
79
|
angle: number;
|
|
73
80
|
}
|
|
81
|
+
type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';
|
|
82
|
+
interface PatternConfig {
|
|
83
|
+
mode: TileMode;
|
|
84
|
+
/** Extra horizontal gap between tiles, as % of tile width. */
|
|
85
|
+
horizontalSpacing: number;
|
|
86
|
+
/** Extra vertical gap between tiles, as % of tile height. */
|
|
87
|
+
verticalSpacing: number;
|
|
88
|
+
/** Rotation of the whole pattern, in degrees. */
|
|
89
|
+
angle: number;
|
|
90
|
+
/** Brick row/column shift, as % of tile size. */
|
|
91
|
+
horizontalOffset: number;
|
|
92
|
+
/** Added rotation per horizontal step, in degrees. */
|
|
93
|
+
rotationStepH: number;
|
|
94
|
+
/** Added rotation per vertical step, in degrees. */
|
|
95
|
+
rotationStepV: number;
|
|
96
|
+
}
|
|
97
|
+
/** Persisted on a layer's meta while it is rendered as a repeating pattern. */
|
|
98
|
+
interface PatternState {
|
|
99
|
+
config: PatternConfig;
|
|
100
|
+
/** Original (pre-pattern) image source, as a durable data URL when possible. */
|
|
101
|
+
originalSrc: string;
|
|
102
|
+
/** Original fabric transform, restored when the pattern is turned off. */
|
|
103
|
+
original: {
|
|
104
|
+
left: number;
|
|
105
|
+
top: number;
|
|
106
|
+
scaleX: number;
|
|
107
|
+
scaleY: number;
|
|
108
|
+
width: number;
|
|
109
|
+
height: number;
|
|
110
|
+
angle: number;
|
|
111
|
+
cropX: number;
|
|
112
|
+
cropY: number;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
declare const DEFAULT_PATTERN_CONFIG: PatternConfig;
|
|
116
|
+
interface MockupPrintArea {
|
|
117
|
+
left: number;
|
|
118
|
+
top: number;
|
|
119
|
+
width: number;
|
|
120
|
+
height: number;
|
|
121
|
+
}
|
|
122
|
+
interface MockupConfig {
|
|
123
|
+
/** Garment/product image rendered behind the design (preview only). */
|
|
124
|
+
image: string;
|
|
125
|
+
/** Print-area rectangle, in canvas pixels. Drawn as a guide. */
|
|
126
|
+
printArea?: MockupPrintArea;
|
|
127
|
+
}
|
|
74
128
|
interface EditorEvents {
|
|
75
129
|
'layer:added': {
|
|
76
130
|
layer: LayerData;
|
|
@@ -97,6 +151,19 @@ interface EditorEvents {
|
|
|
97
151
|
canUndo: boolean;
|
|
98
152
|
canRedo: boolean;
|
|
99
153
|
};
|
|
154
|
+
'zoom:changed': {
|
|
155
|
+
zoom: number;
|
|
156
|
+
};
|
|
157
|
+
'snap:changed': {
|
|
158
|
+
enabled: boolean;
|
|
159
|
+
};
|
|
160
|
+
'crop:changed': {
|
|
161
|
+
active: boolean;
|
|
162
|
+
layerId: string | null;
|
|
163
|
+
};
|
|
164
|
+
'mockup:changed': {
|
|
165
|
+
mockup: MockupConfig | null;
|
|
166
|
+
};
|
|
100
167
|
'canvas:modified': Record<string, never>;
|
|
101
168
|
'export:start': {
|
|
102
169
|
format: string;
|
|
@@ -128,8 +195,11 @@ declare class Layer {
|
|
|
128
195
|
visible: boolean;
|
|
129
196
|
locked: boolean;
|
|
130
197
|
opacity: number;
|
|
198
|
+
/** Non-fabric data (e.g. pattern config) that must persist with the layer. */
|
|
199
|
+
meta: LayerMeta;
|
|
131
200
|
readonly fabricObject: FabricObject;
|
|
132
201
|
constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
|
|
202
|
+
private hasMeta;
|
|
133
203
|
toData(): LayerData;
|
|
134
204
|
serialize(): SerializedLayer;
|
|
135
205
|
}
|
|
@@ -175,15 +245,128 @@ declare class HistoryManager {
|
|
|
175
245
|
saveImmediate(): void;
|
|
176
246
|
undo(): Promise<void>;
|
|
177
247
|
redo(): Promise<void>;
|
|
248
|
+
/** True while a restore (undo/redo/deserialize) is in flight. Managers that
|
|
249
|
+
* react to canvas events should skip mutating history during this window. */
|
|
250
|
+
isRestoring(): boolean;
|
|
178
251
|
pause(): void;
|
|
179
252
|
resume(): void;
|
|
180
253
|
canUndo(): boolean;
|
|
181
254
|
canRedo(): boolean;
|
|
182
255
|
clear(): void;
|
|
256
|
+
private cancelPending;
|
|
183
257
|
dispose(): void;
|
|
184
258
|
private emitChanged;
|
|
185
259
|
}
|
|
186
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Snaps a dragged object's edges and centre to the canvas edges/centre and to
|
|
263
|
+
* other objects, drawing transient guide lines while it does. Switchable via
|
|
264
|
+
* {@link setEnabled}; inert (zero overhead beyond a flag check) when disabled.
|
|
265
|
+
*/
|
|
266
|
+
declare class SnapManager {
|
|
267
|
+
private canvas;
|
|
268
|
+
private events;
|
|
269
|
+
private enabled;
|
|
270
|
+
private threshold;
|
|
271
|
+
private guides;
|
|
272
|
+
private readonly onMoving;
|
|
273
|
+
private readonly onAfterRender;
|
|
274
|
+
private readonly onModified;
|
|
275
|
+
constructor(canvas: Canvas, events: EventEmitter<EditorEvents>);
|
|
276
|
+
setEnabled(enabled: boolean): void;
|
|
277
|
+
isEnabled(): boolean;
|
|
278
|
+
setThreshold(px: number): void;
|
|
279
|
+
dispose(): void;
|
|
280
|
+
private handleMoving;
|
|
281
|
+
private drawGuides;
|
|
282
|
+
private clearGuides;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Interactive crop for image layers. {@link start} drops a draggable/resizable
|
|
287
|
+
* rectangle over the image; {@link apply} converts it into fabric crop props
|
|
288
|
+
* (cropX/cropY/width/height in element pixels) and keeps the displayed size in
|
|
289
|
+
* sync with the rectangle.
|
|
290
|
+
*
|
|
291
|
+
* Rotation is unsupported: an angled image is normalised to 0° on start.
|
|
292
|
+
*/
|
|
293
|
+
declare class CropController {
|
|
294
|
+
private canvas;
|
|
295
|
+
private history;
|
|
296
|
+
private events;
|
|
297
|
+
private session;
|
|
298
|
+
private readonly onSelectionCleared;
|
|
299
|
+
constructor(canvas: Canvas, history: HistoryManager, events: EventEmitter<EditorEvents>);
|
|
300
|
+
isActive(): boolean;
|
|
301
|
+
activeLayerId(): string | null;
|
|
302
|
+
start(layer: Layer): void;
|
|
303
|
+
apply(): void;
|
|
304
|
+
cancel(): void;
|
|
305
|
+
dispose(): void;
|
|
306
|
+
private finish;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Renders a single image layer as a repeating pattern that fills the canvas.
|
|
311
|
+
*
|
|
312
|
+
* The tiled result is rasterised onto an offscreen canvas and swapped in as the
|
|
313
|
+
* layer's image source, so it survives export, serialization and undo/redo with
|
|
314
|
+
* no extra machinery. The original source + transform are kept in `layer.meta`
|
|
315
|
+
* so the pattern can be turned back off.
|
|
316
|
+
*/
|
|
317
|
+
declare class PatternManager {
|
|
318
|
+
private canvas;
|
|
319
|
+
private layers;
|
|
320
|
+
private history;
|
|
321
|
+
private chains;
|
|
322
|
+
constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager);
|
|
323
|
+
isPattern(layerId: string): boolean;
|
|
324
|
+
getConfig(layerId: string): PatternConfig | null;
|
|
325
|
+
/** Turn a plain image layer into a pattern, or update an existing one. */
|
|
326
|
+
apply(layerId: string, config: PatternConfig): Promise<void>;
|
|
327
|
+
/** Restore the original image and drop the pattern. */
|
|
328
|
+
disable(layerId: string): Promise<void>;
|
|
329
|
+
/** Run `task` after any in-flight work for this layer, regardless of outcome. */
|
|
330
|
+
private enqueue;
|
|
331
|
+
private renderLayer;
|
|
332
|
+
}
|
|
333
|
+
/** Clear the decoded-image cache (e.g. on teardown). Exported for completeness. */
|
|
334
|
+
declare function clearPatternImageCache(): void;
|
|
335
|
+
/**
|
|
336
|
+
* Draw the source image repeatedly across a `targetW × targetH` offscreen
|
|
337
|
+
* canvas and return the result as a PNG data URL.
|
|
338
|
+
*
|
|
339
|
+
* Exported for unit testing of the tile geometry.
|
|
340
|
+
*/
|
|
341
|
+
declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): Promise<string>;
|
|
342
|
+
/** Placement of one tile, relative to the (already rotated) pattern centre. */
|
|
343
|
+
interface TilePlacement {
|
|
344
|
+
/** Tile-centre offset from the pattern centre, in px. */
|
|
345
|
+
x: number;
|
|
346
|
+
y: number;
|
|
347
|
+
/** Per-tile rotation, in radians. */
|
|
348
|
+
rotation: number;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Pure tile geometry: where each tile centre lands and how much it is rotated,
|
|
352
|
+
* for a config + target/base size. Covers the rotated bounding diagonal so
|
|
353
|
+
* corners stay filled at any pattern angle. Extracted for unit testing.
|
|
354
|
+
*/
|
|
355
|
+
declare function computeTilePositions(config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): TilePlacement[];
|
|
356
|
+
/**
|
|
357
|
+
* Draw the tiled pattern onto a 2D context. The geometry lives in
|
|
358
|
+
* {@link computeTilePositions}; this just plays it out as canvas calls.
|
|
359
|
+
*/
|
|
360
|
+
declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): void;
|
|
361
|
+
/** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */
|
|
362
|
+
interface CanvasRenderingProtocol {
|
|
363
|
+
save(): void;
|
|
364
|
+
restore(): void;
|
|
365
|
+
translate(x: number, y: number): void;
|
|
366
|
+
rotate(angle: number): void;
|
|
367
|
+
drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
|
|
368
|
+
}
|
|
369
|
+
|
|
187
370
|
declare class UnitConverter {
|
|
188
371
|
private unit;
|
|
189
372
|
private dpi;
|
|
@@ -211,8 +394,14 @@ declare class CanvasEditor {
|
|
|
211
394
|
readonly history: HistoryManager;
|
|
212
395
|
readonly events: EventEmitter<EditorEvents>;
|
|
213
396
|
readonly units: UnitConverter;
|
|
397
|
+
readonly snapping: SnapManager;
|
|
398
|
+
readonly crop: CropController;
|
|
399
|
+
readonly patterns: PatternManager;
|
|
214
400
|
private fileAdapter?;
|
|
215
401
|
private imageProvider?;
|
|
402
|
+
private zoomLevel;
|
|
403
|
+
private mockup;
|
|
404
|
+
private designBackground;
|
|
216
405
|
constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
|
|
217
406
|
addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
|
|
218
407
|
addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
|
|
@@ -221,11 +410,21 @@ declare class CanvasEditor {
|
|
|
221
410
|
removeLayer(id: string): void;
|
|
222
411
|
selectLayer(id: string | null): void;
|
|
223
412
|
getSelectedLayer(): Layer | null;
|
|
413
|
+
/** Mirror a layer along the given axis. */
|
|
414
|
+
flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
|
|
415
|
+
/** Clone a layer (offset slightly) and select the copy. */
|
|
416
|
+
duplicateLayer(id: string): Promise<Layer | null>;
|
|
224
417
|
toJSON(): EditorState;
|
|
225
418
|
fromJSON(state: EditorState): Promise<void>;
|
|
226
419
|
toPNG(options?: PngExportOptions): Promise<Blob>;
|
|
227
420
|
toSVG(): string;
|
|
228
421
|
toDataURL(format?: ImageFormat, multiplier?: number): string;
|
|
422
|
+
/**
|
|
423
|
+
* Run an export with the configured design background applied, even when a
|
|
424
|
+
* mockup preview has forced the live canvas transparent — so exports reflect
|
|
425
|
+
* the design, not the preview. Restores the preview state afterwards.
|
|
426
|
+
*/
|
|
427
|
+
private withDesignBackground;
|
|
229
428
|
toPrintifyPositioning(): Record<string, PrintifyPositioning>;
|
|
230
429
|
save(filename: string, format: 'png' | 'svg' | 'json'): Promise<string | undefined>;
|
|
231
430
|
uploadImage(file: File): Promise<ImageProviderResult | undefined>;
|
|
@@ -233,8 +432,22 @@ declare class CanvasEditor {
|
|
|
233
432
|
setFileAdapter(adapter: FileAdapter): void;
|
|
234
433
|
setImageProvider(provider: ImageProvider): void;
|
|
235
434
|
setBackground(color: string): void;
|
|
435
|
+
getDesignBackground(): string;
|
|
236
436
|
resize(width: number, height: number): void;
|
|
437
|
+
setZoom(level: number): void;
|
|
438
|
+
/** @deprecated use setZoom — kept for backward compatibility. */
|
|
237
439
|
zoom(level: number): void;
|
|
440
|
+
getZoom(): number;
|
|
441
|
+
zoomIn(step?: number): void;
|
|
442
|
+
zoomOut(step?: number): void;
|
|
443
|
+
resetZoom(): void;
|
|
444
|
+
/** Fit the canvas inside a viewport (in px), accounting for padding. */
|
|
445
|
+
zoomToFit(viewportWidth: number, viewportHeight: number, padding?: number): void;
|
|
446
|
+
applyPattern(layerId: string, config: PatternConfig): Promise<void>;
|
|
447
|
+
clearPattern(layerId: string): Promise<void>;
|
|
448
|
+
setMockup(mockup: MockupConfig | null): void;
|
|
449
|
+
clearMockup(): void;
|
|
450
|
+
getMockup(): MockupConfig | null;
|
|
238
451
|
dispose(): void;
|
|
239
452
|
private setupCanvasEvents;
|
|
240
453
|
}
|
|
@@ -247,4 +460,4 @@ declare function round2(v: number): number;
|
|
|
247
460
|
declare function serializeEditor(editor: CanvasEditor): EditorState;
|
|
248
461
|
declare function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void>;
|
|
249
462
|
|
|
250
|
-
export { CanvasEditor, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerType, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, type TemplateDefinition, type TemplateParameter, type Unit, UnitConverter, clamp, deserializeEditor, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };
|
|
463
|
+
export { CanvasEditor, CropController, DEFAULT_PATTERN_CONFIG, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerMeta, type LayerType, type MockupConfig, type MockupPrintArea, type PatternConfig, PatternManager, type PatternState, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, SnapManager, type TemplateDefinition, type TemplateParameter, type TileMode, type TilePlacement, type Unit, UnitConverter, buildPatternDataURL, clamp, clearPatternImageCache, computeTilePositions, deserializeEditor, drawTiles, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };
|
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ interface LayerData {
|
|
|
9
9
|
visible: boolean;
|
|
10
10
|
locked: boolean;
|
|
11
11
|
opacity: number;
|
|
12
|
+
/** Non-fabric metadata persisted with the layer (pattern config, etc). */
|
|
13
|
+
meta?: LayerMeta;
|
|
14
|
+
}
|
|
15
|
+
interface LayerMeta {
|
|
16
|
+
pattern?: PatternState;
|
|
17
|
+
[key: string]: unknown;
|
|
12
18
|
}
|
|
13
19
|
interface SerializedLayer extends LayerData {
|
|
14
20
|
fabricObject: Record<string, unknown>;
|
|
@@ -21,6 +27,7 @@ interface EditorState {
|
|
|
21
27
|
};
|
|
22
28
|
layers: SerializedLayer[];
|
|
23
29
|
background?: string;
|
|
30
|
+
mockup?: MockupConfig | null;
|
|
24
31
|
}
|
|
25
32
|
interface EditorConfig {
|
|
26
33
|
width: number;
|
|
@@ -71,6 +78,53 @@ interface PrintifyPositioning {
|
|
|
71
78
|
scale: number;
|
|
72
79
|
angle: number;
|
|
73
80
|
}
|
|
81
|
+
type TileMode = 'grid' | 'brick-horizontal' | 'brick-vertical';
|
|
82
|
+
interface PatternConfig {
|
|
83
|
+
mode: TileMode;
|
|
84
|
+
/** Extra horizontal gap between tiles, as % of tile width. */
|
|
85
|
+
horizontalSpacing: number;
|
|
86
|
+
/** Extra vertical gap between tiles, as % of tile height. */
|
|
87
|
+
verticalSpacing: number;
|
|
88
|
+
/** Rotation of the whole pattern, in degrees. */
|
|
89
|
+
angle: number;
|
|
90
|
+
/** Brick row/column shift, as % of tile size. */
|
|
91
|
+
horizontalOffset: number;
|
|
92
|
+
/** Added rotation per horizontal step, in degrees. */
|
|
93
|
+
rotationStepH: number;
|
|
94
|
+
/** Added rotation per vertical step, in degrees. */
|
|
95
|
+
rotationStepV: number;
|
|
96
|
+
}
|
|
97
|
+
/** Persisted on a layer's meta while it is rendered as a repeating pattern. */
|
|
98
|
+
interface PatternState {
|
|
99
|
+
config: PatternConfig;
|
|
100
|
+
/** Original (pre-pattern) image source, as a durable data URL when possible. */
|
|
101
|
+
originalSrc: string;
|
|
102
|
+
/** Original fabric transform, restored when the pattern is turned off. */
|
|
103
|
+
original: {
|
|
104
|
+
left: number;
|
|
105
|
+
top: number;
|
|
106
|
+
scaleX: number;
|
|
107
|
+
scaleY: number;
|
|
108
|
+
width: number;
|
|
109
|
+
height: number;
|
|
110
|
+
angle: number;
|
|
111
|
+
cropX: number;
|
|
112
|
+
cropY: number;
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
declare const DEFAULT_PATTERN_CONFIG: PatternConfig;
|
|
116
|
+
interface MockupPrintArea {
|
|
117
|
+
left: number;
|
|
118
|
+
top: number;
|
|
119
|
+
width: number;
|
|
120
|
+
height: number;
|
|
121
|
+
}
|
|
122
|
+
interface MockupConfig {
|
|
123
|
+
/** Garment/product image rendered behind the design (preview only). */
|
|
124
|
+
image: string;
|
|
125
|
+
/** Print-area rectangle, in canvas pixels. Drawn as a guide. */
|
|
126
|
+
printArea?: MockupPrintArea;
|
|
127
|
+
}
|
|
74
128
|
interface EditorEvents {
|
|
75
129
|
'layer:added': {
|
|
76
130
|
layer: LayerData;
|
|
@@ -97,6 +151,19 @@ interface EditorEvents {
|
|
|
97
151
|
canUndo: boolean;
|
|
98
152
|
canRedo: boolean;
|
|
99
153
|
};
|
|
154
|
+
'zoom:changed': {
|
|
155
|
+
zoom: number;
|
|
156
|
+
};
|
|
157
|
+
'snap:changed': {
|
|
158
|
+
enabled: boolean;
|
|
159
|
+
};
|
|
160
|
+
'crop:changed': {
|
|
161
|
+
active: boolean;
|
|
162
|
+
layerId: string | null;
|
|
163
|
+
};
|
|
164
|
+
'mockup:changed': {
|
|
165
|
+
mockup: MockupConfig | null;
|
|
166
|
+
};
|
|
100
167
|
'canvas:modified': Record<string, never>;
|
|
101
168
|
'export:start': {
|
|
102
169
|
format: string;
|
|
@@ -128,8 +195,11 @@ declare class Layer {
|
|
|
128
195
|
visible: boolean;
|
|
129
196
|
locked: boolean;
|
|
130
197
|
opacity: number;
|
|
198
|
+
/** Non-fabric data (e.g. pattern config) that must persist with the layer. */
|
|
199
|
+
meta: LayerMeta;
|
|
131
200
|
readonly fabricObject: FabricObject;
|
|
132
201
|
constructor(type: LayerType, fabricObject: FabricObject, name?: string, id?: string);
|
|
202
|
+
private hasMeta;
|
|
133
203
|
toData(): LayerData;
|
|
134
204
|
serialize(): SerializedLayer;
|
|
135
205
|
}
|
|
@@ -175,15 +245,128 @@ declare class HistoryManager {
|
|
|
175
245
|
saveImmediate(): void;
|
|
176
246
|
undo(): Promise<void>;
|
|
177
247
|
redo(): Promise<void>;
|
|
248
|
+
/** True while a restore (undo/redo/deserialize) is in flight. Managers that
|
|
249
|
+
* react to canvas events should skip mutating history during this window. */
|
|
250
|
+
isRestoring(): boolean;
|
|
178
251
|
pause(): void;
|
|
179
252
|
resume(): void;
|
|
180
253
|
canUndo(): boolean;
|
|
181
254
|
canRedo(): boolean;
|
|
182
255
|
clear(): void;
|
|
256
|
+
private cancelPending;
|
|
183
257
|
dispose(): void;
|
|
184
258
|
private emitChanged;
|
|
185
259
|
}
|
|
186
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Snaps a dragged object's edges and centre to the canvas edges/centre and to
|
|
263
|
+
* other objects, drawing transient guide lines while it does. Switchable via
|
|
264
|
+
* {@link setEnabled}; inert (zero overhead beyond a flag check) when disabled.
|
|
265
|
+
*/
|
|
266
|
+
declare class SnapManager {
|
|
267
|
+
private canvas;
|
|
268
|
+
private events;
|
|
269
|
+
private enabled;
|
|
270
|
+
private threshold;
|
|
271
|
+
private guides;
|
|
272
|
+
private readonly onMoving;
|
|
273
|
+
private readonly onAfterRender;
|
|
274
|
+
private readonly onModified;
|
|
275
|
+
constructor(canvas: Canvas, events: EventEmitter<EditorEvents>);
|
|
276
|
+
setEnabled(enabled: boolean): void;
|
|
277
|
+
isEnabled(): boolean;
|
|
278
|
+
setThreshold(px: number): void;
|
|
279
|
+
dispose(): void;
|
|
280
|
+
private handleMoving;
|
|
281
|
+
private drawGuides;
|
|
282
|
+
private clearGuides;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Interactive crop for image layers. {@link start} drops a draggable/resizable
|
|
287
|
+
* rectangle over the image; {@link apply} converts it into fabric crop props
|
|
288
|
+
* (cropX/cropY/width/height in element pixels) and keeps the displayed size in
|
|
289
|
+
* sync with the rectangle.
|
|
290
|
+
*
|
|
291
|
+
* Rotation is unsupported: an angled image is normalised to 0° on start.
|
|
292
|
+
*/
|
|
293
|
+
declare class CropController {
|
|
294
|
+
private canvas;
|
|
295
|
+
private history;
|
|
296
|
+
private events;
|
|
297
|
+
private session;
|
|
298
|
+
private readonly onSelectionCleared;
|
|
299
|
+
constructor(canvas: Canvas, history: HistoryManager, events: EventEmitter<EditorEvents>);
|
|
300
|
+
isActive(): boolean;
|
|
301
|
+
activeLayerId(): string | null;
|
|
302
|
+
start(layer: Layer): void;
|
|
303
|
+
apply(): void;
|
|
304
|
+
cancel(): void;
|
|
305
|
+
dispose(): void;
|
|
306
|
+
private finish;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Renders a single image layer as a repeating pattern that fills the canvas.
|
|
311
|
+
*
|
|
312
|
+
* The tiled result is rasterised onto an offscreen canvas and swapped in as the
|
|
313
|
+
* layer's image source, so it survives export, serialization and undo/redo with
|
|
314
|
+
* no extra machinery. The original source + transform are kept in `layer.meta`
|
|
315
|
+
* so the pattern can be turned back off.
|
|
316
|
+
*/
|
|
317
|
+
declare class PatternManager {
|
|
318
|
+
private canvas;
|
|
319
|
+
private layers;
|
|
320
|
+
private history;
|
|
321
|
+
private chains;
|
|
322
|
+
constructor(canvas: Canvas, layers: LayerManager, history: HistoryManager);
|
|
323
|
+
isPattern(layerId: string): boolean;
|
|
324
|
+
getConfig(layerId: string): PatternConfig | null;
|
|
325
|
+
/** Turn a plain image layer into a pattern, or update an existing one. */
|
|
326
|
+
apply(layerId: string, config: PatternConfig): Promise<void>;
|
|
327
|
+
/** Restore the original image and drop the pattern. */
|
|
328
|
+
disable(layerId: string): Promise<void>;
|
|
329
|
+
/** Run `task` after any in-flight work for this layer, regardless of outcome. */
|
|
330
|
+
private enqueue;
|
|
331
|
+
private renderLayer;
|
|
332
|
+
}
|
|
333
|
+
/** Clear the decoded-image cache (e.g. on teardown). Exported for completeness. */
|
|
334
|
+
declare function clearPatternImageCache(): void;
|
|
335
|
+
/**
|
|
336
|
+
* Draw the source image repeatedly across a `targetW × targetH` offscreen
|
|
337
|
+
* canvas and return the result as a PNG data URL.
|
|
338
|
+
*
|
|
339
|
+
* Exported for unit testing of the tile geometry.
|
|
340
|
+
*/
|
|
341
|
+
declare function buildPatternDataURL(src: string, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): Promise<string>;
|
|
342
|
+
/** Placement of one tile, relative to the (already rotated) pattern centre. */
|
|
343
|
+
interface TilePlacement {
|
|
344
|
+
/** Tile-centre offset from the pattern centre, in px. */
|
|
345
|
+
x: number;
|
|
346
|
+
y: number;
|
|
347
|
+
/** Per-tile rotation, in radians. */
|
|
348
|
+
rotation: number;
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Pure tile geometry: where each tile centre lands and how much it is rotated,
|
|
352
|
+
* for a config + target/base size. Covers the rotated bounding diagonal so
|
|
353
|
+
* corners stay filled at any pattern angle. Extracted for unit testing.
|
|
354
|
+
*/
|
|
355
|
+
declare function computeTilePositions(config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): TilePlacement[];
|
|
356
|
+
/**
|
|
357
|
+
* Draw the tiled pattern onto a 2D context. The geometry lives in
|
|
358
|
+
* {@link computeTilePositions}; this just plays it out as canvas calls.
|
|
359
|
+
*/
|
|
360
|
+
declare function drawTiles(ctx: CanvasRenderingProtocol, img: CanvasImageSource, config: PatternConfig, targetW: number, targetH: number, baseW: number, baseH: number): void;
|
|
361
|
+
/** Minimal 2D-context surface used by {@link drawTiles}; lets tests inject a spy. */
|
|
362
|
+
interface CanvasRenderingProtocol {
|
|
363
|
+
save(): void;
|
|
364
|
+
restore(): void;
|
|
365
|
+
translate(x: number, y: number): void;
|
|
366
|
+
rotate(angle: number): void;
|
|
367
|
+
drawImage(image: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void;
|
|
368
|
+
}
|
|
369
|
+
|
|
187
370
|
declare class UnitConverter {
|
|
188
371
|
private unit;
|
|
189
372
|
private dpi;
|
|
@@ -211,8 +394,14 @@ declare class CanvasEditor {
|
|
|
211
394
|
readonly history: HistoryManager;
|
|
212
395
|
readonly events: EventEmitter<EditorEvents>;
|
|
213
396
|
readonly units: UnitConverter;
|
|
397
|
+
readonly snapping: SnapManager;
|
|
398
|
+
readonly crop: CropController;
|
|
399
|
+
readonly patterns: PatternManager;
|
|
214
400
|
private fileAdapter?;
|
|
215
401
|
private imageProvider?;
|
|
402
|
+
private zoomLevel;
|
|
403
|
+
private mockup;
|
|
404
|
+
private designBackground;
|
|
216
405
|
constructor(canvasElement: HTMLCanvasElement, config: EditorConfig);
|
|
217
406
|
addImage(url: string, options?: Partial<Record<string, unknown>>): Promise<Layer>;
|
|
218
407
|
addText(text: string, options?: Partial<Record<string, unknown>>): Layer;
|
|
@@ -221,11 +410,21 @@ declare class CanvasEditor {
|
|
|
221
410
|
removeLayer(id: string): void;
|
|
222
411
|
selectLayer(id: string | null): void;
|
|
223
412
|
getSelectedLayer(): Layer | null;
|
|
413
|
+
/** Mirror a layer along the given axis. */
|
|
414
|
+
flipLayer(id: string, axis: 'horizontal' | 'vertical'): void;
|
|
415
|
+
/** Clone a layer (offset slightly) and select the copy. */
|
|
416
|
+
duplicateLayer(id: string): Promise<Layer | null>;
|
|
224
417
|
toJSON(): EditorState;
|
|
225
418
|
fromJSON(state: EditorState): Promise<void>;
|
|
226
419
|
toPNG(options?: PngExportOptions): Promise<Blob>;
|
|
227
420
|
toSVG(): string;
|
|
228
421
|
toDataURL(format?: ImageFormat, multiplier?: number): string;
|
|
422
|
+
/**
|
|
423
|
+
* Run an export with the configured design background applied, even when a
|
|
424
|
+
* mockup preview has forced the live canvas transparent — so exports reflect
|
|
425
|
+
* the design, not the preview. Restores the preview state afterwards.
|
|
426
|
+
*/
|
|
427
|
+
private withDesignBackground;
|
|
229
428
|
toPrintifyPositioning(): Record<string, PrintifyPositioning>;
|
|
230
429
|
save(filename: string, format: 'png' | 'svg' | 'json'): Promise<string | undefined>;
|
|
231
430
|
uploadImage(file: File): Promise<ImageProviderResult | undefined>;
|
|
@@ -233,8 +432,22 @@ declare class CanvasEditor {
|
|
|
233
432
|
setFileAdapter(adapter: FileAdapter): void;
|
|
234
433
|
setImageProvider(provider: ImageProvider): void;
|
|
235
434
|
setBackground(color: string): void;
|
|
435
|
+
getDesignBackground(): string;
|
|
236
436
|
resize(width: number, height: number): void;
|
|
437
|
+
setZoom(level: number): void;
|
|
438
|
+
/** @deprecated use setZoom — kept for backward compatibility. */
|
|
237
439
|
zoom(level: number): void;
|
|
440
|
+
getZoom(): number;
|
|
441
|
+
zoomIn(step?: number): void;
|
|
442
|
+
zoomOut(step?: number): void;
|
|
443
|
+
resetZoom(): void;
|
|
444
|
+
/** Fit the canvas inside a viewport (in px), accounting for padding. */
|
|
445
|
+
zoomToFit(viewportWidth: number, viewportHeight: number, padding?: number): void;
|
|
446
|
+
applyPattern(layerId: string, config: PatternConfig): Promise<void>;
|
|
447
|
+
clearPattern(layerId: string): Promise<void>;
|
|
448
|
+
setMockup(mockup: MockupConfig | null): void;
|
|
449
|
+
clearMockup(): void;
|
|
450
|
+
getMockup(): MockupConfig | null;
|
|
238
451
|
dispose(): void;
|
|
239
452
|
private setupCanvasEvents;
|
|
240
453
|
}
|
|
@@ -247,4 +460,4 @@ declare function round2(v: number): number;
|
|
|
247
460
|
declare function serializeEditor(editor: CanvasEditor): EditorState;
|
|
248
461
|
declare function deserializeEditor(editor: CanvasEditor, state: EditorState): Promise<void>;
|
|
249
462
|
|
|
250
|
-
export { CanvasEditor, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerType, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, type TemplateDefinition, type TemplateParameter, type Unit, UnitConverter, clamp, deserializeEditor, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };
|
|
463
|
+
export { CanvasEditor, CropController, DEFAULT_PATTERN_CONFIG, type EditorConfig, type EditorEvents, type EditorState, EventEmitter, type ExportFormat, type FileAdapter, HistoryManager, type ImageProvider, type ImageProviderResult, Layer, type LayerData, LayerManager, type LayerMeta, type LayerType, type MockupConfig, type MockupPrintArea, type PatternConfig, PatternManager, type PatternState, type PngExportOptions, type PrintifyPositioning, type SerializedLayer, type ShapePlugin, SnapManager, type TemplateDefinition, type TemplateParameter, type TileMode, type TilePlacement, type Unit, UnitConverter, buildPatternDataURL, clamp, clearPatternImageCache, computeTilePositions, deserializeEditor, drawTiles, exportDataURL, exportPNG, exportSVG, generateId, round2, serializeEditor };
|