@fieldnotes/core 0.31.1 → 0.33.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/README.md +25 -0
- package/dist/index.cjs +243 -36
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -2
- package/dist/index.d.ts +17 -2
- package/dist/index.js +243 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -563,6 +563,31 @@ const unsub = viewport.onSelectionChange((ids) => {
|
|
|
563
563
|
// call unsub() to unsubscribe
|
|
564
564
|
```
|
|
565
565
|
|
|
566
|
+
## Aligning the Selection
|
|
567
|
+
|
|
568
|
+
Two methods on `Viewport` let you snap or space selected elements in one undo step.
|
|
569
|
+
|
|
570
|
+
- **`viewport.alignSelection(edge)`** — `edge`: `AlignEdge` = `'left' | 'center-x' | 'right' | 'top' | 'middle' | 'bottom'`; aligns every selected element to the corresponding edge or center of the selection's bounding box. Needs 2+ selected elements. Locked elements anchor the bounding box without moving.
|
|
571
|
+
- **`viewport.distributeSelection(axis)`** — `axis`: `DistributeAxis` = `'horizontal' | 'vertical'`; evenly spaces selected elements' centers along the axis. Needs 3+ selected elements. Locked elements anchor the span without moving.
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
viewport.alignSelection('left'); // flush left edges
|
|
575
|
+
viewport.alignSelection('center-x'); // center on vertical axis
|
|
576
|
+
viewport.alignSelection('middle'); // center on horizontal axis
|
|
577
|
+
viewport.distributeSelection('horizontal'); // equal horizontal spacing
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
Grids are ignored by both operations.
|
|
581
|
+
|
|
582
|
+
## Smart Alignment Guides
|
|
583
|
+
|
|
584
|
+
Call `viewport.setSmartGuides(true)` to enable drag-time alignment snapping. While dragging a selection, its edges and centers snap to the edges and centers of nearby visible elements (within 6 screen pixels), and guide lines are drawn at each matched alignment. Smart guides replace grid snapping for the duration of the drag; the result is still committed as a single undo step.
|
|
585
|
+
|
|
586
|
+
```typescript
|
|
587
|
+
viewport.setSmartGuides(true); // enable
|
|
588
|
+
viewport.setSmartGuides(false); // disable (default)
|
|
589
|
+
```
|
|
590
|
+
|
|
566
591
|
## Built-in Interactions
|
|
567
592
|
|
|
568
593
|
| Input | Action |
|
package/dist/index.cjs
CHANGED
|
@@ -2351,6 +2351,23 @@ function distToBounds(point, bounds) {
|
|
|
2351
2351
|
function findBoundArrows(elementId, store) {
|
|
2352
2352
|
return store.getElementsByType("arrow").filter((a) => a.fromBinding?.elementId === elementId || a.toBinding?.elementId === elementId);
|
|
2353
2353
|
}
|
|
2354
|
+
function updateArrowsBoundToElements(movedIds, store) {
|
|
2355
|
+
const movedNonArrowIds = /* @__PURE__ */ new Set();
|
|
2356
|
+
for (const id of movedIds) {
|
|
2357
|
+
const el = store.getById(id);
|
|
2358
|
+
if (el && el.type !== "arrow") movedNonArrowIds.add(id);
|
|
2359
|
+
}
|
|
2360
|
+
if (movedNonArrowIds.size === 0) return;
|
|
2361
|
+
const updated = /* @__PURE__ */ new Set();
|
|
2362
|
+
for (const id of movedNonArrowIds) {
|
|
2363
|
+
for (const ba of findBoundArrows(id, store)) {
|
|
2364
|
+
if (updated.has(ba.id)) continue;
|
|
2365
|
+
updated.add(ba.id);
|
|
2366
|
+
const updates = updateBoundArrow(ba, store);
|
|
2367
|
+
if (updates) store.update(ba.id, updates);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2354
2371
|
function updateBoundArrow(arrow, store) {
|
|
2355
2372
|
if (!arrow.fromBinding && !arrow.toBinding) return null;
|
|
2356
2373
|
const updates = {};
|
|
@@ -3778,6 +3795,19 @@ var NoteEditor = class {
|
|
|
3778
3795
|
}
|
|
3779
3796
|
};
|
|
3780
3797
|
|
|
3798
|
+
// src/elements/translate.ts
|
|
3799
|
+
function translateElementPatch(el, dx, dy) {
|
|
3800
|
+
const position = { x: el.position.x + dx, y: el.position.y + dy };
|
|
3801
|
+
if (el.type === "arrow") {
|
|
3802
|
+
return {
|
|
3803
|
+
position,
|
|
3804
|
+
from: { x: el.from.x + dx, y: el.from.y + dy },
|
|
3805
|
+
to: { x: el.to.x + dx, y: el.to.y + dy }
|
|
3806
|
+
};
|
|
3807
|
+
}
|
|
3808
|
+
return { position };
|
|
3809
|
+
}
|
|
3810
|
+
|
|
3781
3811
|
// src/elements/arrow-label-editor.ts
|
|
3782
3812
|
var ArrowLabelEditor = class {
|
|
3783
3813
|
input = null;
|
|
@@ -5464,6 +5494,16 @@ function getElementStyle(element) {
|
|
|
5464
5494
|
}
|
|
5465
5495
|
|
|
5466
5496
|
// src/canvas/viewport.ts
|
|
5497
|
+
function unionBounds(list) {
|
|
5498
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
5499
|
+
for (const b of list) {
|
|
5500
|
+
minX = Math.min(minX, b.x);
|
|
5501
|
+
minY = Math.min(minY, b.y);
|
|
5502
|
+
maxX = Math.max(maxX, b.x + b.w);
|
|
5503
|
+
maxY = Math.max(maxY, b.y + b.h);
|
|
5504
|
+
}
|
|
5505
|
+
return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };
|
|
5506
|
+
}
|
|
5467
5507
|
var EMPTY_IDS = [];
|
|
5468
5508
|
var ARROW_HIT_THRESHOLD = 10;
|
|
5469
5509
|
function noop() {
|
|
@@ -5536,7 +5576,9 @@ var Viewport = class {
|
|
|
5536
5576
|
gridSize: this._gridSize,
|
|
5537
5577
|
activeLayerId: this.layerManager.activeLayerId,
|
|
5538
5578
|
isLayerVisible: (id) => this.layerManager.isLayerVisible(id),
|
|
5539
|
-
isLayerLocked: (id) => this.layerManager.isLayerLocked(id)
|
|
5579
|
+
isLayerLocked: (id) => this.layerManager.isLayerLocked(id),
|
|
5580
|
+
smartGuides: false,
|
|
5581
|
+
getVisibleRect: () => this.camera.getVisibleRect(this.canvasEl.clientWidth, this.canvasEl.clientHeight)
|
|
5540
5582
|
};
|
|
5541
5583
|
this.inputHandler = new InputHandler(this.wrapper, this.camera, {
|
|
5542
5584
|
toolManager: this.toolManager,
|
|
@@ -5640,6 +5682,7 @@ var Viewport = class {
|
|
|
5640
5682
|
marginViewport;
|
|
5641
5683
|
resizeObserver = null;
|
|
5642
5684
|
_snapToGrid = false;
|
|
5685
|
+
_smartGuides = false;
|
|
5643
5686
|
_gridSize;
|
|
5644
5687
|
renderLoop;
|
|
5645
5688
|
domNodeManager;
|
|
@@ -5660,6 +5703,13 @@ var Viewport = class {
|
|
|
5660
5703
|
this._snapToGrid = enabled;
|
|
5661
5704
|
this.toolContext.snapToGrid = enabled;
|
|
5662
5705
|
}
|
|
5706
|
+
get smartGuides() {
|
|
5707
|
+
return this._smartGuides;
|
|
5708
|
+
}
|
|
5709
|
+
setSmartGuides(enabled) {
|
|
5710
|
+
this._smartGuides = enabled;
|
|
5711
|
+
this.toolContext.smartGuides = enabled;
|
|
5712
|
+
}
|
|
5663
5713
|
fitToContent(padding = 40) {
|
|
5664
5714
|
if (this.wrapper.clientWidth === 0 || this.wrapper.clientHeight === 0) return;
|
|
5665
5715
|
const visibleElements = this.store.getAll().filter((el) => this.layerManager.isLayerVisible(el.layerId));
|
|
@@ -5873,6 +5923,86 @@ var Viewport = class {
|
|
|
5873
5923
|
}
|
|
5874
5924
|
this.historyRecorder.commit();
|
|
5875
5925
|
}
|
|
5926
|
+
alignSelection(edge) {
|
|
5927
|
+
const bounded = this.boundedSelection();
|
|
5928
|
+
if (bounded.length < 2) return;
|
|
5929
|
+
const B = unionBounds(bounded.map((e) => e.bounds));
|
|
5930
|
+
this.historyRecorder.begin();
|
|
5931
|
+
const moved = [];
|
|
5932
|
+
for (const { id, el, bounds: b } of bounded) {
|
|
5933
|
+
if (!this.isMovable(el)) continue;
|
|
5934
|
+
let dx = 0;
|
|
5935
|
+
let dy = 0;
|
|
5936
|
+
switch (edge) {
|
|
5937
|
+
case "left":
|
|
5938
|
+
dx = B.x - b.x;
|
|
5939
|
+
break;
|
|
5940
|
+
case "right":
|
|
5941
|
+
dx = B.x + B.w - (b.x + b.w);
|
|
5942
|
+
break;
|
|
5943
|
+
case "center-x":
|
|
5944
|
+
dx = B.x + B.w / 2 - (b.x + b.w / 2);
|
|
5945
|
+
break;
|
|
5946
|
+
case "top":
|
|
5947
|
+
dy = B.y - b.y;
|
|
5948
|
+
break;
|
|
5949
|
+
case "bottom":
|
|
5950
|
+
dy = B.y + B.h - (b.y + b.h);
|
|
5951
|
+
break;
|
|
5952
|
+
case "middle":
|
|
5953
|
+
dy = B.y + B.h / 2 - (b.y + b.h / 2);
|
|
5954
|
+
break;
|
|
5955
|
+
}
|
|
5956
|
+
if (dx === 0 && dy === 0) continue;
|
|
5957
|
+
this.store.update(id, translateElementPatch(el, dx, dy));
|
|
5958
|
+
moved.push(id);
|
|
5959
|
+
}
|
|
5960
|
+
updateArrowsBoundToElements(moved, this.store);
|
|
5961
|
+
this.historyRecorder.commit();
|
|
5962
|
+
this.requestRender();
|
|
5963
|
+
}
|
|
5964
|
+
distributeSelection(axis) {
|
|
5965
|
+
const bounded = this.boundedSelection();
|
|
5966
|
+
if (bounded.length < 3) return;
|
|
5967
|
+
const center = (b) => axis === "horizontal" ? b.x + b.w / 2 : b.y + b.h / 2;
|
|
5968
|
+
const sorted = [...bounded].sort((p, q) => center(p.bounds) - center(q.bounds));
|
|
5969
|
+
const first = sorted[0];
|
|
5970
|
+
const last = sorted[sorted.length - 1];
|
|
5971
|
+
if (!first || !last) return;
|
|
5972
|
+
const c0 = center(first.bounds);
|
|
5973
|
+
const cN = center(last.bounds);
|
|
5974
|
+
const n = sorted.length;
|
|
5975
|
+
this.historyRecorder.begin();
|
|
5976
|
+
const moved = [];
|
|
5977
|
+
for (let i = 1; i < n - 1; i++) {
|
|
5978
|
+
const item = sorted[i];
|
|
5979
|
+
if (!item || !this.isMovable(item.el)) continue;
|
|
5980
|
+
const target = c0 + i * (cN - c0) / (n - 1);
|
|
5981
|
+
const delta = target - center(item.bounds);
|
|
5982
|
+
if (delta === 0) continue;
|
|
5983
|
+
const [dx, dy] = axis === "horizontal" ? [delta, 0] : [0, delta];
|
|
5984
|
+
this.store.update(item.id, translateElementPatch(item.el, dx, dy));
|
|
5985
|
+
moved.push(item.id);
|
|
5986
|
+
}
|
|
5987
|
+
updateArrowsBoundToElements(moved, this.store);
|
|
5988
|
+
this.historyRecorder.commit();
|
|
5989
|
+
this.requestRender();
|
|
5990
|
+
}
|
|
5991
|
+
boundedSelection() {
|
|
5992
|
+
const out = [];
|
|
5993
|
+
for (const id of this.getSelectedIds()) {
|
|
5994
|
+
const el = this.store.getById(id);
|
|
5995
|
+
if (!el) continue;
|
|
5996
|
+
const bounds = getElementBounds(el);
|
|
5997
|
+
if (bounds) out.push({ id, el, bounds });
|
|
5998
|
+
}
|
|
5999
|
+
return out;
|
|
6000
|
+
}
|
|
6001
|
+
isMovable(el) {
|
|
6002
|
+
if (el.locked) return false;
|
|
6003
|
+
if (el.type === "arrow" && (el.fromBinding ?? el.toBinding)) return false;
|
|
6004
|
+
return true;
|
|
6005
|
+
}
|
|
5876
6006
|
getRenderStats() {
|
|
5877
6007
|
return this.renderLoop.getStats();
|
|
5878
6008
|
}
|
|
@@ -6617,8 +6747,47 @@ function renderArrowHandles(canvasCtx, arrow, zoom) {
|
|
|
6617
6747
|
}
|
|
6618
6748
|
}
|
|
6619
6749
|
|
|
6750
|
+
// src/elements/snap-guides.ts
|
|
6751
|
+
function xAnchors(b) {
|
|
6752
|
+
return { lo: b.x, mid: b.x + b.w / 2, hi: b.x + b.w };
|
|
6753
|
+
}
|
|
6754
|
+
function yAnchors(b) {
|
|
6755
|
+
return { lo: b.y, mid: b.y + b.h / 2, hi: b.y + b.h };
|
|
6756
|
+
}
|
|
6757
|
+
function bestAxisSnap(moving, targets, anchorsFn, threshold) {
|
|
6758
|
+
let best = null;
|
|
6759
|
+
for (const t of targets) {
|
|
6760
|
+
const ta = anchorsFn(t);
|
|
6761
|
+
const pairs = [
|
|
6762
|
+
// colinear alignment: same-type edges/centers line up
|
|
6763
|
+
[ta.lo - moving.lo, ta.lo],
|
|
6764
|
+
[ta.mid - moving.mid, ta.mid],
|
|
6765
|
+
[ta.hi - moving.hi, ta.hi],
|
|
6766
|
+
// abutment: the moving box sits flush against the target's opposite edge
|
|
6767
|
+
[ta.lo - moving.hi, ta.lo],
|
|
6768
|
+
[ta.hi - moving.lo, ta.hi]
|
|
6769
|
+
];
|
|
6770
|
+
for (const [delta, position] of pairs) {
|
|
6771
|
+
const abs = Math.abs(delta);
|
|
6772
|
+
if (abs <= threshold && (best === null || abs < Math.abs(best.delta))) {
|
|
6773
|
+
best = { delta, position };
|
|
6774
|
+
}
|
|
6775
|
+
}
|
|
6776
|
+
}
|
|
6777
|
+
return best;
|
|
6778
|
+
}
|
|
6779
|
+
function computeSnapGuides(moving, targets, threshold) {
|
|
6780
|
+
const xSnap = bestAxisSnap(xAnchors(moving), targets, xAnchors, threshold);
|
|
6781
|
+
const ySnap = bestAxisSnap(yAnchors(moving), targets, yAnchors, threshold);
|
|
6782
|
+
const guides = [];
|
|
6783
|
+
if (xSnap) guides.push({ axis: "x", position: xSnap.position });
|
|
6784
|
+
if (ySnap) guides.push({ axis: "y", position: ySnap.position });
|
|
6785
|
+
return { dx: xSnap?.delta ?? 0, dy: ySnap?.delta ?? 0, guides };
|
|
6786
|
+
}
|
|
6787
|
+
|
|
6620
6788
|
// src/tools/select-tool.ts
|
|
6621
6789
|
var HANDLE_SIZE = 8;
|
|
6790
|
+
var SNAP_PX = 6;
|
|
6622
6791
|
var HANDLE_HIT_PADDING2 = 4;
|
|
6623
6792
|
var SELECTION_PAD = 4;
|
|
6624
6793
|
var MIN_ELEMENT_SIZE = 20;
|
|
@@ -6638,6 +6807,9 @@ var SelectTool = class {
|
|
|
6638
6807
|
ctx = null;
|
|
6639
6808
|
pendingSingleSelectId = null;
|
|
6640
6809
|
hasDragged = false;
|
|
6810
|
+
activeGuides = [];
|
|
6811
|
+
dragSnapTargets = null;
|
|
6812
|
+
dragVisibleRect = null;
|
|
6641
6813
|
resizeAspectRatio = 0;
|
|
6642
6814
|
hoveredId = null;
|
|
6643
6815
|
get selectedIds() {
|
|
@@ -6669,6 +6841,9 @@ var SelectTool = class {
|
|
|
6669
6841
|
this.setSelectedIds([]);
|
|
6670
6842
|
this.mode = { type: "idle" };
|
|
6671
6843
|
this.hoveredId = null;
|
|
6844
|
+
this.activeGuides = [];
|
|
6845
|
+
this.dragSnapTargets = null;
|
|
6846
|
+
this.dragVisibleRect = null;
|
|
6672
6847
|
ctx.setCursor?.("default");
|
|
6673
6848
|
}
|
|
6674
6849
|
snap(point, ctx) {
|
|
@@ -6677,6 +6852,8 @@ var SelectTool = class {
|
|
|
6677
6852
|
onPointerDown(state, ctx) {
|
|
6678
6853
|
this.ctx = ctx;
|
|
6679
6854
|
this.setHovered(null, ctx);
|
|
6855
|
+
this.dragSnapTargets = null;
|
|
6856
|
+
this.dragVisibleRect = null;
|
|
6680
6857
|
const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });
|
|
6681
6858
|
this.lastWorld = this.snap(world, ctx);
|
|
6682
6859
|
this.currentWorld = world;
|
|
@@ -6777,6 +6954,31 @@ var SelectTool = class {
|
|
|
6777
6954
|
const dx = snapped.x - this.lastWorld.x;
|
|
6778
6955
|
const dy = snapped.y - this.lastWorld.y;
|
|
6779
6956
|
this.lastWorld = snapped;
|
|
6957
|
+
let adjDx = dx;
|
|
6958
|
+
let adjDy = dy;
|
|
6959
|
+
this.activeGuides = [];
|
|
6960
|
+
if (ctx.smartGuides) {
|
|
6961
|
+
if (this.dragSnapTargets === null) {
|
|
6962
|
+
const selSet = new Set(this._selectedIds);
|
|
6963
|
+
this.dragVisibleRect = ctx.getVisibleRect?.() ?? null;
|
|
6964
|
+
const candidates = (this.dragVisibleRect ? ctx.store.queryRect(this.dragVisibleRect) : ctx.store.getAll()).filter((el) => !selSet.has(el.id) && el.type !== "grid");
|
|
6965
|
+
const targets = [];
|
|
6966
|
+
for (const el of candidates) {
|
|
6967
|
+
const b = getElementBounds(el);
|
|
6968
|
+
if (b) targets.push(b);
|
|
6969
|
+
}
|
|
6970
|
+
this.dragSnapTargets = targets;
|
|
6971
|
+
}
|
|
6972
|
+
const selectedEls = this._selectedIds.map((id) => ctx.store.getById(id)).filter((el) => !!el && !el.locked);
|
|
6973
|
+
const base = getElementsBoundingBox(selectedEls);
|
|
6974
|
+
if (base) {
|
|
6975
|
+
const moving = { x: base.x + dx, y: base.y + dy, w: base.w, h: base.h };
|
|
6976
|
+
const res = computeSnapGuides(moving, this.dragSnapTargets, SNAP_PX / ctx.camera.zoom);
|
|
6977
|
+
adjDx = dx + res.dx;
|
|
6978
|
+
adjDy = dy + res.dy;
|
|
6979
|
+
this.activeGuides = res.guides;
|
|
6980
|
+
}
|
|
6981
|
+
}
|
|
6780
6982
|
for (const id of this._selectedIds) {
|
|
6781
6983
|
const el = ctx.store.getById(id);
|
|
6782
6984
|
if (!el || el.locked) continue;
|
|
@@ -6785,13 +6987,13 @@ var SelectTool = class {
|
|
|
6785
6987
|
continue;
|
|
6786
6988
|
}
|
|
6787
6989
|
ctx.store.update(id, {
|
|
6788
|
-
position: { x: el.position.x +
|
|
6789
|
-
from: { x: el.from.x +
|
|
6790
|
-
to: { x: el.to.x +
|
|
6990
|
+
position: { x: el.position.x + adjDx, y: el.position.y + adjDy },
|
|
6991
|
+
from: { x: el.from.x + adjDx, y: el.from.y + adjDy },
|
|
6992
|
+
to: { x: el.to.x + adjDx, y: el.to.y + adjDy }
|
|
6791
6993
|
});
|
|
6792
|
-
} else if (ctx.gridType && "size" in el) {
|
|
6793
|
-
const centerX = el.position.x + el.size.w / 2 +
|
|
6794
|
-
const centerY = el.position.y + el.size.h / 2 +
|
|
6994
|
+
} else if (!ctx.smartGuides && ctx.gridType && "size" in el) {
|
|
6995
|
+
const centerX = el.position.x + el.size.w / 2 + adjDx;
|
|
6996
|
+
const centerY = el.position.y + el.size.h / 2 + adjDy;
|
|
6795
6997
|
const snappedCenter = this.snap({ x: centerX, y: centerY }, ctx);
|
|
6796
6998
|
ctx.store.update(id, {
|
|
6797
6999
|
position: {
|
|
@@ -6801,7 +7003,7 @@ var SelectTool = class {
|
|
|
6801
7003
|
});
|
|
6802
7004
|
} else {
|
|
6803
7005
|
ctx.store.update(id, {
|
|
6804
|
-
position: { x: el.position.x +
|
|
7006
|
+
position: { x: el.position.x + adjDx, y: el.position.y + adjDy }
|
|
6805
7007
|
});
|
|
6806
7008
|
}
|
|
6807
7009
|
}
|
|
@@ -6831,6 +7033,10 @@ var SelectTool = class {
|
|
|
6831
7033
|
this.hasDragged = false;
|
|
6832
7034
|
const resizedNoteId = this.mode.type === "resizing" ? this.mode.elementId : null;
|
|
6833
7035
|
this.mode = { type: "idle" };
|
|
7036
|
+
this.activeGuides = [];
|
|
7037
|
+
this.dragSnapTargets = null;
|
|
7038
|
+
this.dragVisibleRect = null;
|
|
7039
|
+
ctx.requestRender();
|
|
6834
7040
|
ctx.setCursor?.("default");
|
|
6835
7041
|
if (resizedNoteId !== null) {
|
|
6836
7042
|
const el = ctx.store.getById(resizedNoteId);
|
|
@@ -6878,42 +7084,43 @@ var SelectTool = class {
|
|
|
6878
7084
|
}
|
|
6879
7085
|
}
|
|
6880
7086
|
}
|
|
7087
|
+
this.renderGuideLines(canvasCtx);
|
|
6881
7088
|
}
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6890
|
-
for (const
|
|
6891
|
-
|
|
6892
|
-
|
|
6893
|
-
|
|
6894
|
-
|
|
6895
|
-
|
|
6896
|
-
|
|
7089
|
+
renderGuideLines(canvasCtx) {
|
|
7090
|
+
if (this.mode.type !== "dragging" || !this.ctx || this.activeGuides.length === 0) return;
|
|
7091
|
+
const zoom = this.ctx.camera.zoom;
|
|
7092
|
+
const rect = this.dragVisibleRect;
|
|
7093
|
+
canvasCtx.save();
|
|
7094
|
+
canvasCtx.strokeStyle = "#FF4081";
|
|
7095
|
+
canvasCtx.lineWidth = 1 / zoom;
|
|
7096
|
+
canvasCtx.setLineDash([]);
|
|
7097
|
+
for (const g of this.activeGuides) {
|
|
7098
|
+
canvasCtx.beginPath();
|
|
7099
|
+
if (g.axis === "x") {
|
|
7100
|
+
const y0 = rect ? rect.y : this.currentWorld.y - 1e5;
|
|
7101
|
+
const y1 = rect ? rect.y + rect.h : this.currentWorld.y + 1e5;
|
|
7102
|
+
canvasCtx.moveTo(g.position, y0);
|
|
7103
|
+
canvasCtx.lineTo(g.position, y1);
|
|
7104
|
+
} else {
|
|
7105
|
+
const x0 = rect ? rect.x : this.currentWorld.x - 1e5;
|
|
7106
|
+
const x1 = rect ? rect.x + rect.w : this.currentWorld.x + 1e5;
|
|
7107
|
+
canvasCtx.moveTo(x0, g.position);
|
|
7108
|
+
canvasCtx.lineTo(x1, g.position);
|
|
6897
7109
|
}
|
|
7110
|
+
canvasCtx.stroke();
|
|
6898
7111
|
}
|
|
7112
|
+
canvasCtx.restore();
|
|
7113
|
+
}
|
|
7114
|
+
updateArrowsBoundTo(ids, ctx) {
|
|
7115
|
+
updateArrowsBoundToElements(ids, ctx.store);
|
|
6899
7116
|
}
|
|
6900
7117
|
nudgeSelection(dx, dy, ctx) {
|
|
6901
7118
|
let moved = false;
|
|
6902
7119
|
for (const id of this._selectedIds) {
|
|
6903
7120
|
const el = ctx.store.getById(id);
|
|
6904
7121
|
if (!el || el.locked) continue;
|
|
6905
|
-
if (el.type === "arrow")
|
|
6906
|
-
|
|
6907
|
-
ctx.store.update(id, {
|
|
6908
|
-
position: { x: el.position.x + dx, y: el.position.y + dy },
|
|
6909
|
-
from: { x: el.from.x + dx, y: el.from.y + dy },
|
|
6910
|
-
to: { x: el.to.x + dx, y: el.to.y + dy }
|
|
6911
|
-
});
|
|
6912
|
-
} else {
|
|
6913
|
-
ctx.store.update(id, {
|
|
6914
|
-
position: { x: el.position.x + dx, y: el.position.y + dy }
|
|
6915
|
-
});
|
|
6916
|
-
}
|
|
7122
|
+
if (el.type === "arrow" && (el.fromBinding || el.toBinding)) continue;
|
|
7123
|
+
ctx.store.update(id, translateElementPatch(el, dx, dy));
|
|
6917
7124
|
moved = true;
|
|
6918
7125
|
}
|
|
6919
7126
|
if (moved) {
|
|
@@ -8105,7 +8312,7 @@ var TemplateTool = class {
|
|
|
8105
8312
|
};
|
|
8106
8313
|
|
|
8107
8314
|
// src/index.ts
|
|
8108
|
-
var VERSION = "0.
|
|
8315
|
+
var VERSION = "0.33.0";
|
|
8109
8316
|
// Annotate the CommonJS export names for ESM import in node:
|
|
8110
8317
|
0 && (module.exports = {
|
|
8111
8318
|
ArrowTool,
|