@fieldnotes/core 0.40.4 → 0.42.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 +127 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -2
- package/dist/index.d.ts +11 -2
- package/dist/index.js +127 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1554,6 +1554,81 @@ var KeyboardHandler = class {
|
|
|
1554
1554
|
}
|
|
1555
1555
|
};
|
|
1556
1556
|
|
|
1557
|
+
// src/canvas/pan-inertia.ts
|
|
1558
|
+
var VELOCITY_WINDOW_MS = 60;
|
|
1559
|
+
var FRICTION = 0.92;
|
|
1560
|
+
var MIN_START_SPEED = 2;
|
|
1561
|
+
var MIN_STOP_SPEED = 0.3;
|
|
1562
|
+
var PanInertia = class {
|
|
1563
|
+
constructor(deps) {
|
|
1564
|
+
this.deps = deps;
|
|
1565
|
+
}
|
|
1566
|
+
samples = [];
|
|
1567
|
+
vx = 0;
|
|
1568
|
+
vy = 0;
|
|
1569
|
+
rafId = null;
|
|
1570
|
+
sample(dx, dy) {
|
|
1571
|
+
const t = this.deps.now();
|
|
1572
|
+
this.samples.push({ dx, dy, t });
|
|
1573
|
+
this.prune(t);
|
|
1574
|
+
}
|
|
1575
|
+
release() {
|
|
1576
|
+
if (!this.deps.enabled()) {
|
|
1577
|
+
this.reset();
|
|
1578
|
+
return;
|
|
1579
|
+
}
|
|
1580
|
+
const t = this.deps.now();
|
|
1581
|
+
this.prune(t);
|
|
1582
|
+
const recent = this.samples;
|
|
1583
|
+
if (recent.length === 0) {
|
|
1584
|
+
this.reset();
|
|
1585
|
+
return;
|
|
1586
|
+
}
|
|
1587
|
+
let sx = 0;
|
|
1588
|
+
let sy = 0;
|
|
1589
|
+
for (const s of recent) {
|
|
1590
|
+
sx += s.dx;
|
|
1591
|
+
sy += s.dy;
|
|
1592
|
+
}
|
|
1593
|
+
this.vx = sx / recent.length;
|
|
1594
|
+
this.vy = sy / recent.length;
|
|
1595
|
+
this.samples = [];
|
|
1596
|
+
if (Math.hypot(this.vx, this.vy) < MIN_START_SPEED) {
|
|
1597
|
+
this.vx = 0;
|
|
1598
|
+
this.vy = 0;
|
|
1599
|
+
return;
|
|
1600
|
+
}
|
|
1601
|
+
this.rafId = this.deps.requestFrame(this.step);
|
|
1602
|
+
}
|
|
1603
|
+
cancel() {
|
|
1604
|
+
this.reset();
|
|
1605
|
+
}
|
|
1606
|
+
step = () => {
|
|
1607
|
+
if (this.rafId === null) return;
|
|
1608
|
+
this.deps.pan(this.vx, this.vy);
|
|
1609
|
+
this.vx *= FRICTION;
|
|
1610
|
+
this.vy *= FRICTION;
|
|
1611
|
+
if (Math.hypot(this.vx, this.vy) >= MIN_STOP_SPEED) {
|
|
1612
|
+
this.rafId = this.deps.requestFrame(this.step);
|
|
1613
|
+
} else {
|
|
1614
|
+
this.reset();
|
|
1615
|
+
}
|
|
1616
|
+
};
|
|
1617
|
+
prune(now) {
|
|
1618
|
+
const cutoff = now - VELOCITY_WINDOW_MS;
|
|
1619
|
+
this.samples = this.samples.filter((s) => s.t >= cutoff);
|
|
1620
|
+
}
|
|
1621
|
+
reset() {
|
|
1622
|
+
if (this.rafId !== null) {
|
|
1623
|
+
this.deps.cancelFrame(this.rafId);
|
|
1624
|
+
this.rafId = null;
|
|
1625
|
+
}
|
|
1626
|
+
this.samples = [];
|
|
1627
|
+
this.vx = 0;
|
|
1628
|
+
this.vy = 0;
|
|
1629
|
+
}
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1557
1632
|
// src/canvas/input-handler.ts
|
|
1558
1633
|
var ZOOM_SENSITIVITY = 1e-3;
|
|
1559
1634
|
var MIDDLE_BUTTON = 1;
|
|
@@ -1579,6 +1654,16 @@ var InputHandler = class {
|
|
|
1579
1654
|
getLastPointerWorld: () => this.lastPointerWorld()
|
|
1580
1655
|
});
|
|
1581
1656
|
this.openContextMenu = options.openContextMenu;
|
|
1657
|
+
this.panInertiaEnabled = options.panInertia ?? true;
|
|
1658
|
+
this.panInertia = new PanInertia({
|
|
1659
|
+
pan: (dx, dy) => this.camera.pan(dx, dy),
|
|
1660
|
+
now: () => typeof performance !== "undefined" ? performance.now() : Date.now(),
|
|
1661
|
+
requestFrame: (cb) => typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame(cb) : 0,
|
|
1662
|
+
cancelFrame: (id) => {
|
|
1663
|
+
if (typeof cancelAnimationFrame !== "undefined") cancelAnimationFrame(id);
|
|
1664
|
+
},
|
|
1665
|
+
enabled: () => this.panInertiaEnabled
|
|
1666
|
+
});
|
|
1582
1667
|
this.scope = options.shortcuts?.scope ?? "focus";
|
|
1583
1668
|
this.keyboard = new KeyboardHandler({
|
|
1584
1669
|
element: this.element,
|
|
@@ -1628,6 +1713,8 @@ var InputHandler = class {
|
|
|
1628
1713
|
keyboard;
|
|
1629
1714
|
scope;
|
|
1630
1715
|
openContextMenu;
|
|
1716
|
+
panInertia;
|
|
1717
|
+
panInertiaEnabled;
|
|
1631
1718
|
setToolManager(toolManager, toolContext) {
|
|
1632
1719
|
this.toolManager = toolManager;
|
|
1633
1720
|
this.toolContext = toolContext;
|
|
@@ -1639,6 +1726,7 @@ var InputHandler = class {
|
|
|
1639
1726
|
return this.keyboard.shortcuts;
|
|
1640
1727
|
}
|
|
1641
1728
|
destroy() {
|
|
1729
|
+
this.panInertia.cancel();
|
|
1642
1730
|
this.actions.dispose();
|
|
1643
1731
|
this.abortController.abort();
|
|
1644
1732
|
this.inputFilter.reset();
|
|
@@ -1662,6 +1750,7 @@ var InputHandler = class {
|
|
|
1662
1750
|
}
|
|
1663
1751
|
onWheel = (e) => {
|
|
1664
1752
|
e.preventDefault();
|
|
1753
|
+
this.panInertia.cancel();
|
|
1665
1754
|
const rect = this.element.getBoundingClientRect();
|
|
1666
1755
|
const zoomFactor = 1 - e.deltaY * ZOOM_SENSITIVITY;
|
|
1667
1756
|
const newZoom = this.camera.zoom * zoomFactor;
|
|
@@ -1671,6 +1760,7 @@ var InputHandler = class {
|
|
|
1671
1760
|
});
|
|
1672
1761
|
};
|
|
1673
1762
|
onPointerDown = (e) => {
|
|
1763
|
+
this.panInertia.cancel();
|
|
1674
1764
|
this.focusSelf();
|
|
1675
1765
|
this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
1676
1766
|
this.element.setPointerCapture?.(e.pointerId);
|
|
@@ -1711,6 +1801,7 @@ var InputHandler = class {
|
|
|
1711
1801
|
const dy = e.clientY - this.lastPointer.y;
|
|
1712
1802
|
this.lastPointer = { x: e.clientX, y: e.clientY };
|
|
1713
1803
|
this.camera.pan(dx, dy);
|
|
1804
|
+
this.panInertia.sample(dx, dy);
|
|
1714
1805
|
return;
|
|
1715
1806
|
}
|
|
1716
1807
|
if (e.pointerType === "pen" && !this.activePointers.has(e.pointerId)) {
|
|
@@ -1741,6 +1832,7 @@ var InputHandler = class {
|
|
|
1741
1832
|
}
|
|
1742
1833
|
if (this.isPanning && this.activePointers.size === 0) {
|
|
1743
1834
|
this.isPanning = false;
|
|
1835
|
+
this.panInertia.release();
|
|
1744
1836
|
}
|
|
1745
1837
|
const upResult = this.inputFilter.filterUp(e);
|
|
1746
1838
|
if (this.isToolActive) {
|
|
@@ -1761,6 +1853,7 @@ var InputHandler = class {
|
|
|
1761
1853
|
return this.actions.hasClipboard();
|
|
1762
1854
|
}
|
|
1763
1855
|
startPinch() {
|
|
1856
|
+
this.panInertia.cancel();
|
|
1764
1857
|
this.cancelLongPress();
|
|
1765
1858
|
this.inputFilter.reset();
|
|
1766
1859
|
this.deferredDown = null;
|
|
@@ -1782,6 +1875,7 @@ var InputHandler = class {
|
|
|
1782
1875
|
const dx = center2.x - this.lastPointer.x;
|
|
1783
1876
|
const dy = center2.y - this.lastPointer.y;
|
|
1784
1877
|
this.camera.pan(dx, dy);
|
|
1878
|
+
this.panInertia.sample(dx, dy);
|
|
1785
1879
|
this.lastPinchDistance = dist;
|
|
1786
1880
|
this.lastPinchCenter = center2;
|
|
1787
1881
|
this.lastPointer = { ...center2 };
|
|
@@ -2753,6 +2847,16 @@ function updateBoundArrow(arrow, store) {
|
|
|
2753
2847
|
var ARROWHEAD_LENGTH = 12;
|
|
2754
2848
|
var ARROWHEAD_ANGLE = Math.PI / 6;
|
|
2755
2849
|
var ARROW_LABEL_FONT_SIZE = 14;
|
|
2850
|
+
function getArrowDashPattern(strokeStyle) {
|
|
2851
|
+
switch (strokeStyle) {
|
|
2852
|
+
case "dashed":
|
|
2853
|
+
return [8, 4];
|
|
2854
|
+
case "dotted":
|
|
2855
|
+
return [2, 4];
|
|
2856
|
+
default:
|
|
2857
|
+
return [];
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2756
2860
|
function renderArrow(ctx, arrow, store, labelEditingId) {
|
|
2757
2861
|
const geometry = getArrowRenderGeometry(arrow);
|
|
2758
2862
|
const { visualFrom, visualTo } = getVisualEndpoints(arrow, geometry, store);
|
|
@@ -2760,9 +2864,8 @@ function renderArrow(ctx, arrow, store, labelEditingId) {
|
|
|
2760
2864
|
ctx.strokeStyle = arrow.color;
|
|
2761
2865
|
ctx.lineWidth = arrow.width;
|
|
2762
2866
|
ctx.lineCap = "round";
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
}
|
|
2867
|
+
const dash = getArrowDashPattern(arrow.strokeStyle);
|
|
2868
|
+
if (dash.length > 0) ctx.setLineDash(dash);
|
|
2766
2869
|
ctx.beginPath();
|
|
2767
2870
|
ctx.moveTo(visualFrom.x, visualFrom.y);
|
|
2768
2871
|
if (arrow.bend !== 0) {
|
|
@@ -3682,6 +3785,7 @@ function createArrow(input) {
|
|
|
3682
3785
|
if (input.fromBinding) result.fromBinding = input.fromBinding;
|
|
3683
3786
|
if (input.toBinding) result.toBinding = input.toBinding;
|
|
3684
3787
|
if (input.label !== void 0) result.label = input.label;
|
|
3788
|
+
if (input.strokeStyle !== void 0) result.strokeStyle = input.strokeStyle;
|
|
3685
3789
|
return result;
|
|
3686
3790
|
}
|
|
3687
3791
|
function createImage(input) {
|
|
@@ -5085,7 +5189,8 @@ function emitArrow(arrow, store) {
|
|
|
5085
5189
|
} else {
|
|
5086
5190
|
d = `M${n(from.x)} ${n(from.y)} L${n(to.x)} ${n(to.y)}`;
|
|
5087
5191
|
}
|
|
5088
|
-
const
|
|
5192
|
+
const pattern = getArrowDashPattern(arrow.strokeStyle);
|
|
5193
|
+
const dash = pattern.length > 0 ? ` stroke-dasharray="${pattern.join(" ")}"` : "";
|
|
5089
5194
|
let out = `<path d="${d}" fill="none" stroke="${esc(arrow.color)}" stroke-width="${n(arrow.width)}" stroke-linecap="round"${dash} />`;
|
|
5090
5195
|
const angle = geometry.tangentEnd;
|
|
5091
5196
|
const p1x = to.x - ARROWHEAD_LENGTH2 * Math.cos(angle - ARROWHEAD_ANGLE2);
|
|
@@ -6289,7 +6394,7 @@ function translateElementPatch(el, dx, dy) {
|
|
|
6289
6394
|
|
|
6290
6395
|
// src/elements/element-style.ts
|
|
6291
6396
|
function styleToPatch(element, style) {
|
|
6292
|
-
const { color, fillColor, strokeWidth, opacity, fontSize } = style;
|
|
6397
|
+
const { color, fillColor, strokeWidth, opacity, fontSize, strokeStyle } = style;
|
|
6293
6398
|
switch (element.type) {
|
|
6294
6399
|
case "stroke":
|
|
6295
6400
|
return {
|
|
@@ -6300,7 +6405,8 @@ function styleToPatch(element, style) {
|
|
|
6300
6405
|
case "arrow":
|
|
6301
6406
|
return {
|
|
6302
6407
|
...color !== void 0 ? { color } : {},
|
|
6303
|
-
...strokeWidth !== void 0 ? { width: strokeWidth } : {}
|
|
6408
|
+
...strokeWidth !== void 0 ? { width: strokeWidth } : {},
|
|
6409
|
+
...strokeStyle !== void 0 ? { strokeStyle } : {}
|
|
6304
6410
|
};
|
|
6305
6411
|
case "shape":
|
|
6306
6412
|
return {
|
|
@@ -6341,7 +6447,11 @@ function getElementStyle(element) {
|
|
|
6341
6447
|
case "stroke":
|
|
6342
6448
|
return { color: element.color, strokeWidth: element.width, opacity: element.opacity };
|
|
6343
6449
|
case "arrow":
|
|
6344
|
-
return {
|
|
6450
|
+
return {
|
|
6451
|
+
color: element.color,
|
|
6452
|
+
strokeWidth: element.width,
|
|
6453
|
+
...element.strokeStyle !== void 0 ? { strokeStyle: element.strokeStyle } : {}
|
|
6454
|
+
};
|
|
6345
6455
|
case "shape":
|
|
6346
6456
|
return {
|
|
6347
6457
|
color: element.strokeColor,
|
|
@@ -6415,6 +6525,8 @@ var SelectionOps = class {
|
|
|
6415
6525
|
if (opacity !== void 0) result.opacity = opacity;
|
|
6416
6526
|
const fontSize = sharedValue(styles.map((s) => s.fontSize));
|
|
6417
6527
|
if (fontSize !== void 0) result.fontSize = fontSize;
|
|
6528
|
+
const strokeStyle = sharedValue(styles.map((s) => s.strokeStyle));
|
|
6529
|
+
if (strokeStyle !== void 0) result.strokeStyle = strokeStyle;
|
|
6418
6530
|
return result;
|
|
6419
6531
|
}
|
|
6420
6532
|
applyStyle(style) {
|
|
@@ -6865,7 +6977,8 @@ var Viewport = class {
|
|
|
6865
6977
|
shortcuts: options.shortcuts,
|
|
6866
6978
|
addImage: (src, world) => this.addImage(src, world),
|
|
6867
6979
|
getCenteredWorld: () => this.centeredPosition({ w: 300, h: 200 }),
|
|
6868
|
-
onPaste: options.onPaste
|
|
6980
|
+
onPaste: options.onPaste,
|
|
6981
|
+
panInertia: options.panInertia
|
|
6869
6982
|
});
|
|
6870
6983
|
if (options.contextMenu !== false) {
|
|
6871
6984
|
this.contextMenu = new ContextMenu({
|
|
@@ -8832,6 +8945,7 @@ var ArrowTool = class {
|
|
|
8832
8945
|
end = { x: 0, y: 0 };
|
|
8833
8946
|
color;
|
|
8834
8947
|
width;
|
|
8948
|
+
strokeStyle;
|
|
8835
8949
|
fromBinding;
|
|
8836
8950
|
fromTarget = null;
|
|
8837
8951
|
toTarget = null;
|
|
@@ -8839,9 +8953,10 @@ var ArrowTool = class {
|
|
|
8839
8953
|
constructor(options = {}) {
|
|
8840
8954
|
this.color = options.color ?? "#000000";
|
|
8841
8955
|
this.width = options.width ?? 2;
|
|
8956
|
+
this.strokeStyle = options.strokeStyle ?? "solid";
|
|
8842
8957
|
}
|
|
8843
8958
|
getOptions() {
|
|
8844
|
-
return { color: this.color, width: this.width };
|
|
8959
|
+
return { color: this.color, width: this.width, strokeStyle: this.strokeStyle };
|
|
8845
8960
|
}
|
|
8846
8961
|
onOptionsChange(listener) {
|
|
8847
8962
|
this.optionListeners.add(listener);
|
|
@@ -8850,6 +8965,7 @@ var ArrowTool = class {
|
|
|
8850
8965
|
setOptions(options) {
|
|
8851
8966
|
if (options.color !== void 0) this.color = options.color;
|
|
8852
8967
|
if (options.width !== void 0) this.width = options.width;
|
|
8968
|
+
if (options.strokeStyle !== void 0) this.strokeStyle = options.strokeStyle;
|
|
8853
8969
|
this.notifyOptionsChange();
|
|
8854
8970
|
}
|
|
8855
8971
|
notifyOptionsChange() {
|
|
@@ -8909,6 +9025,7 @@ var ArrowTool = class {
|
|
|
8909
9025
|
position: this.start,
|
|
8910
9026
|
color: this.color,
|
|
8911
9027
|
width: this.width,
|
|
9028
|
+
strokeStyle: this.strokeStyle,
|
|
8912
9029
|
fromBinding: this.fromBinding,
|
|
8913
9030
|
toBinding: this.toTarget ? { elementId: this.toTarget.id } : void 0,
|
|
8914
9031
|
layerId: ctx.activeLayerId ?? ""
|
|
@@ -9776,7 +9893,7 @@ var LaserTool = class {
|
|
|
9776
9893
|
};
|
|
9777
9894
|
|
|
9778
9895
|
// src/index.ts
|
|
9779
|
-
var VERSION = "0.
|
|
9896
|
+
var VERSION = "0.42.0";
|
|
9780
9897
|
// Annotate the CommonJS export names for ESM import in node:
|
|
9781
9898
|
0 && (module.exports = {
|
|
9782
9899
|
ArrowTool,
|