@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.js
CHANGED
|
@@ -23,15 +23,16 @@ var EventBus = class {
|
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
// src/core/state-serializer.ts
|
|
26
|
-
var CURRENT_VERSION =
|
|
27
|
-
function exportState(elements, camera) {
|
|
26
|
+
var CURRENT_VERSION = 2;
|
|
27
|
+
function exportState(elements, camera, layers = []) {
|
|
28
28
|
return {
|
|
29
29
|
version: CURRENT_VERSION,
|
|
30
30
|
camera: {
|
|
31
31
|
position: { ...camera.position },
|
|
32
32
|
zoom: camera.zoom
|
|
33
33
|
},
|
|
34
|
-
elements: elements.map((el) => structuredClone(el))
|
|
34
|
+
elements: elements.map((el) => structuredClone(el)),
|
|
35
|
+
layers: layers.map((l) => ({ ...l }))
|
|
35
36
|
};
|
|
36
37
|
}
|
|
37
38
|
function parseState(json) {
|
|
@@ -69,6 +70,19 @@ function validateState(data) {
|
|
|
69
70
|
migrateElement(el);
|
|
70
71
|
}
|
|
71
72
|
cleanBindings(obj["elements"]);
|
|
73
|
+
const layers = obj["layers"];
|
|
74
|
+
if (!Array.isArray(layers) || layers.length === 0) {
|
|
75
|
+
obj["layers"] = [
|
|
76
|
+
{
|
|
77
|
+
id: "default-layer",
|
|
78
|
+
name: "Layer 1",
|
|
79
|
+
visible: true,
|
|
80
|
+
locked: false,
|
|
81
|
+
order: 0,
|
|
82
|
+
opacity: 1
|
|
83
|
+
}
|
|
84
|
+
];
|
|
85
|
+
}
|
|
72
86
|
}
|
|
73
87
|
var VALID_TYPES = /* @__PURE__ */ new Set(["stroke", "note", "arrow", "image", "html", "text", "shape"]);
|
|
74
88
|
function validateElement(el) {
|
|
@@ -101,6 +115,9 @@ function cleanBindings(elements) {
|
|
|
101
115
|
}
|
|
102
116
|
}
|
|
103
117
|
function migrateElement(obj) {
|
|
118
|
+
if (typeof obj["layerId"] !== "string") {
|
|
119
|
+
obj["layerId"] = "default-layer";
|
|
120
|
+
}
|
|
104
121
|
if (obj["type"] === "arrow" && typeof obj["bend"] !== "number") {
|
|
105
122
|
obj["bend"] = 0;
|
|
106
123
|
}
|
|
@@ -119,6 +136,14 @@ function migrateElement(obj) {
|
|
|
119
136
|
}
|
|
120
137
|
}
|
|
121
138
|
|
|
139
|
+
// src/core/snap.ts
|
|
140
|
+
function snapPoint(point, gridSize) {
|
|
141
|
+
return {
|
|
142
|
+
x: Math.round(point.x / gridSize) * gridSize || 0,
|
|
143
|
+
y: Math.round(point.y / gridSize) * gridSize || 0
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
122
147
|
// src/core/auto-save.ts
|
|
123
148
|
var DEFAULT_KEY = "fieldnotes-autosave";
|
|
124
149
|
var DEFAULT_DEBOUNCE_MS = 1e3;
|
|
@@ -128,9 +153,11 @@ var AutoSave = class {
|
|
|
128
153
|
this.camera = camera;
|
|
129
154
|
this.key = options.key ?? DEFAULT_KEY;
|
|
130
155
|
this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
156
|
+
this.layerManager = options.layerManager;
|
|
131
157
|
}
|
|
132
158
|
key;
|
|
133
159
|
debounceMs;
|
|
160
|
+
layerManager;
|
|
134
161
|
timerId = null;
|
|
135
162
|
unsubscribers = [];
|
|
136
163
|
start() {
|
|
@@ -141,6 +168,9 @@ var AutoSave = class {
|
|
|
141
168
|
this.store.on("update", schedule),
|
|
142
169
|
this.camera.onChange(schedule)
|
|
143
170
|
];
|
|
171
|
+
if (this.layerManager) {
|
|
172
|
+
this.unsubscribers.push(this.layerManager.on("change", schedule));
|
|
173
|
+
}
|
|
144
174
|
}
|
|
145
175
|
stop() {
|
|
146
176
|
this.cancelPending();
|
|
@@ -173,7 +203,8 @@ var AutoSave = class {
|
|
|
173
203
|
}
|
|
174
204
|
save() {
|
|
175
205
|
if (typeof localStorage === "undefined") return;
|
|
176
|
-
const
|
|
206
|
+
const layers = this.layerManager?.snapshot() ?? [];
|
|
207
|
+
const state = exportState(this.store.snapshot(), this.camera, layers);
|
|
177
208
|
localStorage.setItem(this.key, JSON.stringify(state));
|
|
178
209
|
}
|
|
179
210
|
};
|
|
@@ -550,11 +581,20 @@ var InputHandler = class {
|
|
|
550
581
|
var ElementStore = class {
|
|
551
582
|
elements = /* @__PURE__ */ new Map();
|
|
552
583
|
bus = new EventBus();
|
|
584
|
+
layerOrderMap = /* @__PURE__ */ new Map();
|
|
553
585
|
get count() {
|
|
554
586
|
return this.elements.size;
|
|
555
587
|
}
|
|
588
|
+
setLayerOrder(order) {
|
|
589
|
+
this.layerOrderMap = new Map(order);
|
|
590
|
+
}
|
|
556
591
|
getAll() {
|
|
557
|
-
return [...this.elements.values()].sort((a, b) =>
|
|
592
|
+
return [...this.elements.values()].sort((a, b) => {
|
|
593
|
+
const layerA = this.layerOrderMap.get(a.layerId) ?? 0;
|
|
594
|
+
const layerB = this.layerOrderMap.get(b.layerId) ?? 0;
|
|
595
|
+
if (layerA !== layerB) return layerA - layerB;
|
|
596
|
+
return a.zIndex - b.zIndex;
|
|
597
|
+
});
|
|
558
598
|
}
|
|
559
599
|
getById(id) {
|
|
560
600
|
return this.elements.get(id);
|
|
@@ -738,12 +778,13 @@ function getEdgeIntersection(bounds, outsidePoint) {
|
|
|
738
778
|
y: cy + dy * scale
|
|
739
779
|
};
|
|
740
780
|
}
|
|
741
|
-
function findBindTarget(point, store, threshold, excludeId) {
|
|
781
|
+
function findBindTarget(point, store, threshold, excludeId, filter) {
|
|
742
782
|
let closest = null;
|
|
743
783
|
let closestDist = Infinity;
|
|
744
784
|
for (const el of store.getAll()) {
|
|
745
785
|
if (!isBindable(el)) continue;
|
|
746
786
|
if (excludeId && el.id === excludeId) continue;
|
|
787
|
+
if (filter && !filter(el)) continue;
|
|
747
788
|
const bounds = getElementBounds(el);
|
|
748
789
|
if (!bounds) continue;
|
|
749
790
|
const dist = distToBounds(point, bounds);
|
|
@@ -901,14 +942,19 @@ function smoothToSegments(points) {
|
|
|
901
942
|
}
|
|
902
943
|
|
|
903
944
|
// src/elements/element-renderer.ts
|
|
904
|
-
var DOM_ELEMENT_TYPES = /* @__PURE__ */ new Set(["note", "
|
|
945
|
+
var DOM_ELEMENT_TYPES = /* @__PURE__ */ new Set(["note", "html", "text"]);
|
|
905
946
|
var ARROWHEAD_LENGTH = 12;
|
|
906
947
|
var ARROWHEAD_ANGLE = Math.PI / 6;
|
|
907
948
|
var ElementRenderer = class {
|
|
908
949
|
store = null;
|
|
950
|
+
imageCache = /* @__PURE__ */ new Map();
|
|
951
|
+
onImageLoad = null;
|
|
909
952
|
setStore(store) {
|
|
910
953
|
this.store = store;
|
|
911
954
|
}
|
|
955
|
+
setOnImageLoad(callback) {
|
|
956
|
+
this.onImageLoad = callback;
|
|
957
|
+
}
|
|
912
958
|
isDomElement(element) {
|
|
913
959
|
return DOM_ELEMENT_TYPES.has(element.type);
|
|
914
960
|
}
|
|
@@ -923,6 +969,9 @@ var ElementRenderer = class {
|
|
|
923
969
|
case "shape":
|
|
924
970
|
this.renderShape(ctx, element);
|
|
925
971
|
break;
|
|
972
|
+
case "image":
|
|
973
|
+
this.renderImage(ctx, element);
|
|
974
|
+
break;
|
|
926
975
|
}
|
|
927
976
|
}
|
|
928
977
|
renderStroke(ctx, stroke) {
|
|
@@ -1058,6 +1107,20 @@ var ElementRenderer = class {
|
|
|
1058
1107
|
}
|
|
1059
1108
|
}
|
|
1060
1109
|
}
|
|
1110
|
+
renderImage(ctx, image) {
|
|
1111
|
+
const img = this.getImage(image.src);
|
|
1112
|
+
if (!img) return;
|
|
1113
|
+
ctx.drawImage(img, image.position.x, image.position.y, image.size.w, image.size.h);
|
|
1114
|
+
}
|
|
1115
|
+
getImage(src) {
|
|
1116
|
+
const cached = this.imageCache.get(src);
|
|
1117
|
+
if (cached) return cached.complete ? cached : null;
|
|
1118
|
+
const img = new Image();
|
|
1119
|
+
img.src = src;
|
|
1120
|
+
this.imageCache.set(src, img);
|
|
1121
|
+
img.onload = () => this.onImageLoad?.();
|
|
1122
|
+
return null;
|
|
1123
|
+
}
|
|
1061
1124
|
};
|
|
1062
1125
|
|
|
1063
1126
|
// src/elements/note-editor.ts
|
|
@@ -1409,6 +1472,7 @@ function createStroke(input) {
|
|
|
1409
1472
|
position: input.position ?? { x: 0, y: 0 },
|
|
1410
1473
|
zIndex: input.zIndex ?? 0,
|
|
1411
1474
|
locked: input.locked ?? false,
|
|
1475
|
+
layerId: input.layerId ?? "",
|
|
1412
1476
|
points: input.points,
|
|
1413
1477
|
color: input.color ?? "#000000",
|
|
1414
1478
|
width: input.width ?? 2,
|
|
@@ -1422,6 +1486,7 @@ function createNote(input) {
|
|
|
1422
1486
|
position: input.position,
|
|
1423
1487
|
zIndex: input.zIndex ?? 0,
|
|
1424
1488
|
locked: input.locked ?? false,
|
|
1489
|
+
layerId: input.layerId ?? "",
|
|
1425
1490
|
size: input.size ?? { w: 200, h: 100 },
|
|
1426
1491
|
text: input.text ?? "",
|
|
1427
1492
|
backgroundColor: input.backgroundColor ?? "#ffeb3b",
|
|
@@ -1435,6 +1500,7 @@ function createArrow(input) {
|
|
|
1435
1500
|
position: input.position ?? { x: 0, y: 0 },
|
|
1436
1501
|
zIndex: input.zIndex ?? 0,
|
|
1437
1502
|
locked: input.locked ?? false,
|
|
1503
|
+
layerId: input.layerId ?? "",
|
|
1438
1504
|
from: input.from,
|
|
1439
1505
|
to: input.to,
|
|
1440
1506
|
bend: input.bend ?? 0,
|
|
@@ -1452,6 +1518,7 @@ function createImage(input) {
|
|
|
1452
1518
|
position: input.position,
|
|
1453
1519
|
zIndex: input.zIndex ?? 0,
|
|
1454
1520
|
locked: input.locked ?? false,
|
|
1521
|
+
layerId: input.layerId ?? "",
|
|
1455
1522
|
size: input.size,
|
|
1456
1523
|
src: input.src
|
|
1457
1524
|
};
|
|
@@ -1463,6 +1530,7 @@ function createHtmlElement(input) {
|
|
|
1463
1530
|
position: input.position,
|
|
1464
1531
|
zIndex: input.zIndex ?? 0,
|
|
1465
1532
|
locked: input.locked ?? false,
|
|
1533
|
+
layerId: input.layerId ?? "",
|
|
1466
1534
|
size: input.size
|
|
1467
1535
|
};
|
|
1468
1536
|
}
|
|
@@ -1473,6 +1541,7 @@ function createShape(input) {
|
|
|
1473
1541
|
position: input.position,
|
|
1474
1542
|
zIndex: input.zIndex ?? 0,
|
|
1475
1543
|
locked: input.locked ?? false,
|
|
1544
|
+
layerId: input.layerId ?? "",
|
|
1476
1545
|
shape: input.shape ?? "rectangle",
|
|
1477
1546
|
size: input.size,
|
|
1478
1547
|
strokeColor: input.strokeColor ?? "#000000",
|
|
@@ -1487,6 +1556,7 @@ function createText(input) {
|
|
|
1487
1556
|
position: input.position,
|
|
1488
1557
|
zIndex: input.zIndex ?? 0,
|
|
1489
1558
|
locked: input.locked ?? false,
|
|
1559
|
+
layerId: input.layerId ?? "",
|
|
1490
1560
|
size: input.size ?? { w: 200, h: 28 },
|
|
1491
1561
|
text: input.text ?? "",
|
|
1492
1562
|
fontSize: input.fontSize ?? 16,
|
|
@@ -1495,16 +1565,168 @@ function createText(input) {
|
|
|
1495
1565
|
};
|
|
1496
1566
|
}
|
|
1497
1567
|
|
|
1568
|
+
// src/layers/layer-manager.ts
|
|
1569
|
+
var LayerManager = class {
|
|
1570
|
+
constructor(store) {
|
|
1571
|
+
this.store = store;
|
|
1572
|
+
const defaultLayer = {
|
|
1573
|
+
id: createId("layer"),
|
|
1574
|
+
name: "Layer 1",
|
|
1575
|
+
visible: true,
|
|
1576
|
+
locked: false,
|
|
1577
|
+
order: 0,
|
|
1578
|
+
opacity: 1
|
|
1579
|
+
};
|
|
1580
|
+
this.layers.set(defaultLayer.id, defaultLayer);
|
|
1581
|
+
this._activeLayerId = defaultLayer.id;
|
|
1582
|
+
this.syncLayerOrder();
|
|
1583
|
+
}
|
|
1584
|
+
layers = /* @__PURE__ */ new Map();
|
|
1585
|
+
_activeLayerId;
|
|
1586
|
+
bus = new EventBus();
|
|
1587
|
+
get activeLayer() {
|
|
1588
|
+
const layer = this.layers.get(this._activeLayerId);
|
|
1589
|
+
if (!layer) throw new Error("Active layer not found");
|
|
1590
|
+
return { ...layer };
|
|
1591
|
+
}
|
|
1592
|
+
get activeLayerId() {
|
|
1593
|
+
return this._activeLayerId;
|
|
1594
|
+
}
|
|
1595
|
+
getLayers() {
|
|
1596
|
+
return [...this.layers.values()].sort((a, b) => a.order - b.order).map((l) => ({ ...l }));
|
|
1597
|
+
}
|
|
1598
|
+
getLayer(id) {
|
|
1599
|
+
const layer = this.layers.get(id);
|
|
1600
|
+
return layer ? { ...layer } : void 0;
|
|
1601
|
+
}
|
|
1602
|
+
isLayerVisible(id) {
|
|
1603
|
+
return this.layers.get(id)?.visible ?? true;
|
|
1604
|
+
}
|
|
1605
|
+
isLayerLocked(id) {
|
|
1606
|
+
return this.layers.get(id)?.locked ?? false;
|
|
1607
|
+
}
|
|
1608
|
+
createLayer(name) {
|
|
1609
|
+
const maxOrder = Math.max(...[...this.layers.values()].map((l) => l.order), -1);
|
|
1610
|
+
const autoName = name ?? `Layer ${this.layers.size + 1}`;
|
|
1611
|
+
const layer = {
|
|
1612
|
+
id: createId("layer"),
|
|
1613
|
+
name: autoName,
|
|
1614
|
+
visible: true,
|
|
1615
|
+
locked: false,
|
|
1616
|
+
order: maxOrder + 1,
|
|
1617
|
+
opacity: 1
|
|
1618
|
+
};
|
|
1619
|
+
this.addLayerDirect(layer);
|
|
1620
|
+
return { ...layer };
|
|
1621
|
+
}
|
|
1622
|
+
removeLayer(id) {
|
|
1623
|
+
if (this.layers.size <= 1) {
|
|
1624
|
+
throw new Error("Cannot remove the last layer");
|
|
1625
|
+
}
|
|
1626
|
+
if (this._activeLayerId === id) {
|
|
1627
|
+
const remaining = [...this.layers.values()].filter((l) => l.id !== id).sort((a, b) => b.order - a.order);
|
|
1628
|
+
const fallback = remaining[0];
|
|
1629
|
+
if (fallback) this._activeLayerId = fallback.id;
|
|
1630
|
+
}
|
|
1631
|
+
const elements = this.store.getAll().filter((el) => el.layerId === id);
|
|
1632
|
+
for (const el of elements) {
|
|
1633
|
+
this.store.update(el.id, { layerId: this._activeLayerId });
|
|
1634
|
+
}
|
|
1635
|
+
this.removeLayerDirect(id);
|
|
1636
|
+
}
|
|
1637
|
+
renameLayer(id, name) {
|
|
1638
|
+
this.updateLayerDirect(id, { name });
|
|
1639
|
+
}
|
|
1640
|
+
reorderLayer(id, newOrder) {
|
|
1641
|
+
if (!this.layers.has(id)) return;
|
|
1642
|
+
this.updateLayerDirect(id, { order: newOrder });
|
|
1643
|
+
}
|
|
1644
|
+
setLayerVisible(id, visible) {
|
|
1645
|
+
if (!visible && id === this._activeLayerId) {
|
|
1646
|
+
const fallback = this.findFallbackLayer(id);
|
|
1647
|
+
if (!fallback) return false;
|
|
1648
|
+
this._activeLayerId = fallback.id;
|
|
1649
|
+
}
|
|
1650
|
+
this.updateLayerDirect(id, { visible });
|
|
1651
|
+
return true;
|
|
1652
|
+
}
|
|
1653
|
+
setLayerLocked(id, locked) {
|
|
1654
|
+
if (locked && id === this._activeLayerId) {
|
|
1655
|
+
const fallback = this.findFallbackLayer(id);
|
|
1656
|
+
if (!fallback) return false;
|
|
1657
|
+
this._activeLayerId = fallback.id;
|
|
1658
|
+
}
|
|
1659
|
+
this.updateLayerDirect(id, { locked });
|
|
1660
|
+
return true;
|
|
1661
|
+
}
|
|
1662
|
+
setActiveLayer(id) {
|
|
1663
|
+
if (!this.layers.has(id)) return;
|
|
1664
|
+
this._activeLayerId = id;
|
|
1665
|
+
this.bus.emit("change", null);
|
|
1666
|
+
}
|
|
1667
|
+
moveElementToLayer(elementId, layerId) {
|
|
1668
|
+
if (!this.layers.has(layerId)) return;
|
|
1669
|
+
this.store.update(elementId, { layerId });
|
|
1670
|
+
this.bus.emit("change", null);
|
|
1671
|
+
}
|
|
1672
|
+
snapshot() {
|
|
1673
|
+
return this.getLayers();
|
|
1674
|
+
}
|
|
1675
|
+
loadSnapshot(layers) {
|
|
1676
|
+
this.layers.clear();
|
|
1677
|
+
for (const layer of layers) {
|
|
1678
|
+
this.layers.set(layer.id, { ...layer });
|
|
1679
|
+
}
|
|
1680
|
+
const first = this.getLayers()[0];
|
|
1681
|
+
if (first) this._activeLayerId = first.id;
|
|
1682
|
+
this.syncLayerOrder();
|
|
1683
|
+
this.bus.emit("change", null);
|
|
1684
|
+
}
|
|
1685
|
+
on(event, callback) {
|
|
1686
|
+
return this.bus.on(event, callback);
|
|
1687
|
+
}
|
|
1688
|
+
addLayerDirect(layer) {
|
|
1689
|
+
this.layers.set(layer.id, { ...layer });
|
|
1690
|
+
this.syncLayerOrder();
|
|
1691
|
+
this.bus.emit("change", null);
|
|
1692
|
+
}
|
|
1693
|
+
removeLayerDirect(id) {
|
|
1694
|
+
this.layers.delete(id);
|
|
1695
|
+
this.syncLayerOrder();
|
|
1696
|
+
this.bus.emit("change", null);
|
|
1697
|
+
}
|
|
1698
|
+
updateLayerDirect(id, props) {
|
|
1699
|
+
const layer = this.layers.get(id);
|
|
1700
|
+
if (!layer) return;
|
|
1701
|
+
Object.assign(layer, props);
|
|
1702
|
+
if ("order" in props) this.syncLayerOrder();
|
|
1703
|
+
this.bus.emit("change", null);
|
|
1704
|
+
}
|
|
1705
|
+
syncLayerOrder() {
|
|
1706
|
+
const order = /* @__PURE__ */ new Map();
|
|
1707
|
+
for (const layer of this.layers.values()) {
|
|
1708
|
+
order.set(layer.id, layer.order);
|
|
1709
|
+
}
|
|
1710
|
+
this.store.setLayerOrder(order);
|
|
1711
|
+
}
|
|
1712
|
+
findFallbackLayer(excludeId) {
|
|
1713
|
+
return [...this.layers.values()].filter((l) => l.id !== excludeId && l.visible && !l.locked).sort((a, b) => b.order - a.order)[0];
|
|
1714
|
+
}
|
|
1715
|
+
};
|
|
1716
|
+
|
|
1498
1717
|
// src/canvas/viewport.ts
|
|
1499
1718
|
var Viewport = class {
|
|
1500
1719
|
constructor(container, options = {}) {
|
|
1501
1720
|
this.container = container;
|
|
1502
1721
|
this.camera = new Camera(options.camera);
|
|
1503
1722
|
this.background = new Background(options.background);
|
|
1723
|
+
this._gridSize = options.background?.spacing ?? 24;
|
|
1504
1724
|
this.store = new ElementStore();
|
|
1725
|
+
this.layerManager = new LayerManager(this.store);
|
|
1505
1726
|
this.toolManager = new ToolManager();
|
|
1506
1727
|
this.renderer = new ElementRenderer();
|
|
1507
1728
|
this.renderer.setStore(this.store);
|
|
1729
|
+
this.renderer.setOnImageLoad(() => this.requestRender());
|
|
1508
1730
|
this.noteEditor = new NoteEditor();
|
|
1509
1731
|
this.noteEditor.setOnStop((id) => this.onTextEditStop(id));
|
|
1510
1732
|
this.history = new HistoryStack();
|
|
@@ -1523,7 +1745,12 @@ var Viewport = class {
|
|
|
1523
1745
|
editElement: (id) => this.startEditingElement(id),
|
|
1524
1746
|
setCursor: (cursor) => {
|
|
1525
1747
|
this.wrapper.style.cursor = cursor;
|
|
1526
|
-
}
|
|
1748
|
+
},
|
|
1749
|
+
snapToGrid: false,
|
|
1750
|
+
gridSize: this._gridSize,
|
|
1751
|
+
activeLayerId: this.layerManager.activeLayerId,
|
|
1752
|
+
isLayerVisible: (id) => this.layerManager.isLayerVisible(id),
|
|
1753
|
+
isLayerLocked: (id) => this.layerManager.isLayerLocked(id)
|
|
1527
1754
|
};
|
|
1528
1755
|
this.inputHandler = new InputHandler(this.wrapper, this.camera, {
|
|
1529
1756
|
toolManager: this.toolManager,
|
|
@@ -1544,6 +1771,10 @@ var Viewport = class {
|
|
|
1544
1771
|
this.store.on("update", () => this.requestRender()),
|
|
1545
1772
|
this.store.on("clear", () => this.clearDomNodes())
|
|
1546
1773
|
];
|
|
1774
|
+
this.layerManager.on("change", () => {
|
|
1775
|
+
this.toolContext.activeLayerId = this.layerManager.activeLayerId;
|
|
1776
|
+
this.requestRender();
|
|
1777
|
+
});
|
|
1547
1778
|
this.wrapper.addEventListener("dblclick", this.onDblClick);
|
|
1548
1779
|
this.wrapper.addEventListener("dragover", this.onDragOver);
|
|
1549
1780
|
this.wrapper.addEventListener("drop", this.onDrop);
|
|
@@ -1553,6 +1784,7 @@ var Viewport = class {
|
|
|
1553
1784
|
}
|
|
1554
1785
|
camera;
|
|
1555
1786
|
store;
|
|
1787
|
+
layerManager;
|
|
1556
1788
|
toolManager;
|
|
1557
1789
|
history;
|
|
1558
1790
|
domLayer;
|
|
@@ -1568,6 +1800,8 @@ var Viewport = class {
|
|
|
1568
1800
|
toolContext;
|
|
1569
1801
|
resizeObserver = null;
|
|
1570
1802
|
animFrameId = 0;
|
|
1803
|
+
_snapToGrid = false;
|
|
1804
|
+
_gridSize;
|
|
1571
1805
|
needsRender = true;
|
|
1572
1806
|
domNodes = /* @__PURE__ */ new Map();
|
|
1573
1807
|
htmlContent = /* @__PURE__ */ new Map();
|
|
@@ -1575,11 +1809,18 @@ var Viewport = class {
|
|
|
1575
1809
|
get ctx() {
|
|
1576
1810
|
return this.canvasEl.getContext("2d");
|
|
1577
1811
|
}
|
|
1812
|
+
get snapToGrid() {
|
|
1813
|
+
return this._snapToGrid;
|
|
1814
|
+
}
|
|
1815
|
+
setSnapToGrid(enabled) {
|
|
1816
|
+
this._snapToGrid = enabled;
|
|
1817
|
+
this.toolContext.snapToGrid = enabled;
|
|
1818
|
+
}
|
|
1578
1819
|
requestRender() {
|
|
1579
1820
|
this.needsRender = true;
|
|
1580
1821
|
}
|
|
1581
1822
|
exportState() {
|
|
1582
|
-
return exportState(this.store.snapshot(), this.camera);
|
|
1823
|
+
return exportState(this.store.snapshot(), this.camera, this.layerManager.snapshot());
|
|
1583
1824
|
}
|
|
1584
1825
|
exportJSON() {
|
|
1585
1826
|
return JSON.stringify(this.exportState());
|
|
@@ -1589,6 +1830,9 @@ var Viewport = class {
|
|
|
1589
1830
|
this.noteEditor.destroy(this.store);
|
|
1590
1831
|
this.clearDomNodes();
|
|
1591
1832
|
this.store.loadSnapshot(state.elements);
|
|
1833
|
+
if (state.layers && state.layers.length > 0) {
|
|
1834
|
+
this.layerManager.loadSnapshot(state.layers);
|
|
1835
|
+
}
|
|
1592
1836
|
this.history.clear();
|
|
1593
1837
|
this.historyRecorder.resume();
|
|
1594
1838
|
this.camera.moveTo(state.camera.position.x, state.camera.position.y);
|
|
@@ -1612,7 +1856,7 @@ var Viewport = class {
|
|
|
1612
1856
|
return result;
|
|
1613
1857
|
}
|
|
1614
1858
|
addImage(src, position, size = { w: 300, h: 200 }) {
|
|
1615
|
-
const image = createImage({ position, size, src });
|
|
1859
|
+
const image = createImage({ position, size, src, layerId: this.layerManager.activeLayerId });
|
|
1616
1860
|
this.historyRecorder.begin();
|
|
1617
1861
|
this.store.add(image);
|
|
1618
1862
|
this.historyRecorder.commit();
|
|
@@ -1620,7 +1864,7 @@ var Viewport = class {
|
|
|
1620
1864
|
return image.id;
|
|
1621
1865
|
}
|
|
1622
1866
|
addHtmlElement(dom, position, size = { w: 200, h: 150 }) {
|
|
1623
|
-
const el = createHtmlElement({ position, size });
|
|
1867
|
+
const el = createHtmlElement({ position, size, layerId: this.layerManager.activeLayerId });
|
|
1624
1868
|
this.htmlContent.set(el.id, dom);
|
|
1625
1869
|
this.historyRecorder.begin();
|
|
1626
1870
|
this.store.add(el);
|
|
@@ -1663,9 +1907,17 @@ var Viewport = class {
|
|
|
1663
1907
|
ctx.save();
|
|
1664
1908
|
ctx.translate(this.camera.position.x, this.camera.position.y);
|
|
1665
1909
|
ctx.scale(this.camera.zoom, this.camera.zoom);
|
|
1666
|
-
|
|
1910
|
+
const allElements = this.store.getAll();
|
|
1911
|
+
let domZIndex = 0;
|
|
1912
|
+
for (const element of allElements) {
|
|
1913
|
+
if (!this.layerManager.isLayerVisible(element.layerId)) {
|
|
1914
|
+
if (this.renderer.isDomElement(element)) {
|
|
1915
|
+
this.hideDomNode(element.id);
|
|
1916
|
+
}
|
|
1917
|
+
continue;
|
|
1918
|
+
}
|
|
1667
1919
|
if (this.renderer.isDomElement(element)) {
|
|
1668
|
-
this.syncDomNode(element);
|
|
1920
|
+
this.syncDomNode(element, domZIndex++);
|
|
1669
1921
|
} else {
|
|
1670
1922
|
this.renderer.renderCanvasElement(ctx, element);
|
|
1671
1923
|
}
|
|
@@ -1797,7 +2049,7 @@ var Viewport = class {
|
|
|
1797
2049
|
reader.readAsDataURL(file);
|
|
1798
2050
|
}
|
|
1799
2051
|
};
|
|
1800
|
-
syncDomNode(element) {
|
|
2052
|
+
syncDomNode(element, zIndex = 0) {
|
|
1801
2053
|
let node = this.domNodes.get(element.id);
|
|
1802
2054
|
if (!node) {
|
|
1803
2055
|
node = document.createElement("div");
|
|
@@ -1811,10 +2063,12 @@ var Viewport = class {
|
|
|
1811
2063
|
}
|
|
1812
2064
|
const size = "size" in element ? element.size : null;
|
|
1813
2065
|
Object.assign(node.style, {
|
|
2066
|
+
display: "block",
|
|
1814
2067
|
left: `${element.position.x}px`,
|
|
1815
2068
|
top: `${element.position.y}px`,
|
|
1816
2069
|
width: size ? `${size.w}px` : "auto",
|
|
1817
|
-
height: size ? `${size.h}px` : "auto"
|
|
2070
|
+
height: size ? `${size.h}px` : "auto",
|
|
2071
|
+
zIndex: String(zIndex)
|
|
1818
2072
|
});
|
|
1819
2073
|
this.renderDomContent(node, element);
|
|
1820
2074
|
}
|
|
@@ -1849,26 +2103,6 @@ var Viewport = class {
|
|
|
1849
2103
|
node.style.color = element.textColor;
|
|
1850
2104
|
}
|
|
1851
2105
|
}
|
|
1852
|
-
if (element.type === "image") {
|
|
1853
|
-
if (!node.dataset["initialized"]) {
|
|
1854
|
-
node.dataset["initialized"] = "true";
|
|
1855
|
-
const img = document.createElement("img");
|
|
1856
|
-
img.src = element.src;
|
|
1857
|
-
Object.assign(img.style, {
|
|
1858
|
-
width: "100%",
|
|
1859
|
-
height: "100%",
|
|
1860
|
-
objectFit: "contain",
|
|
1861
|
-
pointerEvents: "none"
|
|
1862
|
-
});
|
|
1863
|
-
img.draggable = false;
|
|
1864
|
-
node.appendChild(img);
|
|
1865
|
-
} else {
|
|
1866
|
-
const img = node.querySelector("img");
|
|
1867
|
-
if (img && img.src !== element.src) {
|
|
1868
|
-
img.src = element.src;
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
2106
|
if (element.type === "html" && !node.dataset["initialized"]) {
|
|
1873
2107
|
const content = this.htmlContent.get(element.id);
|
|
1874
2108
|
if (content) {
|
|
@@ -1951,6 +2185,10 @@ var Viewport = class {
|
|
|
1951
2185
|
}
|
|
1952
2186
|
}
|
|
1953
2187
|
}
|
|
2188
|
+
hideDomNode(id) {
|
|
2189
|
+
const node = this.domNodes.get(id);
|
|
2190
|
+
if (node) node.style.display = "none";
|
|
2191
|
+
}
|
|
1954
2192
|
removeDomNode(id) {
|
|
1955
2193
|
this.htmlContent.delete(id);
|
|
1956
2194
|
const node = this.domNodes.get(id);
|
|
@@ -2097,7 +2335,8 @@ var PencilTool = class {
|
|
|
2097
2335
|
const stroke = createStroke({
|
|
2098
2336
|
points: simplified,
|
|
2099
2337
|
color: this.color,
|
|
2100
|
-
width: this.width
|
|
2338
|
+
width: this.width,
|
|
2339
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2101
2340
|
});
|
|
2102
2341
|
ctx.store.add(stroke);
|
|
2103
2342
|
this.points = [];
|
|
@@ -2161,6 +2400,8 @@ var EraserTool = class {
|
|
|
2161
2400
|
const strokes = ctx.store.getElementsByType("stroke");
|
|
2162
2401
|
let erased = false;
|
|
2163
2402
|
for (const stroke of strokes) {
|
|
2403
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(stroke.layerId)) continue;
|
|
2404
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(stroke.layerId)) continue;
|
|
2164
2405
|
if (this.strokeIntersects(stroke, world)) {
|
|
2165
2406
|
ctx.store.remove(stroke.id);
|
|
2166
2407
|
erased = true;
|
|
@@ -2323,10 +2564,13 @@ var SelectTool = class {
|
|
|
2323
2564
|
this.mode = { type: "idle" };
|
|
2324
2565
|
ctx.setCursor?.("default");
|
|
2325
2566
|
}
|
|
2567
|
+
snap(point, ctx) {
|
|
2568
|
+
return ctx.snapToGrid && ctx.gridSize ? snapPoint(point, ctx.gridSize) : point;
|
|
2569
|
+
}
|
|
2326
2570
|
onPointerDown(state, ctx) {
|
|
2327
2571
|
this.ctx = ctx;
|
|
2328
2572
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
2329
|
-
this.lastWorld = world;
|
|
2573
|
+
this.lastWorld = this.snap(world, ctx);
|
|
2330
2574
|
this.currentWorld = world;
|
|
2331
2575
|
const arrowHit = hitTestArrowHandles(world, this._selectedIds, ctx);
|
|
2332
2576
|
if (arrowHit) {
|
|
@@ -2379,9 +2623,10 @@ var SelectTool = class {
|
|
|
2379
2623
|
}
|
|
2380
2624
|
if (this.mode.type === "dragging" && this._selectedIds.length > 0) {
|
|
2381
2625
|
ctx.setCursor?.("move");
|
|
2382
|
-
const
|
|
2383
|
-
const
|
|
2384
|
-
this.lastWorld
|
|
2626
|
+
const snapped = this.snap(world, ctx);
|
|
2627
|
+
const dx = snapped.x - this.lastWorld.x;
|
|
2628
|
+
const dy = snapped.y - this.lastWorld.y;
|
|
2629
|
+
this.lastWorld = snapped;
|
|
2385
2630
|
for (const id of this._selectedIds) {
|
|
2386
2631
|
const el = ctx.store.getById(id);
|
|
2387
2632
|
if (!el || el.locked) continue;
|
|
@@ -2642,6 +2887,8 @@ var SelectTool = class {
|
|
|
2642
2887
|
findElementsInRect(marquee, ctx) {
|
|
2643
2888
|
const ids = [];
|
|
2644
2889
|
for (const el of ctx.store.getAll()) {
|
|
2890
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
2891
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
2645
2892
|
const bounds = this.getElementBounds(el);
|
|
2646
2893
|
if (bounds && this.rectsOverlap(marquee, bounds)) {
|
|
2647
2894
|
ids.push(el.id);
|
|
@@ -2676,6 +2923,8 @@ var SelectTool = class {
|
|
|
2676
2923
|
hitTest(world, ctx) {
|
|
2677
2924
|
const elements = ctx.store.getAll().reverse();
|
|
2678
2925
|
for (const el of elements) {
|
|
2926
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;
|
|
2927
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;
|
|
2679
2928
|
if (this.isInsideBounds(world, el)) return el;
|
|
2680
2929
|
}
|
|
2681
2930
|
return null;
|
|
@@ -2720,17 +2969,26 @@ var ArrowTool = class {
|
|
|
2720
2969
|
if (options.color !== void 0) this.color = options.color;
|
|
2721
2970
|
if (options.width !== void 0) this.width = options.width;
|
|
2722
2971
|
}
|
|
2972
|
+
layerFilter(ctx) {
|
|
2973
|
+
if (!ctx.isLayerVisible && !ctx.isLayerLocked) return void 0;
|
|
2974
|
+
return (el) => {
|
|
2975
|
+
if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) return false;
|
|
2976
|
+
if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) return false;
|
|
2977
|
+
return true;
|
|
2978
|
+
};
|
|
2979
|
+
}
|
|
2723
2980
|
onPointerDown(state, ctx) {
|
|
2724
2981
|
this.drawing = true;
|
|
2725
2982
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
2726
2983
|
const threshold = BIND_THRESHOLD2 / ctx.camera.zoom;
|
|
2727
|
-
const
|
|
2984
|
+
const filter = this.layerFilter(ctx);
|
|
2985
|
+
const target = findBindTarget(world, ctx.store, threshold, void 0, filter);
|
|
2728
2986
|
if (target) {
|
|
2729
2987
|
this.start = getElementCenter(target);
|
|
2730
2988
|
this.fromBinding = { elementId: target.id };
|
|
2731
2989
|
this.fromTarget = target;
|
|
2732
2990
|
} else {
|
|
2733
|
-
this.start = world;
|
|
2991
|
+
this.start = ctx.snapToGrid && ctx.gridSize ? snapPoint(world, ctx.gridSize) : world;
|
|
2734
2992
|
this.fromBinding = void 0;
|
|
2735
2993
|
this.fromTarget = null;
|
|
2736
2994
|
}
|
|
@@ -2742,12 +3000,13 @@ var ArrowTool = class {
|
|
|
2742
3000
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
2743
3001
|
const threshold = BIND_THRESHOLD2 / ctx.camera.zoom;
|
|
2744
3002
|
const excludeId = this.fromBinding?.elementId;
|
|
2745
|
-
const
|
|
3003
|
+
const filter = this.layerFilter(ctx);
|
|
3004
|
+
const target = findBindTarget(world, ctx.store, threshold, excludeId, filter);
|
|
2746
3005
|
if (target) {
|
|
2747
3006
|
this.end = getElementCenter(target);
|
|
2748
3007
|
this.toTarget = target;
|
|
2749
3008
|
} else {
|
|
2750
|
-
this.end = world;
|
|
3009
|
+
this.end = ctx.snapToGrid && ctx.gridSize ? snapPoint(world, ctx.gridSize) : world;
|
|
2751
3010
|
this.toTarget = null;
|
|
2752
3011
|
}
|
|
2753
3012
|
ctx.requestRender();
|
|
@@ -2763,7 +3022,8 @@ var ArrowTool = class {
|
|
|
2763
3022
|
color: this.color,
|
|
2764
3023
|
width: this.width,
|
|
2765
3024
|
fromBinding: this.fromBinding,
|
|
2766
|
-
toBinding: this.toTarget ? { elementId: this.toTarget.id } : void 0
|
|
3025
|
+
toBinding: this.toTarget ? { elementId: this.toTarget.id } : void 0,
|
|
3026
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2767
3027
|
});
|
|
2768
3028
|
ctx.store.add(arrow);
|
|
2769
3029
|
this.fromTarget = null;
|
|
@@ -2842,12 +3102,16 @@ var NoteTool = class {
|
|
|
2842
3102
|
onPointerMove(_state, _ctx) {
|
|
2843
3103
|
}
|
|
2844
3104
|
onPointerUp(state, ctx) {
|
|
2845
|
-
|
|
3105
|
+
let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3106
|
+
if (ctx.snapToGrid && ctx.gridSize) {
|
|
3107
|
+
world = snapPoint(world, ctx.gridSize);
|
|
3108
|
+
}
|
|
2846
3109
|
const note = createNote({
|
|
2847
3110
|
position: world,
|
|
2848
3111
|
size: { ...this.size },
|
|
2849
3112
|
backgroundColor: this.backgroundColor,
|
|
2850
|
-
textColor: this.textColor
|
|
3113
|
+
textColor: this.textColor,
|
|
3114
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2851
3115
|
});
|
|
2852
3116
|
ctx.store.add(note);
|
|
2853
3117
|
ctx.requestRender();
|
|
@@ -2883,12 +3147,16 @@ var TextTool = class {
|
|
|
2883
3147
|
onPointerMove(_state, _ctx) {
|
|
2884
3148
|
}
|
|
2885
3149
|
onPointerUp(state, ctx) {
|
|
2886
|
-
|
|
3150
|
+
let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3151
|
+
if (ctx.snapToGrid && ctx.gridSize) {
|
|
3152
|
+
world = snapPoint(world, ctx.gridSize);
|
|
3153
|
+
}
|
|
2887
3154
|
const textEl = createText({
|
|
2888
3155
|
position: world,
|
|
2889
3156
|
fontSize: this.fontSize,
|
|
2890
3157
|
color: this.color,
|
|
2891
|
-
textAlign: this.textAlign
|
|
3158
|
+
textAlign: this.textAlign,
|
|
3159
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2892
3160
|
});
|
|
2893
3161
|
ctx.store.add(textEl);
|
|
2894
3162
|
ctx.requestRender();
|
|
@@ -2965,12 +3233,12 @@ var ShapeTool = class {
|
|
|
2965
3233
|
}
|
|
2966
3234
|
onPointerDown(state, ctx) {
|
|
2967
3235
|
this.drawing = true;
|
|
2968
|
-
this.start = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3236
|
+
this.start = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);
|
|
2969
3237
|
this.end = { ...this.start };
|
|
2970
3238
|
}
|
|
2971
3239
|
onPointerMove(state, ctx) {
|
|
2972
3240
|
if (!this.drawing) return;
|
|
2973
|
-
this.end = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
3241
|
+
this.end = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);
|
|
2974
3242
|
ctx.requestRender();
|
|
2975
3243
|
}
|
|
2976
3244
|
onPointerUp(_state, ctx) {
|
|
@@ -2984,7 +3252,8 @@ var ShapeTool = class {
|
|
|
2984
3252
|
shape: this.shape,
|
|
2985
3253
|
strokeColor: this.strokeColor,
|
|
2986
3254
|
strokeWidth: this.strokeWidth,
|
|
2987
|
-
fillColor: this.fillColor
|
|
3255
|
+
fillColor: this.fillColor,
|
|
3256
|
+
layerId: ctx.activeLayerId ?? ""
|
|
2988
3257
|
});
|
|
2989
3258
|
ctx.store.add(shape);
|
|
2990
3259
|
ctx.requestRender();
|
|
@@ -3034,6 +3303,9 @@ var ShapeTool = class {
|
|
|
3034
3303
|
}
|
|
3035
3304
|
return { position: { x, y }, size: { w, h } };
|
|
3036
3305
|
}
|
|
3306
|
+
snap(point, ctx) {
|
|
3307
|
+
return ctx.snapToGrid && ctx.gridSize ? snapPoint(point, ctx.gridSize) : point;
|
|
3308
|
+
}
|
|
3037
3309
|
onKeyDown = (e) => {
|
|
3038
3310
|
if (e.key === "Shift") this.shiftHeld = true;
|
|
3039
3311
|
};
|
|
@@ -3042,8 +3314,48 @@ var ShapeTool = class {
|
|
|
3042
3314
|
};
|
|
3043
3315
|
};
|
|
3044
3316
|
|
|
3317
|
+
// src/history/layer-commands.ts
|
|
3318
|
+
var CreateLayerCommand = class {
|
|
3319
|
+
constructor(manager, layer) {
|
|
3320
|
+
this.manager = manager;
|
|
3321
|
+
this.layer = layer;
|
|
3322
|
+
}
|
|
3323
|
+
execute(_store) {
|
|
3324
|
+
this.manager.addLayerDirect(this.layer);
|
|
3325
|
+
}
|
|
3326
|
+
undo(_store) {
|
|
3327
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3328
|
+
}
|
|
3329
|
+
};
|
|
3330
|
+
var RemoveLayerCommand = class {
|
|
3331
|
+
constructor(manager, layer) {
|
|
3332
|
+
this.manager = manager;
|
|
3333
|
+
this.layer = layer;
|
|
3334
|
+
}
|
|
3335
|
+
execute(_store) {
|
|
3336
|
+
this.manager.removeLayerDirect(this.layer.id);
|
|
3337
|
+
}
|
|
3338
|
+
undo(_store) {
|
|
3339
|
+
this.manager.addLayerDirect(this.layer);
|
|
3340
|
+
}
|
|
3341
|
+
};
|
|
3342
|
+
var UpdateLayerCommand = class {
|
|
3343
|
+
constructor(manager, layerId, previous, current) {
|
|
3344
|
+
this.manager = manager;
|
|
3345
|
+
this.layerId = layerId;
|
|
3346
|
+
this.previous = previous;
|
|
3347
|
+
this.current = current;
|
|
3348
|
+
}
|
|
3349
|
+
execute(_store) {
|
|
3350
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.current });
|
|
3351
|
+
}
|
|
3352
|
+
undo(_store) {
|
|
3353
|
+
this.manager.updateLayerDirect(this.layerId, { ...this.previous });
|
|
3354
|
+
}
|
|
3355
|
+
};
|
|
3356
|
+
|
|
3045
3357
|
// src/index.ts
|
|
3046
|
-
var VERSION = "0.
|
|
3358
|
+
var VERSION = "0.6.0";
|
|
3047
3359
|
export {
|
|
3048
3360
|
AddElementCommand,
|
|
3049
3361
|
ArrowTool,
|
|
@@ -3051,6 +3363,7 @@ export {
|
|
|
3051
3363
|
Background,
|
|
3052
3364
|
BatchCommand,
|
|
3053
3365
|
Camera,
|
|
3366
|
+
CreateLayerCommand,
|
|
3054
3367
|
ElementRenderer,
|
|
3055
3368
|
ElementStore,
|
|
3056
3369
|
EraserTool,
|
|
@@ -3060,15 +3373,18 @@ export {
|
|
|
3060
3373
|
HistoryStack,
|
|
3061
3374
|
ImageTool,
|
|
3062
3375
|
InputHandler,
|
|
3376
|
+
LayerManager,
|
|
3063
3377
|
NoteEditor,
|
|
3064
3378
|
NoteTool,
|
|
3065
3379
|
PencilTool,
|
|
3066
3380
|
RemoveElementCommand,
|
|
3381
|
+
RemoveLayerCommand,
|
|
3067
3382
|
SelectTool,
|
|
3068
3383
|
ShapeTool,
|
|
3069
3384
|
TextTool,
|
|
3070
3385
|
ToolManager,
|
|
3071
3386
|
UpdateElementCommand,
|
|
3387
|
+
UpdateLayerCommand,
|
|
3072
3388
|
VERSION,
|
|
3073
3389
|
Viewport,
|
|
3074
3390
|
clearStaleBindings,
|
|
@@ -3094,6 +3410,7 @@ export {
|
|
|
3094
3410
|
isBindable,
|
|
3095
3411
|
isNearBezier,
|
|
3096
3412
|
parseState,
|
|
3413
|
+
snapPoint,
|
|
3097
3414
|
unbindArrow,
|
|
3098
3415
|
updateBoundArrow
|
|
3099
3416
|
};
|