@reekon-tools/boldr-utils 1.11.0 → 1.12.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/dist/annotation/canvas/AnnotationCanvasInner.native.js +48 -7
- package/dist/annotation/canvas/AnnotationCanvasSkia.d.ts +2 -2
- package/dist/annotation/canvas/AnnotationCanvasSkia.js +16 -3
- package/dist/annotation/canvas/Tool.d.ts +8 -1
- package/dist/annotation/canvas/backgroundLayers.d.ts +20 -0
- package/dist/annotation/canvas/backgroundLayers.js +98 -0
- package/dist/annotation/canvas/elements/BackgroundImageElement.d.ts +10 -7
- package/dist/annotation/canvas/elements/BackgroundImageElement.js +45 -11
- package/dist/annotation/canvas/elements/BackgroundSvg.d.ts +3 -4
- package/dist/annotation/canvas/elements/BackgroundSvg.js +23 -29
- package/dist/annotation/canvas/elements/backgroundUrl.js +2 -2
- package/dist/annotation/canvas/tools/selectTool.js +183 -19
- package/dist/annotation/canvas/useAnnotationCanvasState.js +29 -20
- package/dist/annotation/canvas/viewport.js +7 -6
- package/dist/annotation/data/AnnotationDataProvider.d.ts +1 -1
- package/dist/annotation/data/InMemoryAnnotationProvider.d.ts +1 -1
- package/dist/annotation/data/hooks/useAnnotationCanvasDoc.d.ts +7 -1
- package/dist/annotation/data/hooks/useAnnotationCanvasDoc.js +124 -22
- package/dist/annotation/data/hooks/useAnnotationMutations.d.ts +1 -1
- package/dist/exports.d.ts +1 -0
- package/dist/exports.js +1 -0
- package/dist/types/annotation.d.ts +27 -0
- package/dist/types/annotation.js +68 -0
- package/package.json +1 -1
package/dist/exports.js
CHANGED
|
@@ -36,6 +36,7 @@ export { hydrateCanvasState } from './annotation/data/canvasPersistence.js';
|
|
|
36
36
|
export { InMemoryAnnotationProvider } from './annotation/data/InMemoryAnnotationProvider.js';
|
|
37
37
|
export { STAMP_TILE_SIZE, GROUP_HEADER_TILE_WIDTH, GROUP_HEADER_TILE_HEIGHT, DEFAULT_TILE_SCALE, TILE_SCALE_MIN, TILE_SCALE_MAX, clampTileScale, resolveTileScaleFactor, tileDocSizeForFactor, tileScaleFromDocSize, stampTileSize, stampTileDims, isUnassociatedStamp, } from './annotation/canvas/stampLayout.js';
|
|
38
38
|
export { createViewportApi, fitToScreen, fitRectToScreen, imageDocRect, panBy, zoomAt, DEFAULT_VIEWPORT, } from './annotation/canvas/viewport.js';
|
|
39
|
+
export { LEGACY_BACKGROUND_LAYER_ID, BACKGROUND_PLACEMENT_GAP_RATIO, backgroundLayersOf, backgroundLayerDocRect, backgroundLayersUnionRect, placeNewBackgroundLayer, } from './annotation/canvas/backgroundLayers.js';
|
|
39
40
|
export { createPenTool, } from './annotation/canvas/tools/penTool.js';
|
|
40
41
|
export { createSelectTool, } from './annotation/canvas/tools/selectTool.js';
|
|
41
42
|
export { createMeasurementStampTool, } from './annotation/canvas/tools/measurementStampTool.js';
|
|
@@ -96,11 +96,27 @@ export interface AnnotationBackgroundImage {
|
|
|
96
96
|
heightPx: number;
|
|
97
97
|
format?: 'raster' | 'svg';
|
|
98
98
|
}
|
|
99
|
+
export interface BackgroundLayerTransform {
|
|
100
|
+
x: number;
|
|
101
|
+
y: number;
|
|
102
|
+
scaleX: number;
|
|
103
|
+
scaleY: number;
|
|
104
|
+
}
|
|
105
|
+
export interface AnnotationBackgroundLayer {
|
|
106
|
+
id: AnnotationElementId;
|
|
107
|
+
storagePath: string;
|
|
108
|
+
downloadUrl: string;
|
|
109
|
+
widthPx: number;
|
|
110
|
+
heightPx: number;
|
|
111
|
+
format?: 'raster' | 'svg';
|
|
112
|
+
transform: BackgroundLayerTransform;
|
|
113
|
+
}
|
|
99
114
|
export interface AnnotationViewport {
|
|
100
115
|
width: number;
|
|
101
116
|
height: number;
|
|
102
117
|
backgroundImage?: AnnotationBackgroundImage;
|
|
103
118
|
backgroundFit?: BackgroundFit;
|
|
119
|
+
backgroundImages?: AnnotationBackgroundLayer[];
|
|
104
120
|
}
|
|
105
121
|
export type TileScalePlatform = 'web' | 'mobile';
|
|
106
122
|
export interface AnnotationCanvasState {
|
|
@@ -155,6 +171,17 @@ export type AnnotationPatchOp = {
|
|
|
155
171
|
} | {
|
|
156
172
|
op: 'removeMeasurement';
|
|
157
173
|
id: AnnotationElementId;
|
|
174
|
+
} | {
|
|
175
|
+
op: 'addBackgroundImage';
|
|
176
|
+
image: AnnotationBackgroundLayer;
|
|
177
|
+
index?: number;
|
|
178
|
+
} | {
|
|
179
|
+
op: 'updateBackgroundImage';
|
|
180
|
+
id: AnnotationElementId;
|
|
181
|
+
patch: Partial<Omit<AnnotationBackgroundLayer, 'id'>>;
|
|
182
|
+
} | {
|
|
183
|
+
op: 'removeBackgroundImage';
|
|
184
|
+
id: AnnotationElementId;
|
|
158
185
|
} | {
|
|
159
186
|
op: 'setViewport';
|
|
160
187
|
patch: Partial<AnnotationViewport>;
|
package/dist/types/annotation.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { backgroundLayersOf } from '../annotation/canvas/backgroundLayers.js';
|
|
1
2
|
export const DEFAULT_LAYER_ID = 'default';
|
|
2
3
|
export const createDefaultLayer = () => ({
|
|
3
4
|
id: DEFAULT_LAYER_ID,
|
|
@@ -20,11 +21,40 @@ export const createEmptyCanvasState = (viewport) => ({
|
|
|
20
21
|
...(viewport?.backgroundFit !== undefined
|
|
21
22
|
? { backgroundFit: viewport.backgroundFit }
|
|
22
23
|
: {}),
|
|
24
|
+
...(viewport?.backgroundImages !== undefined
|
|
25
|
+
? { backgroundImages: viewport.backgroundImages }
|
|
26
|
+
: {}),
|
|
23
27
|
},
|
|
24
28
|
strokes: [],
|
|
25
29
|
shapes: [],
|
|
26
30
|
placedMeasurements: [],
|
|
27
31
|
});
|
|
32
|
+
// Layer 0 projected into the legacy single-slot shape. The transform is
|
|
33
|
+
// dropped — old clients draw the legacy field fit-centered, an accepted
|
|
34
|
+
// degradation. `format` is included only when defined so the mirror survives
|
|
35
|
+
// the write path's JSON round-trip without changing shape.
|
|
36
|
+
const legacyBackgroundOf = (layer) => ({
|
|
37
|
+
storagePath: layer.storagePath,
|
|
38
|
+
downloadUrl: layer.downloadUrl,
|
|
39
|
+
widthPx: layer.widthPx,
|
|
40
|
+
heightPx: layer.heightPx,
|
|
41
|
+
...(layer.format ? { format: layer.format } : {}),
|
|
42
|
+
});
|
|
43
|
+
// Every background mutation lands here: it writes the (already-normalized)
|
|
44
|
+
// layer array and mirrors layer 0 into the legacy slot, so old clients —
|
|
45
|
+
// which read only `backgroundImage` and rewrite the whole canvas on save —
|
|
46
|
+
// keep rendering the first image instead of persisting its loss. An empty
|
|
47
|
+
// stack sets BOTH fields to explicit `undefined`: the write path's JSON
|
|
48
|
+
// round-trip strips those keys (Firestore rejects undefined values).
|
|
49
|
+
// `backgroundFit` is left alone — it belongs to the legacy render path.
|
|
50
|
+
const withBackgroundLayers = (state, layers) => ({
|
|
51
|
+
...state,
|
|
52
|
+
viewport: {
|
|
53
|
+
...state.viewport,
|
|
54
|
+
backgroundImages: layers.length > 0 ? layers : undefined,
|
|
55
|
+
backgroundImage: layers.length > 0 ? legacyBackgroundOf(layers[0]) : undefined,
|
|
56
|
+
},
|
|
57
|
+
});
|
|
28
58
|
// Apply an in-memory patch to a canvas state. Pure — returns a new object.
|
|
29
59
|
// Used by the canvas reducer and by InMemoryAnnotationProvider; consumers
|
|
30
60
|
// can also call this when they receive a patch from the canvas to compute
|
|
@@ -71,6 +101,22 @@ const applyOp = (state, op) => {
|
|
|
71
101
|
...state,
|
|
72
102
|
placedMeasurements: state.placedMeasurements.filter((m) => m.id !== op.id),
|
|
73
103
|
};
|
|
104
|
+
case 'addBackgroundImage': {
|
|
105
|
+
const layers = backgroundLayersOf(state.viewport);
|
|
106
|
+
// Clamp so a stale index (e.g. an undo replayed after a concurrent
|
|
107
|
+
// removal) can never create a sparse array — a hole becomes `null`
|
|
108
|
+
// through the write path's JSON round-trip and corrupts the doc.
|
|
109
|
+
const index = Math.max(0, Math.min(op.index ?? layers.length, layers.length));
|
|
110
|
+
return withBackgroundLayers(state, [
|
|
111
|
+
...layers.slice(0, index),
|
|
112
|
+
op.image,
|
|
113
|
+
...layers.slice(index),
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
case 'updateBackgroundImage':
|
|
117
|
+
return withBackgroundLayers(state, backgroundLayersOf(state.viewport).map((l) => l.id === op.id ? { ...l, ...op.patch } : l));
|
|
118
|
+
case 'removeBackgroundImage':
|
|
119
|
+
return withBackgroundLayers(state, backgroundLayersOf(state.viewport).filter((l) => l.id !== op.id));
|
|
74
120
|
case 'setViewport':
|
|
75
121
|
return { ...state, viewport: { ...state.viewport, ...op.patch } };
|
|
76
122
|
case 'setTileScaleFactor':
|
|
@@ -148,6 +194,28 @@ const invertOp = (before, op) => {
|
|
|
148
194
|
}
|
|
149
195
|
return { op: 'updateMeasurement', id: op.id, patch: inversePatch };
|
|
150
196
|
}
|
|
197
|
+
case 'addBackgroundImage':
|
|
198
|
+
return { op: 'removeBackgroundImage', id: op.image.id };
|
|
199
|
+
case 'removeBackgroundImage': {
|
|
200
|
+
// Invert against the NORMALIZED stack: the before-state may hold only
|
|
201
|
+
// the legacy single field (the op being inverted is what materialized
|
|
202
|
+
// the array), and undo must still restore that layer — at its index.
|
|
203
|
+
const layers = backgroundLayersOf(before.viewport);
|
|
204
|
+
const index = layers.findIndex((l) => l.id === op.id);
|
|
205
|
+
return index >= 0
|
|
206
|
+
? { op: 'addBackgroundImage', image: layers[index], index }
|
|
207
|
+
: null;
|
|
208
|
+
}
|
|
209
|
+
case 'updateBackgroundImage': {
|
|
210
|
+
const prev = backgroundLayersOf(before.viewport).find((l) => l.id === op.id);
|
|
211
|
+
if (!prev)
|
|
212
|
+
return null;
|
|
213
|
+
const inversePatch = {};
|
|
214
|
+
for (const k of Object.keys(op.patch)) {
|
|
215
|
+
inversePatch[k] = prev[k];
|
|
216
|
+
}
|
|
217
|
+
return { op: 'updateBackgroundImage', id: op.id, patch: inversePatch };
|
|
218
|
+
}
|
|
151
219
|
case 'setViewport': {
|
|
152
220
|
const inversePatch = {};
|
|
153
221
|
for (const k of Object.keys(op.patch)) {
|