@fieldnotes/core 0.4.1 → 0.6.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/index.cjs +375 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +95 -4
- package/dist/index.d.ts +95 -4
- package/dist/index.js +370 -53
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,7 @@ __export(index_exports, {
|
|
|
26
26
|
Background: () => Background,
|
|
27
27
|
BatchCommand: () => BatchCommand,
|
|
28
28
|
Camera: () => Camera,
|
|
29
|
+
CreateLayerCommand: () => CreateLayerCommand,
|
|
29
30
|
ElementRenderer: () => ElementRenderer,
|
|
30
31
|
ElementStore: () => ElementStore,
|
|
31
32
|
EraserTool: () => EraserTool,
|
|
@@ -35,15 +36,18 @@ __export(index_exports, {
|
|
|
35
36
|
HistoryStack: () => HistoryStack,
|
|
36
37
|
ImageTool: () => ImageTool,
|
|
37
38
|
InputHandler: () => InputHandler,
|
|
39
|
+
LayerManager: () => LayerManager,
|
|
38
40
|
NoteEditor: () => NoteEditor,
|
|
39
41
|
NoteTool: () => NoteTool,
|
|
40
42
|
PencilTool: () => PencilTool,
|
|
41
43
|
RemoveElementCommand: () => RemoveElementCommand,
|
|
44
|
+
RemoveLayerCommand: () => RemoveLayerCommand,
|
|
42
45
|
SelectTool: () => SelectTool,
|
|
43
46
|
ShapeTool: () => ShapeTool,
|
|
44
47
|
TextTool: () => TextTool,
|
|
45
48
|
ToolManager: () => ToolManager,
|
|
46
49
|
UpdateElementCommand: () => UpdateElementCommand,
|
|
50
|
+
UpdateLayerCommand: () => UpdateLayerCommand,
|
|
47
51
|
VERSION: () => VERSION,
|
|
48
52
|
Viewport: () => Viewport,
|
|
49
53
|
clearStaleBindings: () => clearStaleBindings,
|
|
@@ -69,6 +73,7 @@ __export(index_exports, {
|
|
|
69
73
|
isBindable: () => isBindable,
|
|
70
74
|
isNearBezier: () => isNearBezier,
|
|
71
75
|
parseState: () => parseState,
|
|
76
|
+
snapPoint: () => snapPoint,
|
|
72
77
|
unbindArrow: () => unbindArrow,
|
|
73
78
|
updateBoundArrow: () => updateBoundArrow
|
|
74
79
|
});
|
|
@@ -99,15 +104,16 @@ var EventBus = class {
|
|
|
99
104
|
};
|
|
100
105
|
|
|
101
106
|
// src/core/state-serializer.ts
|
|
102
|
-
var CURRENT_VERSION =
|
|
103
|
-
function exportState(elements, camera) {
|
|
107
|
+
var CURRENT_VERSION = 2;
|
|
108
|
+
function exportState(elements, camera, layers = []) {
|
|
104
109
|
return {
|
|
105
110
|
version: CURRENT_VERSION,
|
|
106
111
|
camera: {
|
|
107
112
|
position: { ...camera.position },
|
|
108
113
|
zoom: camera.zoom
|
|
109
114
|
},
|
|
110
|
-
elements: elements.map((el) => structuredClone(el))
|
|
115
|
+
elements: elements.map((el) => structuredClone(el)),
|
|
116
|
+
layers: layers.map((l) => ({ ...l }))
|
|
111
117
|
};
|
|
112
118
|
}
|
|
113
119
|
function parseState(json) {
|
|
@@ -145,6 +151,19 @@ function validateState(data) {
|
|
|
145
151
|
migrateElement(el);
|
|
146
152
|
}
|
|
147
153
|
cleanBindings(obj["elements"]);
|
|
154
|
+
const layers = obj["layers"];
|
|
155
|
+
if (!Array.isArray(layers) || layers.length === 0) {
|
|
156
|
+
obj["layers"] = [
|
|
157
|
+
{
|
|
158
|
+
id: "default-layer",
|
|
159
|
+
name: "Layer 1",
|
|
160
|
+
visible: true,
|
|
161
|
+
locked: false,
|
|
162
|
+
order: 0,
|
|
163
|
+
opacity: 1
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
}
|
|
148
167
|
}
|
|
149
168
|
var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape"]);
|
|
150
169
|
function validateElement(el) {
|
|
@@ -177,6 +196,9 @@ function cleanBindings(elements) {
|
|
|
177
196
|
}
|
|
178
197
|
}
|
|
179
198
|
function migrateElement(obj) {
|
|
199
|
+
if (typeof obj["layerId"] !== "string") {
|
|
200
|
+
obj["layerId"] = "default-layer";
|
|
201
|
+
}
|
|
180
202
|
if (obj["type"] === "arrow" && typeof obj["bend"] !== "number") {
|
|
181
203
|
obj["bend"] = 0;
|
|
182
204
|
}
|
|
@@ -195,6 +217,14 @@ function migrateElement(obj) {
|
|
|
195
217
|
}
|
|
196
218
|
}
|
|
197
219
|
|
|
220
|
+
// src/core/snap.ts
|
|
221
|
+
function snapPoint(point, gridSize) {
|
|
222
|
+
return {
|
|
223
|
+
x: Math.round(point.x / gridSize) * gridSize || 0,
|
|
224
|
+
y: Math.round(point.y / gridSize) * gridSize || 0
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
198
228
|
// src/core/auto-save.ts
|
|
199
229
|
var DEFAULT_KEY = "fieldnotes-autosave";
|
|
200
230
|
var DEFAULT_DEBOUNCE_MS = 1e3;
|
|
@@ -204,9 +234,11 @@ var AutoSave = class {
|
|
|
204
234
|
this.camera = camera;
|
|
205
235
|
this.key = options.key ?? DEFAULT_KEY;
|
|
206
236
|
this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
237
|
+
this.layerManager = options.layerManager;
|
|
207
238
|
}
|
|
208
239
|
key;
|
|
209
240
|
debounceMs;
|
|
241
|
+
layerManager;
|
|
210
242
|
timerId = null;
|
|
211
243
|
unsubscribers = [];
|
|
212
244
|
start() {
|
|
@@ -217,6 +249,9 @@ var AutoSave = class {
|
|
|
217
249
|
this.store.on("update", schedule),
|
|
218
250
|
this.camera.onChange(schedule)
|
|
219
251
|
];
|
|
252
|
+
if (this.layerManager) {
|
|
253
|
+
this.unsubscribers.push(this.layerManager.on("change", schedule));
|
|
254
|
+
}
|
|
220
255
|
}
|
|
221
256
|
stop() {
|
|
222
257
|
this.cancelPending();
|
|
@@ -249,7 +284,8 @@ var AutoSave = class {
|
|
|
249
284
|
}
|
|
250
285
|
save() {
|
|
251
286
|
if (typeof localStorage === "undefined") return;
|
|
252
|
-
const
|
|
287
|
+
const layers = this.layerManager?.snapshot() ?? [];
|
|
288
|
+
const state = exportState(this.store.snapshot(), this.camera, layers);
|
|
253
289
|
localStorage.setItem(this.key, JSON.stringify(state));
|
|
254
290
|
}
|
|
255
291
|
};
|
|
@@ -626,11 +662,20 @@ var InputHandler = class {
|
|
|
626
662
|
var ElementStore = class {
|
|
627
663
|
elements = /* @__PURE__ */ new Map();
|
|
628
664
|
bus = new EventBus();
|
|
665
|
+
layerOrderMap = /* @__PURE__ */ new Map();
|
|
629
666
|
get count() {
|
|
630
667
|
return this.elements.size;
|
|
631
668
|
}
|
|
669
|
+
setLayerOrder(order) {
|
|
670
|
+
this.layerOrderMap = new Map(order);
|
|
671
|
+
}
|
|
632
672
|
getAll() {
|
|
633
|
-
return [...this.elements.values()].sort((a, b) =>
|
|
673
|
+
return [...this.elements.values()].sort((a, b) => {
|
|
674
|
+
const layerA = this.layerOrderMap.get(a.layerId) ?? 0;
|
|
675
|
+
const layerB = this.layerOrderMap.get(b.layerId) ?? 0;
|
|
676
|
+
if (layerA !== layerB) return layerA - layerB;
|
|
677
|
+
return a.zIndex - b.zIndex;
|
|
678
|
+
});
|
|
634
679
|
}
|
|
635
680
|
getById(id) {
|
|
636
681
|
return this.elements.get(id);
|
|
@@ -814,12 +859,13 @@ function getEdgeIntersection(bounds, outsidePoint) {
|
|
|
814
859
|
y: cy + dy * scale
|
|
815
860
|
};
|
|
816
861
|
}
|
|
817
|
-
function findBindTarget(point, store, threshold, excludeId) {
|
|
862
|
+
function findBindTarget(point, store, threshold, excludeId, filter) {
|
|
818
863
|
let closest = null;
|
|
819
864
|
let closestDist = Infinity;
|
|
820
865
|
for (const el of store.getAll()) {
|
|
821
866
|
if (!isBindable(el)) continue;
|
|
822
867
|
if (excludeId && el.id === excludeId) continue;
|
|
868
|
+
if (filter && !filter(el)) continue;
|
|
823
869
|
const bounds = getElementBounds(el);
|
|
824
870
|
if (!bounds) continue;
|
|
825
871
|
const dist = distToBounds(point, bounds);
|
|
@@ -977,14 +1023,19 @@ function smoothToSegments(points) {
|
|
|
977
1023
|
}
|
|
978
1024
|
|
|
979
1025
|
// src/elements/element-renderer.ts
|
|
980
|
-
var DOM_ELEMENT_TYPES = /* @__PURE__ */ new Set(["note", "
|
|
1026
|
+
var DOM_ELEMENT_TYPES = /* @__PURE__ */ new Set(["note", "html", "text"]);
|
|
981
1027
|
var ARROWHEAD_LENGTH = 12;
|
|
982
1028
|
var ARROWHEAD_ANGLE = Math.PI / 6;
|
|
983
1029
|
var ElementRenderer = class {
|
|
984
1030
|
store = null;
|
|
1031
|
+
imageCache = /* @__PURE__ */ new Map();
|
|
1032
|
+
onImageLoad = null;
|
|
985
1033
|
setStore(store) {
|
|
986
1034
|
this.store = store;
|
|
987
1035
|
}
|
|
1036
|
+
setOnImageLoad(callback) {
|
|
1037
|
+
this.onImageLoad = callback;
|
|
1038
|
+
}
|
|
988
1039
|
isDomElement(element) {
|
|
989
1040
|
return DOM_ELEMENT_TYPES.has(element.type);
|
|
990
1041
|
}
|
|
@@ -999,6 +1050,9 @@ var ElementRenderer = class {
|
|
|
999
1050
|
case "shape":
|
|
1000
1051
|
this.renderShape(ctx, element);
|
|
1001
1052
|
break;
|
|
1053
|
+
case "image":
|
|
1054
|
+
this.renderImage(ctx, element);
|
|
1055
|
+
break;
|
|
1002
1056
|
}
|
|
1003
1057
|
}
|
|
1004
1058
|
renderStroke(ctx, stroke) {
|
|
@@ -1134,6 +1188,20 @@ var ElementRenderer = class {
|
|
|
1134
1188
|
}
|
|
1135
1189
|
}
|
|
1136
1190
|
}
|
|
1191
|
+
renderImage(ctx, image) {
|
|
1192
|
+
const img = this.getImage(image.src);
|
|
1193
|
+
if (!img) return;
|
|
1194
|
+
ctx.drawImage(img, image.position.x, image.position.y, image.size.w, image.size.h);
|
|
1195
|
+
}
|
|
1196
|
+
getImage(src) {
|
|
1197
|
+
const cached = this.imageCache.get(src);
|
|
1198
|
+
if (cached) return cached.complete ? cached : null;
|
|
1199
|
+
const img = new Image();
|
|
1200
|
+
img.src = src;
|
|
1201
|
+
this.imageCache.set(src, img);
|
|
1202
|
+
img.onload = () => this.onImageLoad?.();
|
|
1203
|
+
return null;
|
|
1204
|
+
}
|
|
1137
1205
|
};
|
|
1138
1206
|
|
|
1139
1207
|
// src/elements/note-editor.ts
|
|
@@ -1485,6 +1553,7 @@ function createStroke(input) {
|
|
|
1485
1553
|
position: input.position ?? { x: 0, y: 0 },
|
|
1486
1554
|
zIndex: input.zIndex ?? 0,
|
|
1487
1555
|
locked: input.locked ?? false,
|
|
1556
|
+
layerId: input.layerId ?? "",
|
|
1488
1557
|
points: input.points,
|
|
1489
1558
|
color: input.color ?? "#000000",
|
|
1490
1559
|
width: input.width ?? 2,
|
|
@@ -1498,6 +1567,7 @@ function createNote(input) {
|
|
|
1498
1567
|
position: input.position,
|
|
1499
1568
|
zIndex: input.zIndex ?? 0,
|
|
1500
1569
|
locked: input.locked ?? false,
|
|
1570
|
+
layerId: input.layerId ?? "",
|
|
1501
1571
|
size: input.size ?? { w: 200, h: 100 },
|
|
1502
1572
|
text: input.text ?? "",
|
|
1503
1573
|
backgroundColor: input.backgroundColor ?? "#ffeb3b",
|
|
@@ -1511,6 +1581,7 @@ function createArrow(input) {
|
|
|
1511
1581
|
position: input.position ?? { x: 0, y: 0 },
|
|
1512
1582
|
zIndex: input.zIndex ?? 0,
|
|
1513
1583
|
locked: input.locked ?? false,
|
|
1584
|
+
layerId: input.layerId ?? "",
|
|
1514
1585
|
from: input.from,
|
|
1515
1586
|
to: input.to,
|
|
1516
1587
|
bend: input.bend ?? 0,
|
|
@@ -1528,6 +1599,7 @@ function createImage(input) {
|
|
|
1528
1599
|
position: input.position,
|
|
1529
1600
|
zIndex: input.zIndex ?? 0,
|
|
1530
1601
|
locked: input.locked ?? false,
|
|
1602
|
+
layerId: input.layerId ?? "",
|
|
1531
1603
|
size: input.size,
|
|
1532
1604
|
src: input.src
|
|
1533
1605
|
};
|
|
@@ -1539,6 +1611,7 @@ function createHtmlElement(input) {
|
|
|
1539
1611
|
position: input.position,
|
|
1540
1612
|
zIndex: input.zIndex ?? 0,
|
|
1541
1613
|
locked: input.locked ?? false,
|
|
1614
|
+
layerId: input.layerId ?? "",
|
|
1542
1615
|
size: input.size
|
|
1543
1616
|
};
|
|
1544
1617
|
}
|
|
@@ -1549,6 +1622,7 @@ function createShape(input) {
|
|
|
1549
1622
|
position: input.position,
|
|
1550
1623
|
zIndex: input.zIndex ?? 0,
|
|
1551
1624
|
locked: input.locked ?? false,
|
|
1625
|
+
layerId: input.layerId ?? "",
|
|
1552
1626
|
shape: input.shape ?? "rectangle",
|
|
1553
1627
|
size: input.size,
|
|
1554
1628
|
strokeColor: input.strokeColor ?? "#000000",
|
|
@@ -1563,6 +1637,7 @@ function createText(input) {
|
|
|
1563
1637
|
position: input.position,
|
|
1564
1638
|
zIndex: input.zIndex ?? 0,
|
|
1565
1639
|
locked: input.locked ?? false,
|
|
1640
|
+
layerId: input.layerId ?? "",
|
|
1566
1641
|
size: input.size ?? { w: 200, h: 28 },
|
|
1567
1642
|
text: input.text ?? "",
|
|
1568
1643
|
fontSize: input.fontSize ?? 16,
|
|
@@ -1571,16 +1646,168 @@ function createText(input) {
|
|
|
1571
1646
|
};
|
|
1572
1647
|
}
|
|
1573
1648
|
|
|
1649
|
+
// src/layers/layer-manager.ts
|
|
1650
|
+
var LayerManager = class {
|
|
1651
|
+
constructor(store) {
|
|
1652
|
+
this.store = store;
|
|
1653
|
+
const defaultLayer = {
|
|
1654
|
+
id: createId("layer"),
|
|
1655
|
+
name: "Layer 1",
|
|
1656
|
+
visible: true,
|
|
1657
|
+
locked: false,
|
|
1658
|
+
order: 0,
|
|
1659
|
+
opacity: 1
|
|
1660
|
+
};
|
|
1661
|
+
this.layers.set(defaultLayer.id, defaultLayer);
|
|
1662
|
+
this._activeLayerId = defaultLayer.id;
|
|
1663
|
+
this.syncLayerOrder();
|
|
1664
|
+
}
|
|
1665
|
+
layers = /* @__PURE__ */ new Map();
|
|
1666
|
+
_activeLayerId;
|
|
1667
|
+
bus = new EventBus();
|
|
1668
|
+
get activeLayer() {
|
|
1669
|
+
const layer = this.layers.get(this._activeLayerId);
|
|
1670
|
+
if (!layer) throw new Error("Active layer not found");
|
|
1671
|
+
return { ...layer };
|
|
1672
|
+
}
|
|
1673
|
+
get activeLayerId() {
|
|
1674
|
+
return this._activeLayerId;
|
|
1675
|
+
}
|
|
1676
|
+
getLayers() {
|
|
1677
|
+
return [...this.layers.values()].sort((a, b) => a.order - b.order).map((l) => ({ ...l }));
|
|
1678
|
+
}
|
|
1679
|
+
getLayer(id) {
|
|
1680
|
+
const layer = this.layers.get(id);
|
|
1681
|
+
return layer ? { ...layer } : void 0;
|
|
1682
|
+
}
|
|
1683
|
+
isLayerVisible(id) {
|
|
1684
|
+
return this.layers.get(id)?.visible ?? true;
|
|
1685
|
+
}
|
|
1686
|
+
isLayerLocked(id) {
|
|
1687
|
+
return this.layers.get(id)?.locked ?? false;
|
|
1688
|
+
}
|
|
1689
|
+
createLayer(name) {
|
|
1690
|
+
const maxOrder = Math.max(...[...this.layers.values()].map((l) => l.order), -1);
|
|
1691
|
+
const autoName = name ?? `Layer ${this.layers.size + 1}`;
|
|
1692
|
+
const layer = {
|
|
1693
|
+
id: createId("layer"),
|
|
1694
|
+
name: autoName,
|
|
1695
|
+
visible: true,
|
|
1696
|
+
locked: false,
|
|
1697
|
+
order: maxOrder + 1,
|
|
1698
|
+
opacity: 1
|
|
1699
|
+
};
|
|
1700
|
+
this.addLayerDirect(layer);
|
|
1701
|
+
return { ...layer };
|
|
1702
|
+
}
|
|
1703
|
+
removeLayer(id) {
|
|
1704
|
+
if (this.layers.size <= 1) {
|
|
1705
|
+
throw new Error("Cannot remove the last layer");
|
|
1706
|
+
}
|
|
1707
|
+
if (this._activeLayerId === id) {
|
|
1708
|
+
const remaining = [...this.layers.values()].filter((l) => l.id !== id).sort((a, b) => b.order - a.order);
|
|
1709
|
+
const fallback = remaining[0];
|
|
1710
|
+
if (fallback) this._activeLayerId = fallback.id;
|
|
1711
|
+
}
|
|
1712
|
+
const elements = this.store.getAll().filter((el) => el.layerId === id);
|
|
1713
|
+
for (const el of elements) {
|
|
1714
|
+
this.store.update(el.id, { layerId: this._activeLayerId });
|
|
1715
|
+
}
|
|
1716
|
+
this.removeLayerDirect(id);
|
|
1717
|
+
}
|
|
1718
|
+
renameLayer(id, name) {
|
|
1719
|
+
this.updateLayerDirect(id, { name });
|
|
1720
|
+
}
|
|
1721
|
+
reorderLayer(id, newOrder) {
|
|
1722
|
+
if (!this.layers.has(id)) return;
|
|
1723
|
+
this.updateLayerDirect(id, { order: newOrder });
|
|
1724
|
+
}
|
|
1725
|
+
setLayerVisible(id, visible) {
|
|
1726
|
+
if (!visible && id === this._activeLayerId) {
|
|
1727
|
+
const fallback = this.findFallbackLayer(id);
|
|
1728
|
+
if (!fallback) return false;
|
|
1729
|
+
this._activeLayerId = fallback.id;
|
|
1730
|
+
}
|
|
1731
|
+
this.updateLayerDirect(id, { visible });
|
|
1732
|
+
return true;
|
|
1733
|
+
}
|
|
1734
|
+
setLayerLocked(id, locked) {
|
|
1735
|
+
if (locked && id === this._activeLayerId) {
|
|
1736
|
+
const fallback = this.findFallbackLayer(id);
|
|
1737
|
+
if (!fallback) return false;
|
|
1738
|
+
this._activeLayerId = fallback.id;
|
|
1739
|
+
}
|
|
1740
|
+
this.updateLayerDirect(id, { locked });
|
|
1741
|
+
return true;
|
|
1742
|
+
}
|
|
1743
|
+
setActiveLayer(id) {
|
|
1744
|
+
if (!this.layers.has(id)) return;
|
|
1745
|
+
this._activeLayerId = id;
|
|
1746
|
+
this.bus.emit("change", null);
|
|
1747
|
+
}
|
|
1748
|
+
moveElementToLayer(elementId, layerId) {
|
|
1749
|
+
if (!this.layers.has(layerId)) return;
|
|
1750
|
+
this.store.update(elementId, { layerId });
|
|
1751
|
+
this.bus.emit("change", null);
|
|
1752
|
+
}
|
|
1753
|
+
snapshot() {
|
|
1754
|
+
return this.getLayers();
|
|
1755
|
+
}
|
|
1756
|
+
loadSnapshot(layers) {
|
|
1757
|
+
this.layers.clear();
|
|
1758
|
+
for (const layer of layers) {
|
|
1759
|
+
this.layers.set(layer.id, { ...layer });
|
|
1760
|
+
}
|
|
1761
|
+
const first = this.getLayers()[0];
|
|
1762
|
+
if (first) this._activeLayerId = first.id;
|
|
1763
|
+
this.syncLayerOrder();
|
|
1764
|
+
this.bus.emit("change", null);
|
|
1765
|
+
}
|
|
1766
|
+
on(event, callback) {
|
|
1767
|
+
return this.bus.on(event, callback);
|
|
1768
|
+
}
|
|
1769
|
+
addLayerDirect(layer) {
|
|
1770
|
+
this.layers.set(layer.id, { ...layer });
|
|
1771
|
+
this.syncLayerOrder();
|
|
1772
|
+
this.bus.emit("change", null);
|
|
1773
|
+
}
|
|
1774
|
+
removeLayerDirect(id) {
|
|
1775
|
+
this.layers.delete(id);
|
|
1776
|
+
this.syncLayerOrder();
|
|
1777
|
+
this.bus.emit("change", null);
|
|
1778
|
+
}
|
|
1779
|
+
updateLayerDirect(id, props) {
|
|
1780
|
+
const layer = this.layers.get(id);
|
|
1781
|
+
if (!layer) return;
|
|
1782
|
+
Object.assign(layer, props);
|
|
1783
|
+
if ("order" in props) this.syncLayerOrder();
|
|
1784
|
+
this.bus.emit("change", null);
|
|
1785
|
+
}
|
|
1786
|
+
syncLayerOrder() {
|
|
1787
|
+
const order = /* @__PURE__ */ new Map();
|
|
1788
|
+
for (const layer of this.layers.values()) {
|
|
1789
|
+
order.set(layer.id, layer.order);
|
|
1790
|
+
}
|
|
1791
|
+
this.store.setLayerOrder(order);
|
|
1792
|
+
}
|
|
1793
|
+
findFallbackLayer(excludeId) {
|
|
1794
|
+
return [...this.layers.values()].filter((l) => l.id !== excludeId && l.visible && !l.locked).sort((a, b) => b.order - a.order)[0];
|
|
1795
|
+
}
|
|
1796
|
+
};
|
|
1797
|
+
|
|
1574
1798
|
// src/canvas/viewport.ts
|
|
1575
1799
|
var Viewport = class {
|
|
1576
1800
|
constructor(container, options = {}) {
|
|
1577
1801
|
this.container = container;
|
|
1578
1802
|
this.camera = new Camera(options.camera);
|
|
1579
1803
|
this.background = new Background(options.background);
|
|
1804
|
+
this._gridSize = options.background?.spacing ?? 24;
|
|
1580
1805
|
this.store = new ElementStore();
|
|
1806
|
+
this.layerManager = new LayerManager(this.store);
|
|
1581
1807
|
this.toolManager = new ToolManager();
|
|
1582
1808
|
this.renderer = new ElementRenderer();
|
|
1583
1809
|
this.renderer.setStore(this.store);
|
|
1810
|
+
this.renderer.setOnImageLoad(() => this.requestRender());
|
|
1584
1811
|
this.noteEditor = new NoteEditor();
|
|
1585
1812
|
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
1586
1813
|
this.history = new HistoryStack();
|
|
@@ -1599,7 +1826,12 @@ var Viewport = class {
|
|
|
1599
1826
|
editElement: (id) => this.startEditingElement(id),
|
|
1600
1827
|
setCursor: (cursor) => {
|
|
1601
1828
|
this.wrapper.style.cursor = cursor;
|
|
1602
|
-
}
|
|
1829
|
+
},
|
|
1830
|
+
snapToGrid: false,
|
|
1831
|
+
gridSize: this._gridSize,
|
|
1832
|
+
activeLayerId: this.layerManager.activeLayerId,
|
|
1833
|
+
isLayerVisible: (id) => this.layerManager.isLayerVisible(id),
|
|
1834
|
+
isLayerLocked: (id) => this.layerManager.isLayerLocked(id)
|
|
1603
1835
|
};
|
|
1604
1836
|
this.inputHandler = new InputHandler(this.wrapper, this.camera, {
|
|
1605
1837
|
toolManager: this.toolManager,
|
|
@@ -1620,6 +1852,10 @@ var Viewport = class {
|
|
|
1620
1852
|
this.store.on("update", () => this.requestRender()),
|
|
1621
1853
|
this.store.on("clear", () => this.clearDomNodes())
|
|
1622
1854
|
];
|
|
1855
|
+
this.layerManager.on("change", () => {
|
|
1856
|
+
this.toolContext.activeLayerId = this.layerManager.activeLayerId;
|
|
1857
|
+
this.requestRender();
|
|
1858
|
+
});
|
|
1623
1859
|
this.wrapper.addEventListener("dblclick", this.onDblClick);
|
|
1624
1860
|
this.wrapper.addEventListener("dragover", this.onDragOver);
|
|
1625
1861
|
this.wrapper.addEventListener("drop", this.onDrop);
|
|
@@ -1629,6 +1865,7 @@ var Viewport = class {
|
|
|
1629
1865
|
}
|
|
1630
1866
|
camera;
|
|
1631
1867
|
store;
|
|
1868
|
+
layerManager;
|
|
1632
1869
|
toolManager;
|
|
1633
1870
|
history;
|
|
1634
1871
|
domLayer;
|
|
@@ -1644,6 +1881,8 @@ var Viewport = class {
|
|
|
1644
1881
|
toolContext;
|
|
1645
1882
|
resizeObserver = null;
|
|
1646
1883
|
animFrameId = 0;
|
|
1884
|
+
_snapToGrid = false;
|
|
1885
|
+
_gridSize;
|
|
1647
1886
|
needsRender = true;
|
|
1648
1887
|
domNodes = /* @__PURE__ */ new Map();
|
|
1649
1888
|
htmlContent = /* @__PURE__ */ new Map();
|
|
@@ -1651,11 +1890,18 @@ var Viewport = class {
|
|
|
1651
1890
|
get ctx() {
|
|
1652
1891
|
return this.canvasEl.getContext("2d");
|
|
1653
1892
|
}
|
|
1893
|
+
get snapToGrid() {
|
|
1894
|
+
return this._snapToGrid;
|
|
1895
|
+
}
|
|
1896
|
+
setSnapToGrid(enabled) {
|
|
1897
|
+
this._snapToGrid = enabled;
|
|
1898
|
+
this.toolContext.snapToGrid = enabled;
|
|
1899
|
+
}
|
|
1654
1900
|
requestRender() {
|
|
1655
1901
|
this.needsRender = true;
|
|
1656
1902
|
}
|
|
1657
1903
|
exportState() {
|
|
1658
|
-
return exportState(this.store.snapshot(), this.camera);
|
|
1904
|
+
return exportState(this.store.snapshot(), this.camera, this.layerManager.snapshot());
|
|
1659
1905
|
}
|
|
1660
1906
|
exportJSON() {
|
|
1661
1907
|
return JSON.stringify(this.exportState());
|
|
@@ -1665,6 +1911,9 @@ var Viewport = class {
|
|
|
1665
1911
|
this.noteEditor.destroy(this.store);
|
|
1666
1912
|
this.clearDomNodes();
|
|
1667
1913
|
this.store.loadSnapshot(state.elements);
|
|
1914
|
+
if (state.layers && state.layers.length > 0) {
|
|
1915
|
+
this.layerManager.loadSnapshot(state.layers);
|
|
1916
|
+
}
|
|
1668
1917
|
this.history.clear();
|
|
1669
1918
|
this.historyRecorder.resume();
|
|
1670
1919
|
this.camera.moveTo(state.camera.position.x, state.camera.position.y);
|
|
@@ -1688,7 +1937,7 @@ var Viewport = class {
|
|
|
1688
1937
|
return result;
|
|
1689
1938
|
}
|
|
1690
1939
|
addImage(src, position, size = { w: 300, h: 200 }) {
|
|
1691
|
-
const image = createImage({ position, size, src });
|
|
1940
|
+
const image = createImage({ position, size, src, layerId: this.layerManager.activeLayerId });
|
|
1692
1941
|
this.historyRecorder.begin();
|
|
1693
1942
|
this.store.add(image);
|
|
1694
1943
|
this.historyRecorder.commit();
|
|
@@ -1696,7 +1945,7 @@ var Viewport = class {
|
|
|
1696
1945
|
return image.id;
|
|
1697
1946
|
}
|
|
1698
1947
|
addHtmlElement(dom, position, size = { w: 200, h: 150 }) {
|
|
1699
|
-
const el = createHtmlElement({ position, size });
|
|
1948
|
+
const el = createHtmlElement({ position, size, layerId: this.layerManager.activeLayerId });
|
|
1700
1949
|
this.htmlContent.set(el.id, dom);
|
|
1701
1950
|
this.historyRecorder.begin();
|
|
1702
1951
|
this.store.add(el);
|
|
@@ -1739,9 +1988,17 @@ var Viewport = class {
|
|
|
1739
1988
|
ctx.save();
|
|
1740
1989
|
ctx.translate(this.camera.position.x, this.camera.position.y);
|
|
1741
1990
|
ctx.scale(this.camera.zoom, this.camera.zoom);
|
|
1742
|
-
|
|
1991
|
+
const allElements = this.store.getAll();
|
|
1992
|
+
let domZIndex = 0;
|
|
1993
|
+
for (const element of allElements) {
|
|
1994
|
+
if (!this.layerManager.isLayerVisible(element.layerId)) {
|
|
1995
|
+
if (this.renderer.isDomElement(element)) {
|
|
1996
|
+
this.hideDomNode(element.id);
|
|
1997
|
+
}
|
|
1998
|
+
continue;
|
|
1999
|
+
}
|
|
1743
2000
|
if (this.renderer.isDomElement(element)) {
|
|
1744
|
-
this.syncDomNode(element);
|
|
2001
|
+
this.syncDomNode(element, domZIndex++);
|
|
1745
2002
|
} else {
|
|
1746
2003
|
this.renderer.renderCanvasElement(ctx, element);
|
|
1747
2004
|
}
|
|
@@ -1873,7 +2130,7 @@ var Viewport = class {
|
|
|
1873
2130
|
reader.readAsDataURL(file);
|
|
1874
2131
|
}
|
|
1875
2132
|
};
|
|
1876
|
-
syncDomNode(element) {
|
|
2133
|
+
syncDomNode(element, zIndex = 0) {
|
|
1877
2134
|
let node = this.domNodes.get(element.id);
|
|
1878
2135
|
if (!node) {
|
|
1879
2136
|
node = document.createElement("div");
|
|
@@ -1887,10 +2144,12 @@ var Viewport = class {
|
|
|
1887
2144
|
}
|
|
1888
2145
|
const size = "size" in element ? element.size : null;
|
|
1889
2146
|
Object.assign(node.style, {
|
|
2147
|
+
display: "block",
|
|
1890
2148
|
left: `${element.position.x}px`,
|
|
1891
2149
|
top: `${element.position.y}px`,
|
|
1892
2150
|
width: size ? `${size.w}px` : "auto",
|
|
1893
|
-
height: size ? `${size.h}px` : "auto"
|
|
2151
|
+
height: size ? `${size.h}px` : "auto",
|
|
2152
|
+
zIndex: String(zIndex)
|
|
1894
2153
|
});
|
|
1895
2154
|
this.renderDomContent(node, element);
|
|
1896
2155
|
}
|
|
@@ -1925,26 +2184,6 @@ var Viewport = class {
|
|
|
1925
2184
|
node.style.color = element.textColor;
|
|
1926
2185
|
}
|
|
1927
2186
|
}
|
|
1928
|
-
if (element.type === "image") {
|
|
1929
|
-
if (!node.dataset["initialized"]) {
|
|
1930
|
-
node.dataset["initialized"] = "true";
|
|
1931
|
-
const img = document.createElement("img");
|
|
1932
|
-
img.src = element.src;
|
|
1933
|
-
Object.assign(img.style, {
|
|
1934
|
-
width: "100%",
|
|
1935
|
-
height: "100%",
|
|
1936
|
-
objectFit: "contain",
|
|
1937
|
-
pointerEvents: "none"
|
|
1938
|
-
});
|
|
1939
|
-
img.draggable = false;
|
|
1940
|
-
node.appendChild(img);
|
|
1941
|
-
} else {
|
|
1942
|
-
const img = node.querySelector("img");
|
|
1943
|
-
if (img && img.src !== element.src) {
|
|
1944
|
-
img.src = element.src;
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
}
|
|
1948
2187
|
if (element.type === "html" && !node.dataset["initialized"]) {
|
|
1949
2188
|
const content = this.htmlContent.get(element.id);
|
|
1950
2189
|
if (content) {
|
|
@@ -2027,6 +2266,10 @@ var Viewport = class {
|
|
|
2027
2266
|
}
|
|
2028
2267
|
}
|
|
2029
2268
|
}
|
|
2269
|
+
hideDomNode(id) {
|
|
2270
|
+
const node = this.domNodes.get(id);
|
|
2271
|
+
if (node) node.style.display = "none";
|
|
2272
|
+
}
|
|
2030
2273
|
removeDomNode(id) {
|
|
2031
2274
|
this.htmlContent.delete(id);
|
|
2032
2275
|
const node = this.domNodes.get(id);
|
|
@@ -2173,7 +2416,8 @@ var PencilTool = class {
|
|
|
2173
2416
|
const stroke = createStroke({
|
|
2174
2417
|
points: simplified,
|
|
2175
2418
|
color: this.color,
|
|
2176
|
-
width: this.width
|
|
2419
|
+
width: this.width,
|
|
2420
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2177
2421
|
});
|
|
2178
2422
|
ctx.store.add(stroke);
|
|
2179
2423
|
this.points = [];
|
|
@@ -2237,6 +2481,8 @@ var EraserTool = class {
|
|
|
2237
2481
|
const strokes = ctx.store.getElementsByType("stroke");
|
|
2238
2482
|
let erased = false;
|
|
2239
2483
|
for (const stroke of strokes) {
|
|
2484
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(stroke.layerId)) continue;
|
|
2485
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(stroke.layerId)) continue;
|
|
2240
2486
|
if (this.strokeIntersects(stroke, world)) {
|
|
2241
2487
|
ctx.store.remove(stroke.id);
|
|
2242
2488
|
erased = true;
|
|
@@ -2399,10 +2645,13 @@ var SelectTool = class {
|
|
|
2399
2645
|
this.mode = { type: "idle" };
|
|
2400
2646
|
ctx.setCursor?.("default");
|
|
2401
2647
|
}
|
|
2648
|
+
snap(point, ctx) {
|
|
2649
|
+
return ctx.snapToGrid && ctx.gridSize ? snapPoint(point, ctx.gridSize) : point;
|
|
2650
|
+
}
|
|
2402
2651
|
onPointerDown(state, ctx) {
|
|
2403
2652
|
this.ctx = ctx;
|
|
2404
2653
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
2405
|
-
this.lastWorld = world;
|
|
2654
|
+
this.lastWorld = this.snap(world, ctx);
|
|
2406
2655
|
this.currentWorld = world;
|
|
2407
2656
|
const arrowHit = hitTestArrowHandles(world, this._selectedIds, ctx);
|
|
2408
2657
|
if (arrowHit) {
|
|
@@ -2455,9 +2704,10 @@ var SelectTool = class {
|
|
|
2455
2704
|
}
|
|
2456
2705
|
if (this.mode.type === "dragging" && this._selectedIds.length > 0) {
|
|
2457
2706
|
ctx.setCursor?.("move");
|
|
2458
|
-
const
|
|
2459
|
-
const
|
|
2460
|
-
this.lastWorld
|
|
2707
|
+
const snapped = this.snap(world, ctx);
|
|
2708
|
+
const dx = snapped.x - this.lastWorld.x;
|
|
2709
|
+
const dy = snapped.y - this.lastWorld.y;
|
|
2710
|
+
this.lastWorld = snapped;
|
|
2461
2711
|
for (const id of this._selectedIds) {
|
|
2462
2712
|
const el = ctx.store.getById(id);
|
|
2463
2713
|
if (!el || el.locked) continue;
|
|
@@ -2718,6 +2968,8 @@ var SelectTool = class {
|
|
|
2718
2968
|
findElementsInRect(marquee, ctx) {
|
|
2719
2969
|
const ids = [];
|
|
2720
2970
|
for (const el of ctx.store.getAll()) {
|
|
2971
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
2972
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
2721
2973
|
const bounds = this.getElementBounds(el);
|
|
2722
2974
|
if (bounds && this.rectsOverlap(marquee, bounds)) {
|
|
2723
2975
|
ids.push(el.id);
|
|
@@ -2752,6 +3004,8 @@ var SelectTool = class {
|
|
|
2752
3004
|
hitTest(world, ctx) {
|
|
2753
3005
|
const elements = ctx.store.getAll().reverse();
|
|
2754
3006
|
for (const el of elements) {
|
|
3007
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
3008
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
2755
3009
|
if (this.isInsideBounds(world, el)) return el;
|
|
2756
3010
|
}
|
|
2757
3011
|
return null;
|
|
@@ -2796,17 +3050,26 @@ var ArrowTool = class {
|
|
|
2796
3050
|
if (options.color !== void 0) this.color = options.color;
|
|
2797
3051
|
if (options.width !== void 0) this.width = options.width;
|
|
2798
3052
|
}
|
|
3053
|
+
layerFilter(ctx) {
|
|
3054
|
+
if (!ctx.isLayerVisible && !ctx.isLayerLocked) return void 0;
|
|
3055
|
+
return (el) => {
|
|
3056
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) return false;
|
|
3057
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) return false;
|
|
3058
|
+
return true;
|
|
3059
|
+
};
|
|
3060
|
+
}
|
|
2799
3061
|
onPointerDown(state, ctx) {
|
|
2800
3062
|
this.drawing = true;
|
|
2801
3063
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
2802
3064
|
const threshold = BIND_THRESHOLD2 / ctx.camera.zoom;
|
|
2803
|
-
const
|
|
3065
|
+
const filter = this.layerFilter(ctx);
|
|
3066
|
+
const target = findBindTarget(world, ctx.store, threshold, void 0, filter);
|
|
2804
3067
|
if (target) {
|
|
2805
3068
|
this.start = getElementCenter(target);
|
|
2806
3069
|
this.fromBinding = { elementId: target.id };
|
|
2807
3070
|
this.fromTarget = target;
|
|
2808
3071
|
} else {
|
|
2809
|
-
this.start = world;
|
|
3072
|
+
this.start = ctx.snapToGrid && ctx.gridSize ? snapPoint(world, ctx.gridSize) : world;
|
|
2810
3073
|
this.fromBinding = void 0;
|
|
2811
3074
|
this.fromTarget = null;
|
|
2812
3075
|
}
|
|
@@ -2818,12 +3081,13 @@ var ArrowTool = class {
|
|
|
2818
3081
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
2819
3082
|
const threshold = BIND_THRESHOLD2 / ctx.camera.zoom;
|
|
2820
3083
|
const excludeId = this.fromBinding?.elementId;
|
|
2821
|
-
const
|
|
3084
|
+
const filter = this.layerFilter(ctx);
|
|
3085
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, filter);
|
|
2822
3086
|
if (target) {
|
|
2823
3087
|
this.end = getElementCenter(target);
|
|
2824
3088
|
this.toTarget = target;
|
|
2825
3089
|
} else {
|
|
2826
|
-
this.end = world;
|
|
3090
|
+
this.end = ctx.snapToGrid && ctx.gridSize ? snapPoint(world, ctx.gridSize) : world;
|
|
2827
3091
|
this.toTarget = null;
|
|
2828
3092
|
}
|
|
2829
3093
|
ctx.requestRender();
|
|
@@ -2839,7 +3103,8 @@ var ArrowTool = class {
|
|
|
2839
3103
|
color: this.color,
|
|
2840
3104
|
width: this.width,
|
|
2841
3105
|
fromBinding: this.fromBinding,
|
|
2842
|
-
toBinding: this.toTarget ? { elementId: this.toTarget.id } : void 0
|
|
3106
|
+
toBinding: this.toTarget ? { elementId: this.toTarget.id } : void 0,
|
|
3107
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2843
3108
|
});
|
|
2844
3109
|
ctx.store.add(arrow);
|
|
2845
3110
|
this.fromTarget = null;
|
|
@@ -2918,12 +3183,16 @@ var NoteTool = class {
|
|
|
2918
3183
|
onPointerMove(_state, _ctx) {
|
|
2919
3184
|
}
|
|
2920
3185
|
onPointerUp(state, ctx) {
|
|
2921
|
-
|
|
3186
|
+
let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3187
|
+
if (ctx.snapToGrid && ctx.gridSize) {
|
|
3188
|
+
world = snapPoint(world, ctx.gridSize);
|
|
3189
|
+
}
|
|
2922
3190
|
const note = createNote({
|
|
2923
3191
|
position: world,
|
|
2924
3192
|
size: { ...this.size },
|
|
2925
3193
|
backgroundColor: this.backgroundColor,
|
|
2926
|
-
textColor: this.textColor
|
|
3194
|
+
textColor: this.textColor,
|
|
3195
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2927
3196
|
});
|
|
2928
3197
|
ctx.store.add(note);
|
|
2929
3198
|
ctx.requestRender();
|
|
@@ -2959,12 +3228,16 @@ var TextTool = class {
|
|
|
2959
3228
|
onPointerMove(_state, _ctx) {
|
|
2960
3229
|
}
|
|
2961
3230
|
onPointerUp(state, ctx) {
|
|
2962
|
-
|
|
3231
|
+
let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3232
|
+
if (ctx.snapToGrid && ctx.gridSize) {
|
|
3233
|
+
world = snapPoint(world, ctx.gridSize);
|
|
3234
|
+
}
|
|
2963
3235
|
const textEl = createText({
|
|
2964
3236
|
position: world,
|
|
2965
3237
|
fontSize: this.fontSize,
|
|
2966
3238
|
color: this.color,
|
|
2967
|
-
textAlign: this.textAlign
|
|
3239
|
+
textAlign: this.textAlign,
|
|
3240
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2968
3241
|
});
|
|
2969
3242
|
ctx.store.add(textEl);
|
|
2970
3243
|
ctx.requestRender();
|
|
@@ -3041,12 +3314,12 @@ var ShapeTool = class {
|
|
|
3041
3314
|
}
|
|
3042
3315
|
onPointerDown(state, ctx) {
|
|
3043
3316
|
this.drawing = true;
|
|
3044
|
-
this.start = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3317
|
+
this.start = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);
|
|
3045
3318
|
this.end = { ...this.start };
|
|
3046
3319
|
}
|
|
3047
3320
|
onPointerMove(state, ctx) {
|
|
3048
3321
|
if (!this.drawing) return;
|
|
3049
|
-
this.end = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3322
|
+
this.end = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);
|
|
3050
3323
|
ctx.requestRender();
|
|
3051
3324
|
}
|
|
3052
3325
|
onPointerUp(_state, ctx) {
|
|
@@ -3060,7 +3333,8 @@ var ShapeTool = class {
|
|
|
3060
3333
|
shape: this.shape,
|
|
3061
3334
|
strokeColor: this.strokeColor,
|
|
3062
3335
|
strokeWidth: this.strokeWidth,
|
|
3063
|
-
fillColor: this.fillColor
|
|
3336
|
+
fillColor: this.fillColor,
|
|
3337
|
+
layerId: ctx.activeLayerId ?? ""
|
|
3064
3338
|
});
|
|
3065
3339
|
ctx.store.add(shape);
|
|
3066
3340
|
ctx.requestRender();
|
|
@@ -3110,6 +3384,9 @@ var ShapeTool = class {
|
|
|
3110
3384
|
}
|
|
3111
3385
|
return { position: { x, y }, size: { w, h } };
|
|
3112
3386
|
}
|
|
3387
|
+
snap(point, ctx) {
|
|
3388
|
+
return ctx.snapToGrid && ctx.gridSize ? snapPoint(point, ctx.gridSize) : point;
|
|
3389
|
+
}
|
|
3113
3390
|
onKeyDown = (e) => {
|
|
3114
3391
|
if (e.key === "Shift") this.shiftHeld = true;
|
|
3115
3392
|
};
|
|
@@ -3118,8 +3395,48 @@ var ShapeTool = class {
|
|
|
3118
3395
|
};
|
|
3119
3396
|
};
|
|
3120
3397
|
|
|
3398
|
+
// src/history/layer-commands.ts
|
|
3399
|
+
var CreateLayerCommand = class {
|
|
3400
|
+
constructor(manager, layer) {
|
|
3401
|
+
this.manager = manager;
|
|
3402
|
+
this.layer = layer;
|
|
3403
|
+
}
|
|
3404
|
+
execute(_store) {
|
|
3405
|
+
this.manager.addLayerDirect(this.layer);
|
|
3406
|
+
}
|
|
3407
|
+
undo(_store) {
|
|
3408
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3409
|
+
}
|
|
3410
|
+
};
|
|
3411
|
+
var RemoveLayerCommand = class {
|
|
3412
|
+
constructor(manager, layer) {
|
|
3413
|
+
this.manager = manager;
|
|
3414
|
+
this.layer = layer;
|
|
3415
|
+
}
|
|
3416
|
+
execute(_store) {
|
|
3417
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3418
|
+
}
|
|
3419
|
+
undo(_store) {
|
|
3420
|
+
this.manager.addLayerDirect(this.layer);
|
|
3421
|
+
}
|
|
3422
|
+
};
|
|
3423
|
+
var UpdateLayerCommand = class {
|
|
3424
|
+
constructor(manager, layerId, previous, current) {
|
|
3425
|
+
this.manager = manager;
|
|
3426
|
+
this.layerId = layerId;
|
|
3427
|
+
this.previous = previous;
|
|
3428
|
+
this.current = current;
|
|
3429
|
+
}
|
|
3430
|
+
execute(_store) {
|
|
3431
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.current });
|
|
3432
|
+
}
|
|
3433
|
+
undo(_store) {
|
|
3434
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.previous });
|
|
3435
|
+
}
|
|
3436
|
+
};
|
|
3437
|
+
|
|
3121
3438
|
// src/index.ts
|
|
3122
|
-
var VERSION = "0.
|
|
3439
|
+
var VERSION = "0.6.0";
|
|
3123
3440
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3124
3441
|
0 && (module.exports = {
|
|
3125
3442
|
AddElementCommand,
|
|
@@ -3128,6 +3445,7 @@ var VERSION = "0.4.1";
|
|
|
3128
3445
|
Background,
|
|
3129
3446
|
BatchCommand,
|
|
3130
3447
|
Camera,
|
|
3448
|
+
CreateLayerCommand,
|
|
3131
3449
|
ElementRenderer,
|
|
3132
3450
|
ElementStore,
|
|
3133
3451
|
EraserTool,
|
|
@@ -3137,15 +3455,18 @@ var VERSION = "0.4.1";
|
|
|
3137
3455
|
HistoryStack,
|
|
3138
3456
|
ImageTool,
|
|
3139
3457
|
InputHandler,
|
|
3458
|
+
LayerManager,
|
|
3140
3459
|
NoteEditor,
|
|
3141
3460
|
NoteTool,
|
|
3142
3461
|
PencilTool,
|
|
3143
3462
|
RemoveElementCommand,
|
|
3463
|
+
RemoveLayerCommand,
|
|
3144
3464
|
SelectTool,
|
|
3145
3465
|
ShapeTool,
|
|
3146
3466
|
TextTool,
|
|
3147
3467
|
ToolManager,
|
|
3148
3468
|
UpdateElementCommand,
|
|
3469
|
+
UpdateLayerCommand,
|
|
3149
3470
|
VERSION,
|
|
3150
3471
|
Viewport,
|
|
3151
3472
|
clearStaleBindings,
|
|
@@ -3171,6 +3492,7 @@ var VERSION = "0.4.1";
|
|
|
3171
3492
|
isBindable,
|
|
3172
3493
|
isNearBezier,
|
|
3173
3494
|
parseState,
|
|
3495
|
+
snapPoint,
|
|
3174
3496
|
unbindArrow,
|
|
3175
3497
|
updateBoundArrow
|
|
3176
3498
|
});
|