@weasel-js/core 1.8.1 → 1.9.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/CHANGELOG.md +49 -0
- package/README.md +9 -5
- package/dist/{builtins-CMEh6-Oc.d.ts → builtins-CQcvcLXh.d.ts} +98 -31
- package/dist/canvas/DrawCanvas.js +33 -33
- package/dist/canvas/DrawCanvas.js.map +1 -1
- package/dist/canvas/MinimapCanvas.js +29 -29
- package/dist/canvas/MinimapCanvas.js.map +1 -1
- package/dist/canvas/NodeShape.js +63 -54
- package/dist/canvas/NodeShape.js.map +1 -1
- package/dist/canvas/SceneCanvas/features.js +26 -5
- package/dist/canvas/SceneCanvas/features.js.map +1 -1
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js +3 -2
- package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
- package/dist/canvas/SceneCanvas.js +526 -529
- package/dist/canvas/SceneCanvas.js.map +1 -1
- package/dist/canvas/SceneViewCanvas.js +35 -35
- package/dist/canvas/SceneViewCanvas.js.map +1 -1
- package/dist/canvas/defaultDrawOne.js +6 -1
- package/dist/canvas/defaultDrawOne.js.map +1 -1
- package/dist/canvas/pickWalk.js.map +1 -1
- package/dist/canvas/sceneAdapter.js.map +1 -1
- package/dist/canvas/useHitObserver.js +23 -0
- package/dist/canvas/useHitObserver.js.map +1 -0
- package/dist/canvas/useHostAnchor.js.map +1 -1
- package/dist/core/device/useDeviceProfile.js.map +1 -1
- package/dist/core/scene/derivedPath.js.map +1 -1
- package/dist/core/scene/effectivePose.js.map +1 -1
- package/dist/core/scene/kitRegistry.js.map +1 -1
- package/dist/core/scene/scene.js.map +1 -1
- package/dist/core/scene/types.js.map +1 -1
- package/dist/core/scene/useScene.js.map +1 -1
- package/dist/core/viewport/fitViewToBounds.js +3 -3
- package/dist/core/viewport/fitViewToBounds.js.map +1 -1
- package/dist/core/viewport/screenSlop.js +8 -2
- package/dist/core/viewport/screenSlop.js.map +1 -1
- package/dist/features/minimap/actions.js.map +1 -1
- package/dist/features/paths/markerCommands.js +95 -63
- package/dist/features/paths/markerCommands.js.map +1 -1
- package/dist/features/paths/tessellate/dash.js +52 -0
- package/dist/features/paths/tessellate/dash.js.map +1 -0
- package/dist/features/paths/tessellate/insets.js +32 -0
- package/dist/features/paths/tessellate/insets.js.map +1 -0
- package/dist/features/paths/tessellate/metric.js +72 -0
- package/dist/features/paths/tessellate/metric.js.map +1 -0
- package/dist/features/paths/tessellate/stroke.js +74 -134
- package/dist/features/paths/tessellate/stroke.js.map +1 -1
- package/dist/features/paths/tessellate/vertexWidths.js +32 -0
- package/dist/features/paths/tessellate/vertexWidths.js.map +1 -0
- package/dist/features/pointer/PointerContext.js +2 -2
- package/dist/features/pointer/PointerContext.js.map +1 -1
- package/dist/features/poseRun/usePoseRun.js.map +1 -1
- package/dist/features/text/useTextEdit.js +86 -84
- package/dist/features/text/useTextEdit.js.map +1 -1
- package/dist/index.d.ts +78 -39
- package/dist/index.js +148 -148
- package/dist/interactions/actions/defaults/align.js.map +1 -1
- package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
- package/dist/interactions/actions/defaults/areaSelect.js.map +1 -1
- package/dist/interactions/actions/defaults/booleans.js.map +1 -1
- package/dist/interactions/actions/defaults/cancelGesture.js.map +1 -1
- package/dist/interactions/actions/defaults/clearSelection.js.map +1 -1
- package/dist/interactions/actions/defaults/clipboard.js.map +1 -1
- package/dist/interactions/actions/defaults/clone.js.map +1 -1
- package/dist/interactions/actions/defaults/createOutlines.js +1 -1
- package/dist/interactions/actions/defaults/createOutlines.js.map +1 -1
- package/dist/interactions/actions/defaults/createPaintAction.js.map +1 -1
- package/dist/interactions/actions/defaults/delete.js.map +1 -1
- package/dist/interactions/actions/defaults/distribute.js.map +1 -1
- package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
- package/dist/interactions/actions/defaults/editAnchors.js.map +1 -1
- package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/escape.js +1 -1
- package/dist/interactions/actions/defaults/escape.js.map +1 -1
- package/dist/interactions/actions/defaults/exitPathEdit.js.map +1 -1
- package/dist/interactions/actions/defaults/flip.js.map +1 -1
- package/dist/interactions/actions/defaults/group.js.map +1 -1
- package/dist/interactions/actions/defaults/ingest.js.map +1 -1
- package/dist/interactions/actions/defaults/insert.js.map +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js +1 -1
- package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
- package/dist/interactions/actions/defaults/lassoSelect.js.map +1 -1
- package/dist/interactions/actions/defaults/move.js.map +1 -1
- package/dist/interactions/actions/defaults/nudge.js.map +1 -1
- package/dist/interactions/actions/defaults/pinchZoom.js.map +1 -1
- package/dist/interactions/actions/defaults/reorder.js.map +1 -1
- package/dist/interactions/actions/defaults/requiresSelection.js.map +1 -1
- package/dist/interactions/actions/defaults/resize.js.map +1 -1
- package/dist/interactions/actions/defaults/rotate.js.map +1 -1
- package/dist/interactions/actions/defaults/selectAll.js.map +1 -1
- package/dist/interactions/actions/defaults/slice.js.map +1 -1
- package/dist/interactions/actions/defaults/toolActivate.js.map +1 -1
- package/dist/interactions/actions/defaults/toolResetToDefault.js.map +1 -1
- package/dist/interactions/actions/defaults/undoRedo.js +1 -1
- package/dist/interactions/actions/defaults/undoRedo.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportDragPan.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportWheelPan.js.map +1 -1
- package/dist/interactions/actions/defaults/viewportZoom.js.map +1 -1
- package/dist/interactions/actions/planeInput.js.map +1 -1
- package/dist/interactions/gestures/shared/screenTolerance.js.map +1 -1
- package/dist/{registerProgram-ateHDGjw.d.ts → registerProgram-BMZRDgrh.d.ts} +4 -0
- package/dist/renderer/cache/markerCommandCache.js +46 -42
- package/dist/renderer/cache/markerCommandCache.js.map +1 -1
- package/dist/renderer/cache/outlineStrokeMeshCache.js +30 -25
- package/dist/renderer/cache/outlineStrokeMeshCache.js.map +1 -1
- package/dist/renderer/cache/strokeMeshCache.js +42 -31
- package/dist/renderer/cache/strokeMeshCache.js.map +1 -1
- package/dist/renderer/cullDrawCommands.js +32 -31
- package/dist/renderer/cullDrawCommands.js.map +1 -1
- package/dist/renderer/draw.js +315 -362
- package/dist/renderer/draw.js.map +1 -1
- package/dist/renderer/glyphOutlineMesh.js +67 -0
- package/dist/renderer/glyphOutlineMesh.js.map +1 -0
- package/dist/renderer/math/mat3.js +8 -3
- package/dist/renderer/math/mat3.js.map +1 -1
- package/dist/renderer/strokeLengths.js +50 -0
- package/dist/renderer/strokeLengths.js.map +1 -0
- package/dist/renderer.d.ts +2 -2
- package/dist/{test-seams-fYf6m5pu.d.ts → test-seams-CuIxe0xY.d.ts} +1 -1
- package/dist/test-seams.d.ts +2 -2
- package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
- package/dist/tools/builtin/pen/usePenTool.js +1 -1
- package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
- package/dist/tools/builtin/select/selectionContributions.js +43 -23
- package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
- package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
- package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +17 -17
|
@@ -3,13 +3,13 @@ import { AUTO_POSE_DESCRIPTOR as t } from "../interactions/actions/resize/autoPo
|
|
|
3
3
|
import { usePointerContext as n, usePointerPosition as r } from "../features/pointer/PointerContext.js";
|
|
4
4
|
import { PointerProviderIfRoot as i } from "./SceneCanvas/PointerProviderIfRoot.js";
|
|
5
5
|
import { accentColorOf as a } from "./accentColor.js";
|
|
6
|
-
import { SceneViewCanvas as
|
|
7
|
-
import { MINIMAP_CENTER as
|
|
8
|
-
import { createLinkedCursorLayer as
|
|
9
|
-
import { computeFitView as
|
|
10
|
-
import { useCallback as
|
|
11
|
-
import { useLatest as v } from "@weasel-js/react";
|
|
12
|
-
import { ActionsProvider as y, ActiveToolContextProvider as b, DepRegistryProvider as x, useActionsRegistry as S, useDepSource as C, useGestureDispatcher as
|
|
6
|
+
import { SceneViewCanvas as o } from "./SceneViewCanvas.js";
|
|
7
|
+
import { MINIMAP_CENTER as s, MINIMAP_PAN as c, minimapCenterAction as l, minimapPanAction as u } from "../features/minimap/actions.js";
|
|
8
|
+
import { createLinkedCursorLayer as d } from "../features/minimap/layers.js";
|
|
9
|
+
import { computeFitView as f, computeIndicatorCommand as p } from "./minimapMath.js";
|
|
10
|
+
import { useCallback as m, useEffect as h, useMemo as g, useRef as ee, useSyncExternalStore as te } from "react";
|
|
11
|
+
import { assignRef as _, useLatest as v } from "@weasel-js/react";
|
|
12
|
+
import { ActionsProvider as y, ActiveToolContextProvider as b, DepRegistryProvider as x, useActionsRegistry as S, useDepSource as C, useGestureDispatcher as ne } from "@weasel-js/routing/react";
|
|
13
13
|
import { jsx as w } from "react/jsx-runtime";
|
|
14
14
|
//#region src/canvas/MinimapCanvas.tsx
|
|
15
15
|
var T = {
|
|
@@ -17,10 +17,10 @@ var T = {
|
|
|
17
17
|
eligibility: { always: !0 },
|
|
18
18
|
bindings: [{
|
|
19
19
|
spec: { kind: "pointerDown" },
|
|
20
|
-
actionId:
|
|
20
|
+
actionId: s
|
|
21
21
|
}, {
|
|
22
22
|
spec: { kind: "drag" },
|
|
23
|
-
actionId:
|
|
23
|
+
actionId: c
|
|
24
24
|
}]
|
|
25
25
|
}, E = /* @__PURE__ */ new Map([[T.id, T]]), D = {
|
|
26
26
|
wheel: !1,
|
|
@@ -29,21 +29,21 @@ var T = {
|
|
|
29
29
|
ingest: !1
|
|
30
30
|
};
|
|
31
31
|
function O(i) {
|
|
32
|
-
let { scene:
|
|
32
|
+
let { scene: s, mainView: c, mainViewDims: y, onMainViewChange: b, width: x, height: T, drawOne: O, alphaFor: k, layerVisibility: A, layerOrder: j, animator: M, fit: N = "scene", poseDescriptor: re, indicatorStyle: P, className: F, canvasRef: I, id: L = "minimap" } = i, R = e(c), z = te(s.subscribe, s.getVersion, s.getVersion), B = re ?? t, V = g(() => f(s, {
|
|
33
33
|
width: x,
|
|
34
34
|
height: T
|
|
35
|
-
},
|
|
36
|
-
|
|
35
|
+
}, N, B), [
|
|
36
|
+
s,
|
|
37
37
|
z,
|
|
38
38
|
x,
|
|
39
39
|
T,
|
|
40
|
-
|
|
40
|
+
N,
|
|
41
41
|
B
|
|
42
|
-
]), H =
|
|
42
|
+
]), H = g(() => p(R, y, P), [
|
|
43
43
|
R,
|
|
44
44
|
y,
|
|
45
45
|
P
|
|
46
|
-
]), U =
|
|
46
|
+
]), U = ee(null), W = v(R), G = v(y), K = v(b), q = v(V), J = g(() => ({
|
|
47
47
|
get: () => W.current,
|
|
48
48
|
set: (e) => K.current(e),
|
|
49
49
|
hostSize: () => G.current
|
|
@@ -54,21 +54,21 @@ function O(i) {
|
|
|
54
54
|
]);
|
|
55
55
|
C("rootView", () => J);
|
|
56
56
|
let Y = S();
|
|
57
|
-
|
|
57
|
+
h(() => {
|
|
58
58
|
if (!Y) return;
|
|
59
|
-
let e = [Y.register(
|
|
59
|
+
let e = [Y.register(l()), Y.register(u())];
|
|
60
60
|
return () => {
|
|
61
61
|
for (let t of e) t();
|
|
62
62
|
};
|
|
63
63
|
}, [Y]);
|
|
64
|
-
let X =
|
|
64
|
+
let X = m((e, t) => {
|
|
65
65
|
let n = U.current?.getBoundingClientRect(), r = q.current;
|
|
66
66
|
return {
|
|
67
67
|
x: r.x + (e - (n?.left ?? 0)) / r.scale.x,
|
|
68
68
|
y: r.y + (t - (n?.top ?? 0)) / r.scale.y
|
|
69
69
|
};
|
|
70
70
|
}, [q]);
|
|
71
|
-
|
|
71
|
+
ne({
|
|
72
72
|
canvasRef: U,
|
|
73
73
|
actions: Y,
|
|
74
74
|
entriesById: E,
|
|
@@ -77,7 +77,7 @@ function O(i) {
|
|
|
77
77
|
channels: D
|
|
78
78
|
});
|
|
79
79
|
let Z = n();
|
|
80
|
-
|
|
80
|
+
h(() => {
|
|
81
81
|
let e = U.current;
|
|
82
82
|
if (!e || !Z) return;
|
|
83
83
|
let t = (e) => {
|
|
@@ -98,11 +98,11 @@ function O(i) {
|
|
|
98
98
|
X,
|
|
99
99
|
L
|
|
100
100
|
]);
|
|
101
|
-
let Q = r(), $ =
|
|
101
|
+
let Q = r(), $ = g(() => d({
|
|
102
102
|
id: `${L}.cursor`,
|
|
103
103
|
pointer: () => Q,
|
|
104
104
|
color: () => a(U.current)
|
|
105
|
-
}), [L, Q]),
|
|
105
|
+
}), [L, Q]), ie = g(() => [H, ...$.draw({ viewId: L }, V, {
|
|
106
106
|
width: x,
|
|
107
107
|
height: T
|
|
108
108
|
})], [
|
|
@@ -112,22 +112,22 @@ function O(i) {
|
|
|
112
112
|
V,
|
|
113
113
|
x,
|
|
114
114
|
T
|
|
115
|
-
]),
|
|
116
|
-
U.current = e,
|
|
115
|
+
]), ae = m((e) => {
|
|
116
|
+
U.current = e, _(I, e);
|
|
117
117
|
}, [I]);
|
|
118
|
-
return /* @__PURE__ */ w(
|
|
119
|
-
scene:
|
|
118
|
+
return /* @__PURE__ */ w(o, {
|
|
119
|
+
scene: s,
|
|
120
120
|
view: V,
|
|
121
121
|
width: x,
|
|
122
122
|
height: T,
|
|
123
123
|
drawOne: O,
|
|
124
|
-
extraCommands:
|
|
124
|
+
extraCommands: ie,
|
|
125
125
|
alphaFor: k,
|
|
126
126
|
layerVisibility: A,
|
|
127
127
|
layerOrder: j,
|
|
128
|
-
animator:
|
|
128
|
+
animator: M,
|
|
129
129
|
className: F,
|
|
130
|
-
canvasRef:
|
|
130
|
+
canvasRef: ae
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
133
|
function k(e) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MinimapCanvas.js","names":["MINIMAP_INPUT","MINIMAP_CENTER","MINIMAP_PAN","TOOLS_BY_ID","CHANNELS","MinimapCanvasInner","mainViewProp","props","mainView","normalizeView","sceneVersion","useSyncExternalStore","scene","descriptor","poseDescriptor","AUTO_POSE_DESCRIPTOR","fitView","useMemo","computeFitView","fit","width","height","indicatorCmd","computeIndicatorCommand","mainViewDims","indicatorStyle","localCanvasRef","useRef","mainViewRef","useLatest","mainViewDimsRef","onMainViewChangeRef","onMainViewChange","fitViewRef","rootView","v","actions","useActionsRegistry","off","minimapCenterAction","minimapPanAction","u","clientToWorld","useCallback","rect","fv","cx","cy","pointerStore","usePointerContext","el","onMove","w","id","onLeave","pointer","usePointerPosition","cursorLayer","createLinkedCursorLayer","accentColorOf","extraCommands","setCanvasRef","canvasRef","SceneViewCanvas","MinimapCanvas","DepRegistryProvider","ActionsProvider","ActiveToolContextProvider","PointerProviderIfRoot"],"sources":["../../src/canvas/MinimapCanvas.tsx"],"sourcesContent":["/**\n * `<MinimapCanvas>` — opinionated minimap on a canvas of its own, built on\n * `<SceneViewCanvas>`.\n *\n * Renders the same `scene` the main canvas is showing, through a derived\n * \"fit\" view, and overlays a dashed visible-window indicator showing where\n * the main canvas is currently looking. Press anywhere in the minimap to\n * recenter the main view on that world point; drag to pan continuously.\n *\n * Input runs on a dispatcher of its own, through the same `minimap.center` /\n * `minimap.pan` actions the in-surface minimap (`createMinimapContribution`)\n * binds. It publishes its pointer into the pointer store in scope, and draws a\n * crosshair wherever that store says the pointer is on another surface — put\n * one `<PointerContextProvider>` around it and the main canvas for linked\n * cursors both ways.\n */\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport type { Ref } from 'react';\nimport {\n ActionsProvider,\n ActiveToolContextProvider,\n DepRegistryProvider,\n useActionsRegistry,\n useDepSource,\n useGestureDispatcher,\n} from '@weasel-js/routing/react';\nimport { useLatest } from '@weasel-js/react';\nimport type { Tool } from '@weasel-js/routing';\nimport { PointerProviderIfRoot } from './SceneCanvas/PointerProviderIfRoot';\nimport { usePointerContext, usePointerPosition } from 'features/pointer/PointerContext';\nimport {\n MINIMAP_CENTER, MINIMAP_PAN, minimapCenterAction, minimapPanAction,\n} from 'features/minimap/actions';\nimport { createLinkedCursorLayer } from 'features/minimap/layers';\nimport type { ViewApi } from 'interactions/actions/depSchema';\nimport { SceneViewCanvas } from './SceneViewCanvas';\nimport {\n computeFitView,\n computeIndicatorCommand,\n} from './minimapMath';\nimport type { IndicatorStyle, MinimapFit } from './minimapMath';\nimport type { SceneViewDrawOne, SceneViewLayers } from './sceneViewRender';\nimport type { DrawCommand } from '../renderer/DrawCommand';\nimport { normalizeView, type View } from '../core/viewport/view';\nimport type { Scene } from '../core/scene/types';\nimport type { PoseDescriptor } from '../core/geometry/poseDescriptor';\nimport type { Animator } from '../animation/types';\nimport { AUTO_POSE_DESCRIPTOR } from '../interactions/actions/resize/autoPoseDescriptor';\nimport { accentColorOf } from './accentColor';\n\n/** Props for `<MinimapCanvas>`. */\nexport interface MinimapCanvasProps<TData, TLayer extends string, TPose> {\n /** Same scene the main canvas is rendering. */\n scene: Scene<TData, TLayer, TPose>;\n /** Main canvas's view — used to position the visible-window indicator and\n * to preserve `scale` when the minimap recenters. */\n mainView: View;\n /** Main canvas's CSS-pixel dims. Used to compute the visible-window rect\n * and the recenter offset. */\n mainViewDims: { width: number; height: number };\n /** Setter called on click (single recenter) and during drag (continuous\n * recenter). Receives a `View` with the same `scale` as `mainView` and\n * `(x, y)` shifted so the pointer's world point lands at the main\n * canvas's center. */\n onMainViewChange: (next: View) => void;\n /** Minimap's own CSS-pixel dims. */\n width: number;\n height: number;\n /** Consumer's draw callback. Applied through the derived fit view; same\n * signature as `<SceneCanvas>`'s scene-slot `drawOne` so the consumer\n * can reuse it (typically simplified — just colored AABBs). */\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Fit policy. Defaults to `\"scene\"` (AABB union of leaf poses). See\n * `MinimapFit` for the full shape.\n *\n * Framing is derived from **document** poses, not `scene.overrides` — a\n * node moved by an override paints where the override puts it, outside the\n * frame if it goes there, rather than making the whole minimap rescale on\n * every frame of a drag or a settle. */\n fit?: MinimapFit<TData, TLayer, TPose>;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Pass the same function the main canvas uses so a\n * scoping-dim treatment shows up in the minimap too. */\n alphaFor?: (id: string) => number;\n /** Hide scene layers in the minimap, keyed `scene:<layerId>` as on\n * `<SceneCanvas>` — pass the main canvas's map so both show the same set. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Paint order for the minimap, keyed as `layerVisibility`. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Optional animator: the minimap repaints on its ticks and paints its\n * `colorOverrides`. Pass the main canvas's animator so both show the same\n * colors. */\n animator?: Animator;\n /** Visual tuning of the indicator stroke. */\n indicatorStyle?: IndicatorStyle;\n /** CSS class for sizing / positioning the canvas. */\n className?: string;\n /** Forwarded ref to the underlying `<canvas>`. */\n canvasRef?: Ref<HTMLCanvasElement>;\n /** The view id this minimap publishes its pointer under. Default\n * `'minimap'`. */\n id?: string;\n}\n\n/** The minimap's own bindings. Unscoped: this dispatcher routes no views, so\n * every input on it is the minimap's. */\nconst MINIMAP_INPUT: Tool = {\n id: 'minimap',\n eligibility: { always: true },\n bindings: [\n { spec: { kind: 'pointerDown' }, actionId: MINIMAP_CENTER },\n { spec: { kind: 'drag' }, actionId: MINIMAP_PAN },\n ],\n};\nconst TOOLS_BY_ID: ReadonlyMap<string, Tool> = new Map([[MINIMAP_INPUT.id, MINIMAP_INPUT]]);\nconst CHANNELS = { wheel: false, pinch: false, contextMenu: false, ingest: false } as const;\n\nfunction MinimapCanvasInner<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n const {\n scene,\n mainView: mainViewProp,\n mainViewDims,\n onMainViewChange,\n width,\n height,\n drawOne,\n alphaFor,\n layerVisibility,\n layerOrder,\n animator,\n fit = 'scene',\n poseDescriptor,\n indicatorStyle,\n className,\n canvasRef,\n id = 'minimap',\n } = props;\n const mainView = normalizeView(mainViewProp);\n\n // Subscribe to scene version so the fit view recomputes when the scene\n // mutates. `<SceneViewCanvas>` also subscribes, but it owns its own\n // rendering; we need the version *here* to invalidate the memoized fit.\n const sceneVersion = useSyncExternalStore(\n scene.subscribe,\n scene.getVersion,\n scene.getVersion,\n );\n\n const descriptor = (poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n\n const fitView = useMemo<View>(() => {\n return computeFitView(scene, { width, height }, fit, descriptor);\n // `sceneVersion` participates so the memo re-evaluates after scene mutations.\n // `descriptor` is stable when the prop is omitted.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scene, sceneVersion, width, height, fit, descriptor]);\n\n const indicatorCmd = useMemo<DrawCommand>(() => {\n return computeIndicatorCommand(mainView, mainViewDims, indicatorStyle);\n }, [mainView, mainViewDims, indicatorStyle]);\n\n // -------------------------------------------------------------------------\n // Input\n // -------------------------------------------------------------------------\n //\n // The \"latest\" pattern (refs holding the current mainView / dims / setter\n // / fitView) lets the dep and the listeners read up-to-date values without\n // re-binding every frame.\n\n const localCanvasRef = useRef<HTMLCanvasElement | null>(null);\n const mainViewRef = useLatest(mainView);\n const mainViewDimsRef = useLatest(mainViewDims);\n const onMainViewChangeRef = useLatest(onMainViewChange);\n const fitViewRef = useLatest(fitView);\n\n // The main canvas's camera, which is what the minimap's actions move.\n const rootView = useMemo<ViewApi>(() => ({\n get: () => mainViewRef.current,\n set: (v) => onMainViewChangeRef.current(v),\n hostSize: () => mainViewDimsRef.current,\n }), [mainViewRef, onMainViewChangeRef, mainViewDimsRef]);\n useDepSource('rootView', () => rootView);\n\n const actions = useActionsRegistry();\n useEffect(() => {\n if (!actions) return;\n const off = [actions.register(minimapCenterAction()), actions.register(minimapPanAction())];\n return () => { for (const u of off) u(); };\n }, [actions]);\n\n /** Client point → world, through the fit camera. */\n const clientToWorld = useCallback((cx: number, cy: number) => {\n const rect = localCanvasRef.current?.getBoundingClientRect();\n const fv = fitViewRef.current;\n return {\n x: fv.x + (cx - (rect?.left ?? 0)) / fv.scale.x,\n y: fv.y + (cy - (rect?.top ?? 0)) / fv.scale.y,\n };\n }, [fitViewRef]);\n\n useGestureDispatcher({\n canvasRef: localCanvasRef,\n actions: actions!,\n entriesById: TOOLS_BY_ID,\n clientToWorld,\n keyboard: false,\n channels: CHANNELS,\n });\n\n // -------------------------------------------------------------------------\n // Linked cursor\n // -------------------------------------------------------------------------\n\n const pointerStore = usePointerContext();\n useEffect(() => {\n const el = localCanvasRef.current;\n if (!el || !pointerStore) return;\n const onMove = (e: PointerEvent): void => {\n const w = clientToWorld(e.clientX, e.clientY);\n pointerStore.set({ worldX: w.x, worldY: w.y, viewId: id });\n };\n const onLeave = (e: PointerEvent): void => {\n if (e.buttons !== 0) return;\n if (pointerStore.get()?.viewId === id) pointerStore.set(null);\n };\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerleave', onLeave);\n return () => {\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerleave', onLeave);\n };\n }, [pointerStore, clientToWorld, id]);\n\n const pointer = usePointerPosition();\n const cursorLayer = useMemo(() => createLinkedCursorLayer({\n id: `${id}.cursor`,\n pointer: () => pointer,\n color: () => accentColorOf(localCanvasRef.current),\n }), [id, pointer]);\n\n const extraCommands = useMemo<DrawCommand[]>(() => [\n indicatorCmd,\n ...cursorLayer.draw({ viewId: id }, fitView, { width, height }),\n ], [indicatorCmd, cursorLayer, id, fitView, width, height]);\n\n // `<SceneViewCanvas>` doesn't expose its element except via `canvasRef`, so\n // we route both our internal ref and the consumer's ref through one setter.\n const setCanvasRef = useCallback((el: HTMLCanvasElement | null) => {\n localCanvasRef.current = el;\n if (typeof canvasRef === 'function') {\n canvasRef(el);\n } else if (canvasRef && typeof canvasRef === 'object') {\n (canvasRef as { current: HTMLCanvasElement | null }).current = el;\n }\n }, [canvasRef]);\n\n return (\n <SceneViewCanvas\n scene={scene}\n view={fitView}\n width={width}\n height={height}\n drawOne={drawOne}\n extraCommands={extraCommands}\n alphaFor={alphaFor}\n layerVisibility={layerVisibility}\n layerOrder={layerOrder}\n animator={animator}\n className={className}\n canvasRef={setCanvasRef}\n />\n );\n}\n\n/**\n * Opinionated minimap. See `MinimapCanvasProps` for the full surface and\n * the module docstring for the rendering / input model.\n *\n * Its dispatcher, actions and deps are its own, so it never competes with\n * the main canvas for input. The pointer store is shared when one is in scope.\n *\n * `forwardRef` is not used because the component is generic over\n * `<TData, TLayer, TPose>` and React's `forwardRef` erases generics. The\n * `canvasRef` prop is the plain-prop equivalent.\n */\nexport function MinimapCanvas<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n return (\n <DepRegistryProvider>\n <ActionsProvider>\n <ActiveToolContextProvider>\n <PointerProviderIfRoot>\n <MinimapCanvasInner {...props} />\n </PointerProviderIfRoot>\n </ActiveToolContextProvider>\n </ActionsProvider>\n </DepRegistryProvider>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;AAkHA,IAAMA,IAAsB;CAC1B,IAAI;CACJ,aAAa,EAAE,QAAQ,GAAK;CAC5B,UAAU,CACR;EAAE,MAAM,EAAE,MAAM,cAAc;EAAG,UAAUC;CAAe,GAC1D;EAAE,MAAM,EAAE,MAAM,OAAO;EAAG,UAAUC;CAAY,CAClD;AACF,GACMC,oBAAyC,IAAI,IAAI,CAAC,CAACH,EAAc,IAAIA,CAAa,CAAC,CAAC,GACpFI,IAAW;CAAE,OAAO;CAAO,OAAO;CAAO,aAAa;CAAO,QAAQ;AAAM;AAEjF,SAASC,EACP,GACA;CACA,IAAM,EACJ,UACA,UAAUC,GACV,iBACA,qBACA,UACA,WACA,YACA,aACA,oBACA,eACA,cACA,SAAM,SACN,mBACA,mBACA,cACA,cACA,QAAK,cACHC,GACEC,IAAWC,EAAcH,CAAY,GAKrCI,IAAeC,EACnBC,EAAM,WACNA,EAAM,YACNA,EAAM,UACR,GAEMC,IAAcC,KAAkBC,GAEhCC,IAAUC,QACPC,EAAeN,GAAO;EAAE;EAAO;CAAO,GAAGO,GAAKN,CAAU,GAI9D;EAACD;EAAOF;EAAcU;EAAOC;EAAQF;EAAKN;CAAU,CAAC,GAElDS,IAAeL,QACZM,EAAwBf,GAAUgB,GAAcC,CAAc,GACpE;EAACjB;EAAUgB;EAAcC;CAAc,CAAC,GAUrCC,IAAiBC,EAAiC,IAAI,GACtDC,IAAcC,EAAUrB,CAAQ,GAChCsB,IAAkBD,EAAUL,CAAY,GACxCO,IAAsBF,EAAUG,CAAgB,GAChDC,IAAaJ,EAAUb,CAAO,GAG9BkB,IAAWjB,SAAwB;EACvC,WAAWW,EAAY;EACvB,MAAM,MAAMG,EAAoB,QAAQI,CAAC;EACzC,gBAAgBL,EAAgB;CAClC,IAAI;EAACF;EAAaG;EAAqBD;CAAe,CAAC;CACvD,EAAa,kBAAkBI,CAAQ;CAEvC,IAAME,IAAUC,EAAmB;CACnC,QAAgB;EACd,IAAI,CAACD,GAAS;EACd,IAAME,IAAM,CAACF,EAAQ,SAASG,EAAoB,CAAC,GAAGH,EAAQ,SAASI,EAAiB,CAAC,CAAC;EAC1F,aAAa;GAAE,KAAK,IAAMC,KAAKH,GAAK,EAAE;EAAG;CAC3C,GAAG,CAACF,CAAO,CAAC;CAGZ,IAAMM,IAAgBC,GAAa,GAAY,MAAe;EAC5D,IAAMC,IAAOlB,EAAe,SAAS,sBAAsB,GACrDmB,IAAKZ,EAAW;EACtB,OAAO;GACL,GAAGY,EAAG,KAAKC,KAAMF,GAAM,QAAQ,MAAMC,EAAG,MAAM;GAC9C,GAAGA,EAAG,KAAKE,KAAMH,GAAM,OAAO,MAAMC,EAAG,MAAM;EAC/C;CACF,GAAG,CAACZ,CAAU,CAAC;CAEf,GAAqB;EACnB,WAAWP;EACF;EACT,aAAavB;EACb;EACA,UAAU;EACV,UAAUC;CACZ,CAAC;CAMD,IAAM4C,IAAeC,EAAkB;CACvC,QAAgB;EACd,IAAMC,IAAKxB,EAAe;EAC1B,IAAI,CAACwB,KAAM,CAACF,GAAc;EAC1B,IAAMG,KAAU,MAA0B;GACxC,IAAMC,IAAIV,EAAc,EAAE,SAAS,EAAE,OAAO;GAC5C,EAAa,IAAI;IAAE,QAAQU,EAAE;IAAG,QAAQA,EAAE;IAAG,QAAQC;GAAG,CAAC;EAC3D,GACMC,KAAW,MAA0B;GACzC,AAAI,EAAE,YAAY,KACdN,EAAa,IAAI,CAAC,EAAE,WAAWK,KAAIL,EAAa,IAAI,IAAI;EAC9D;EAGA,OAFAE,EAAG,iBAAiB,eAAeC,CAAM,GACzCD,EAAG,iBAAiB,gBAAgBI,CAAO,SAC9B;GAEX,AADAJ,EAAG,oBAAoB,eAAeC,CAAM,GAC5CD,EAAG,oBAAoB,gBAAgBI,CAAO;EAChD;CACF,GAAG;EAACN;EAAcN;EAAeW;CAAE,CAAC;CAEpC,IAAME,IAAUC,EAAmB,GAC7BC,IAAcxC,QAAcyC,EAAwB;EACxD,IAAI,GAAGL,EAAG;EACV,eAAeE;EACf,aAAaI,EAAcjC,EAAe,OAAO;CACnD,CAAC,GAAG,CAAC2B,GAAIE,CAAO,CAAC,GAEXK,KAAgB3C,QAA6B,CACjDK,GACA,GAAGmC,EAAY,KAAK,EAAE,QAAQJ,EAAG,GAAGrC,GAAS;EAAE;EAAO;CAAO,CAAC,CAChE,GAAG;EAACM;EAAcmC;EAAaJ;EAAIrC;EAASI;EAAOC;CAAM,CAAC,GAIpDwC,KAAelB,GAAa,MAAiC;EAEjE,AADA,EAAe,UAAUO,GACrB,OAAOY,KAAc,aACvBA,EAAUZ,CAAE,IACHY,KAAa,OAAOA,KAAc,aAC3C,EAAqD,UAAUZ;CAEnE,GAAG,CAACY,CAAS,CAAC;CAEd,OACE,kBAACC,IAAD;EACS;EACP,MAAM/C;EACC;EACC;EACC;EACM;EACL;EACO;EACL;EACF;EACC;EACX,WAAW6C;CACZ,CAAA;AAEL;AAaA,SAAgBG,EACd,GACA;CACA,OACE,kBAACC,GAAD,EAAA,UACE,kBAACC,GAAD,EAAA,UACE,kBAACC,GAAD,EAAA,UACE,kBAACC,GAAD,EAAA,UACE,kBAAC/D,GAAD,EAAoB,GAAIE,EAAQ,CAAA,EACX,CAAA,EACE,CAAA,EACZ,CAAA,EACE,CAAA;AAEzB"}
|
|
1
|
+
{"version":3,"file":"MinimapCanvas.js","names":["MINIMAP_INPUT","MINIMAP_CENTER","MINIMAP_PAN","TOOLS_BY_ID","CHANNELS","MinimapCanvasInner","mainViewProp","props","mainView","normalizeView","sceneVersion","useSyncExternalStore","scene","descriptor","poseDescriptor","AUTO_POSE_DESCRIPTOR","fitView","useMemo","computeFitView","fit","width","height","indicatorCmd","computeIndicatorCommand","mainViewDims","indicatorStyle","localCanvasRef","useRef","mainViewRef","useLatest","mainViewDimsRef","onMainViewChangeRef","onMainViewChange","fitViewRef","rootView","v","actions","useActionsRegistry","off","minimapCenterAction","minimapPanAction","u","clientToWorld","useCallback","rect","fv","cx","cy","pointerStore","usePointerContext","el","onMove","w","id","onLeave","pointer","usePointerPosition","cursorLayer","createLinkedCursorLayer","accentColorOf","extraCommands","setCanvasRef","assignRef","canvasRef","SceneViewCanvas","MinimapCanvas","DepRegistryProvider","ActionsProvider","ActiveToolContextProvider","PointerProviderIfRoot"],"sources":["../../src/canvas/MinimapCanvas.tsx"],"sourcesContent":["/**\n * `<MinimapCanvas>` — opinionated minimap on a canvas of its own, built on\n * `<SceneViewCanvas>`.\n *\n * Renders the same `scene` the main canvas is showing, through a derived\n * \"fit\" view, and overlays a dashed visible-window indicator showing where\n * the main canvas is currently looking. Press anywhere in the minimap to\n * recenter the main view on that world point; drag to pan continuously.\n *\n * Input runs on a dispatcher of its own, through the same `minimap.center` /\n * `minimap.pan` actions the in-surface minimap (`createMinimapContribution`)\n * binds. It publishes its pointer into the pointer store in scope, and draws a\n * crosshair wherever that store says the pointer is on another surface — put\n * one `<PointerContextProvider>` around it and the main canvas for linked\n * cursors both ways.\n */\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport type { Ref } from 'react';\nimport {\n ActionsProvider,\n ActiveToolContextProvider,\n DepRegistryProvider,\n useActionsRegistry,\n useDepSource,\n useGestureDispatcher,\n} from '@weasel-js/routing/react';\nimport { assignRef, useLatest } from '@weasel-js/react';\nimport type { Tool } from '@weasel-js/routing';\nimport { PointerProviderIfRoot } from './SceneCanvas/PointerProviderIfRoot';\nimport { usePointerContext, usePointerPosition } from 'features/pointer/PointerContext';\nimport {\n MINIMAP_CENTER, MINIMAP_PAN, minimapCenterAction, minimapPanAction,\n} from 'features/minimap/actions';\nimport { createLinkedCursorLayer } from 'features/minimap/layers';\nimport type { ViewApi } from 'interactions/actions/depSchema';\nimport { SceneViewCanvas } from './SceneViewCanvas';\nimport {\n computeFitView,\n computeIndicatorCommand,\n} from './minimapMath';\nimport type { IndicatorStyle, MinimapFit } from './minimapMath';\nimport type { SceneViewDrawOne, SceneViewLayers } from './sceneViewRender';\nimport type { DrawCommand } from '../renderer/DrawCommand';\nimport { normalizeView, type View } from '../core/viewport/view';\nimport type { Scene } from '../core/scene/types';\nimport type { PoseDescriptor } from '../core/geometry/poseDescriptor';\nimport type { Animator } from '../animation/types';\nimport { AUTO_POSE_DESCRIPTOR } from '../interactions/actions/resize/autoPoseDescriptor';\nimport { accentColorOf } from './accentColor';\n\n/** Props for `<MinimapCanvas>`. */\nexport interface MinimapCanvasProps<TData, TLayer extends string, TPose> {\n /** Same scene the main canvas is rendering. */\n scene: Scene<TData, TLayer, TPose>;\n /** Main canvas's view — used to position the visible-window indicator and\n * to preserve `scale` when the minimap recenters. */\n mainView: View;\n /** Main canvas's CSS-pixel dims. Used to compute the visible-window rect\n * and the recenter offset. */\n mainViewDims: { width: number; height: number };\n /** Setter called on click (single recenter) and during drag (continuous\n * recenter). Receives a `View` with the same `scale` as `mainView` and\n * `(x, y)` shifted so the pointer's world point lands at the main\n * canvas's center. */\n onMainViewChange: (next: View) => void;\n /** Minimap's own CSS-pixel dims. */\n width: number;\n height: number;\n /** Consumer's draw callback. Applied through the derived fit view; same\n * signature as `<SceneCanvas>`'s scene-slot `drawOne` so the consumer\n * can reuse it (typically simplified — just colored AABBs). */\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Fit policy. Defaults to `\"scene\"` (AABB union of leaf poses). See\n * `MinimapFit` for the full shape.\n *\n * Framing is derived from **document** poses, not `scene.overrides` — a\n * node moved by an override paints where the override puts it, outside the\n * frame if it goes there, rather than making the whole minimap rescale on\n * every frame of a drag or a settle. */\n fit?: MinimapFit<TData, TLayer, TPose>;\n /** How to read poses. Default `AUTO_POSE_DESCRIPTOR`. */\n poseDescriptor?: PoseDescriptor<TPose>;\n /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Pass the same function the main canvas uses so a\n * scoping-dim treatment shows up in the minimap too. */\n alphaFor?: (id: string) => number;\n /** Hide scene layers in the minimap, keyed `scene:<layerId>` as on\n * `<SceneCanvas>` — pass the main canvas's map so both show the same set. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Paint order for the minimap, keyed as `layerVisibility`. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Optional animator: the minimap repaints on its ticks and paints its\n * `colorOverrides`. Pass the main canvas's animator so both show the same\n * colors. */\n animator?: Animator;\n /** Visual tuning of the indicator stroke. */\n indicatorStyle?: IndicatorStyle;\n /** CSS class for sizing / positioning the canvas. */\n className?: string;\n /** Forwarded ref to the underlying `<canvas>`. */\n canvasRef?: Ref<HTMLCanvasElement>;\n /** The view id this minimap publishes its pointer under. Default\n * `'minimap'`. */\n id?: string;\n}\n\n/** The minimap's own bindings. Unscoped: this dispatcher routes no views, so\n * every input on it is the minimap's. */\nconst MINIMAP_INPUT: Tool = {\n id: 'minimap',\n eligibility: { always: true },\n bindings: [\n { spec: { kind: 'pointerDown' }, actionId: MINIMAP_CENTER },\n { spec: { kind: 'drag' }, actionId: MINIMAP_PAN },\n ],\n};\nconst TOOLS_BY_ID: ReadonlyMap<string, Tool> = new Map([[MINIMAP_INPUT.id, MINIMAP_INPUT]]);\nconst CHANNELS = { wheel: false, pinch: false, contextMenu: false, ingest: false } as const;\n\nfunction MinimapCanvasInner<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n const {\n scene,\n mainView: mainViewProp,\n mainViewDims,\n onMainViewChange,\n width,\n height,\n drawOne,\n alphaFor,\n layerVisibility,\n layerOrder,\n animator,\n fit = 'scene',\n poseDescriptor,\n indicatorStyle,\n className,\n canvasRef,\n id = 'minimap',\n } = props;\n const mainView = normalizeView(mainViewProp);\n\n // Subscribe to scene version so the fit view recomputes when the scene\n // mutates. `<SceneViewCanvas>` also subscribes, but it owns its own\n // rendering; we need the version *here* to invalidate the memoized fit.\n const sceneVersion = useSyncExternalStore(\n scene.subscribe,\n scene.getVersion,\n scene.getVersion,\n );\n\n const descriptor = (poseDescriptor ?? AUTO_POSE_DESCRIPTOR) as PoseDescriptor<TPose>;\n\n const fitView = useMemo<View>(() => {\n return computeFitView(scene, { width, height }, fit, descriptor);\n // `sceneVersion` participates so the memo re-evaluates after scene mutations.\n // `descriptor` is stable when the prop is omitted.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [scene, sceneVersion, width, height, fit, descriptor]);\n\n const indicatorCmd = useMemo<DrawCommand>(() => {\n return computeIndicatorCommand(mainView, mainViewDims, indicatorStyle);\n }, [mainView, mainViewDims, indicatorStyle]);\n\n // -------------------------------------------------------------------------\n // Input\n // -------------------------------------------------------------------------\n //\n // The \"latest\" pattern (refs holding the current mainView / dims / setter\n // / fitView) lets the dep and the listeners read up-to-date values without\n // re-binding every frame.\n\n const localCanvasRef = useRef<HTMLCanvasElement | null>(null);\n const mainViewRef = useLatest(mainView);\n const mainViewDimsRef = useLatest(mainViewDims);\n const onMainViewChangeRef = useLatest(onMainViewChange);\n const fitViewRef = useLatest(fitView);\n\n // The main canvas's camera, which is what the minimap's actions move.\n const rootView = useMemo<ViewApi>(() => ({\n get: () => mainViewRef.current,\n set: (v) => onMainViewChangeRef.current(v),\n hostSize: () => mainViewDimsRef.current,\n }), [mainViewRef, onMainViewChangeRef, mainViewDimsRef]);\n useDepSource('rootView', () => rootView);\n\n const actions = useActionsRegistry();\n useEffect(() => {\n if (!actions) return;\n const off = [actions.register(minimapCenterAction()), actions.register(minimapPanAction())];\n return () => { for (const u of off) u(); };\n }, [actions]);\n\n /** Client point → world, through the fit camera. */\n const clientToWorld = useCallback((cx: number, cy: number) => {\n const rect = localCanvasRef.current?.getBoundingClientRect();\n const fv = fitViewRef.current;\n return {\n x: fv.x + (cx - (rect?.left ?? 0)) / fv.scale.x,\n y: fv.y + (cy - (rect?.top ?? 0)) / fv.scale.y,\n };\n }, [fitViewRef]);\n\n useGestureDispatcher({\n canvasRef: localCanvasRef,\n actions: actions!,\n entriesById: TOOLS_BY_ID,\n clientToWorld,\n keyboard: false,\n channels: CHANNELS,\n });\n\n // -------------------------------------------------------------------------\n // Linked cursor\n // -------------------------------------------------------------------------\n\n const pointerStore = usePointerContext();\n useEffect(() => {\n const el = localCanvasRef.current;\n if (!el || !pointerStore) return;\n const onMove = (e: PointerEvent): void => {\n const w = clientToWorld(e.clientX, e.clientY);\n pointerStore.set({ worldX: w.x, worldY: w.y, viewId: id });\n };\n const onLeave = (e: PointerEvent): void => {\n if (e.buttons !== 0) return;\n if (pointerStore.get()?.viewId === id) pointerStore.set(null);\n };\n el.addEventListener('pointermove', onMove);\n el.addEventListener('pointerleave', onLeave);\n return () => {\n el.removeEventListener('pointermove', onMove);\n el.removeEventListener('pointerleave', onLeave);\n };\n }, [pointerStore, clientToWorld, id]);\n\n const pointer = usePointerPosition();\n const cursorLayer = useMemo(() => createLinkedCursorLayer({\n id: `${id}.cursor`,\n pointer: () => pointer,\n color: () => accentColorOf(localCanvasRef.current),\n }), [id, pointer]);\n\n const extraCommands = useMemo<DrawCommand[]>(() => [\n indicatorCmd,\n ...cursorLayer.draw({ viewId: id }, fitView, { width, height }),\n ], [indicatorCmd, cursorLayer, id, fitView, width, height]);\n\n // `<SceneViewCanvas>` doesn't expose its element except via `canvasRef`, so\n // we route both our internal ref and the consumer's ref through one setter.\n const setCanvasRef = useCallback((el: HTMLCanvasElement | null) => {\n localCanvasRef.current = el;\n assignRef(canvasRef, el);\n }, [canvasRef]);\n\n return (\n <SceneViewCanvas\n scene={scene}\n view={fitView}\n width={width}\n height={height}\n drawOne={drawOne}\n extraCommands={extraCommands}\n alphaFor={alphaFor}\n layerVisibility={layerVisibility}\n layerOrder={layerOrder}\n animator={animator}\n className={className}\n canvasRef={setCanvasRef}\n />\n );\n}\n\n/**\n * Opinionated minimap. See `MinimapCanvasProps` for the full surface and\n * the module docstring for the rendering / input model.\n *\n * Its dispatcher, actions and deps are its own, so it never competes with\n * the main canvas for input. The pointer store is shared when one is in scope.\n *\n * `forwardRef` is not used because the component is generic over\n * `<TData, TLayer, TPose>` and React's `forwardRef` erases generics. The\n * `canvasRef` prop is the plain-prop equivalent.\n */\nexport function MinimapCanvas<TData, TLayer extends string, TPose>(\n props: MinimapCanvasProps<TData, TLayer, TPose>,\n) {\n return (\n <DepRegistryProvider>\n <ActionsProvider>\n <ActiveToolContextProvider>\n <PointerProviderIfRoot>\n <MinimapCanvasInner {...props} />\n </PointerProviderIfRoot>\n </ActiveToolContextProvider>\n </ActionsProvider>\n </DepRegistryProvider>\n );\n}\n"],"mappings":"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"}
|
package/dist/canvas/NodeShape.js
CHANGED
|
@@ -10,10 +10,10 @@ import { DEFAULT_SHAPE_FILL as u } from "../util/paint.js";
|
|
|
10
10
|
import { fillInPoseFrame as d } from "../core/fillInPoseFrame.js";
|
|
11
11
|
import { resolveFillPattern as f } from "../features/patterns/resolveSpec.js";
|
|
12
12
|
import { textCommandFromPose as p } from "../features/text/textCommand.js";
|
|
13
|
-
import { hasSlop as
|
|
14
|
-
import { getImageBitmap as
|
|
15
|
-
import { PATH_L as
|
|
16
|
-
import { textLineBoxes as
|
|
13
|
+
import { hasSlop as ee, slopForStrokeHit as m, widenSlop as h } from "../core/viewport/screenSlop.js";
|
|
14
|
+
import { getImageBitmap as g, imageStatus as _ } from "../features/images/imageCache.js";
|
|
15
|
+
import { PATH_L as v, PATH_M as y, PATH_Z as b, boundsOfPath as x, ellipsePath as S, linePath as C, pathContainsPoint as w, regularPolygonPath as T, starPath as E, strokeHitTest as D } from "@weasel-js/geom";
|
|
16
|
+
import { textLineBoxes as te } from "@weasel-js/text";
|
|
17
17
|
//#region src/canvas/NodeShape.ts
|
|
18
18
|
function O(e) {
|
|
19
19
|
return e === void 0 || s(e);
|
|
@@ -57,7 +57,7 @@ function B(e, t, n) {
|
|
|
57
57
|
}
|
|
58
58
|
function V(e, t, n) {
|
|
59
59
|
if (!s(e)) return null;
|
|
60
|
-
let r = t ? i(t, n ?? 1) : 0, a = Math.min(e.x, e.x + e.width), o = Math.min(e.y, e.y + e.height);
|
|
60
|
+
let r = t ? i(t, n?.scale ?? 1, n?.leastScale) : 0, a = Math.min(e.x, e.x + e.width), o = Math.min(e.y, e.y + e.height);
|
|
61
61
|
return {
|
|
62
62
|
x: a - r,
|
|
63
63
|
y: o - r,
|
|
@@ -68,10 +68,10 @@ function V(e, t, n) {
|
|
|
68
68
|
function H(e, t, n, r, i = {}) {
|
|
69
69
|
let a = R(e, t, { derivedPath: i.derivedPath });
|
|
70
70
|
if (a === null) return !0;
|
|
71
|
-
let o = z(e, t, { scale: i.scale }) ?? k, s =
|
|
71
|
+
let o = z(e, t, { scale: i.scale }) ?? k, s = w(a, n, r);
|
|
72
72
|
if (o.filled && s) return !0;
|
|
73
|
-
let { extra:
|
|
74
|
-
return (
|
|
73
|
+
let c = h(i.tolerance, (s ? o.insetPx : o.outsetPx) ?? 0, i.scale), { extra: l, opts: u } = m(c), d = (s ? o.inset : o.outset) + l;
|
|
74
|
+
return (d > 0 || ee(c)) && D(a, n, r, d, u);
|
|
75
75
|
}
|
|
76
76
|
function U() {
|
|
77
77
|
return [...A.high, ...A.normal];
|
|
@@ -90,13 +90,13 @@ function W(e, t) {
|
|
|
90
90
|
verticalAlign: e.verticalAlign
|
|
91
91
|
};
|
|
92
92
|
}
|
|
93
|
-
var
|
|
93
|
+
var ne = {
|
|
94
94
|
id: "kit:text",
|
|
95
95
|
matches: (e) => O(e.pose) ? e.data?.text != null : !1,
|
|
96
96
|
paint: (e, n) => t(e, F, n, () => [p(W(e.data, n))]),
|
|
97
97
|
silhouette: (e, t) => {
|
|
98
|
-
let n =
|
|
99
|
-
return n.length === 0 ? null :
|
|
98
|
+
let n = te(W(e.data, t));
|
|
99
|
+
return n.length === 0 ? null : G(n);
|
|
100
100
|
},
|
|
101
101
|
ink: (e, t, n) => {
|
|
102
102
|
let r = e.data;
|
|
@@ -106,11 +106,11 @@ var G = {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
};
|
|
109
|
-
function
|
|
109
|
+
function G(e) {
|
|
110
110
|
let t = new Uint8Array(e.length * 6), n = new Float32Array(e.length * 10), r = 0, i = 0;
|
|
111
111
|
for (let a of e) {
|
|
112
112
|
let { x: e, y: o, width: s, height: c } = a;
|
|
113
|
-
t[i++] =
|
|
113
|
+
t[i++] = y, n[r++] = e, n[r++] = o, t[i++] = v, n[r++] = e + s, n[r++] = o, t[i++] = v, n[r++] = e + s, n[r++] = o + c, t[i++] = v, n[r++] = e, n[r++] = o + c, t[i++] = v, n[r++] = e, n[r++] = o, t[i++] = b;
|
|
114
114
|
}
|
|
115
115
|
return {
|
|
116
116
|
kind: "polygon",
|
|
@@ -137,21 +137,30 @@ function Y(e, t) {
|
|
|
137
137
|
outset: 0,
|
|
138
138
|
inset: 0
|
|
139
139
|
};
|
|
140
|
-
let i =
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
140
|
+
let i = r(e), a = (t, n) => {
|
|
141
|
+
switch (e.align ?? "center") {
|
|
142
|
+
case "inner": return {
|
|
143
|
+
outset: n,
|
|
144
|
+
inset: t
|
|
145
|
+
};
|
|
146
|
+
case "outer": return {
|
|
147
|
+
outset: t + n,
|
|
148
|
+
inset: 0
|
|
149
|
+
};
|
|
150
|
+
default: return {
|
|
151
|
+
outset: t / 2 + n,
|
|
152
|
+
inset: t / 2
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}, o = e.width ?? 1, s = a(typeof o == "object" ? 0 : n(o, t ?? 1), i.world);
|
|
156
|
+
if (typeof o != "object" && !(i.px > 0)) return s;
|
|
157
|
+
let c = a(typeof o == "object" ? o.px : 0, i.px);
|
|
158
|
+
return {
|
|
159
|
+
outset: s.outset,
|
|
160
|
+
inset: s.inset,
|
|
161
|
+
outsetPx: c.outset,
|
|
162
|
+
insetPx: c.inset
|
|
163
|
+
};
|
|
155
164
|
}
|
|
156
165
|
function X(e, t) {
|
|
157
166
|
let n = t?.vertexColors, r = e[0];
|
|
@@ -190,16 +199,16 @@ var Z = {
|
|
|
190
199
|
...Y(i, n?.scale)
|
|
191
200
|
};
|
|
192
201
|
},
|
|
193
|
-
bounds: (e, t, n) => V(t, q(e.data.stroke), n
|
|
194
|
-
},
|
|
202
|
+
bounds: (e, t, n) => V(t, q(e.data.stroke), n)
|
|
203
|
+
}, re = {
|
|
195
204
|
id: "kit:shape",
|
|
196
205
|
matches: (e) => {
|
|
197
206
|
if (!O(e.pose)) return !1;
|
|
198
207
|
let t = e.data?.shape;
|
|
199
|
-
return t != null &&
|
|
208
|
+
return t != null && ie.has(t);
|
|
200
209
|
},
|
|
201
210
|
paint: (e, n, r) => X(t(e, F, n, () => {
|
|
202
|
-
let t = e.data, r =
|
|
211
|
+
let t = e.data, r = Q(t, n), i = K(t.fill, u), a = i && f(d(i, n)), o = q(t.stroke), s = o && J(o, n);
|
|
203
212
|
return [{
|
|
204
213
|
kind: "path",
|
|
205
214
|
path: r,
|
|
@@ -209,7 +218,7 @@ var Z = {
|
|
|
209
218
|
}), r),
|
|
210
219
|
silhouette: (e, t) => {
|
|
211
220
|
let n = e.data;
|
|
212
|
-
return
|
|
221
|
+
return Q(n, t);
|
|
213
222
|
},
|
|
214
223
|
ink: (e, t, n) => {
|
|
215
224
|
let r = e.data;
|
|
@@ -218,26 +227,26 @@ var Z = {
|
|
|
218
227
|
...Y(q(r.stroke), n?.scale)
|
|
219
228
|
};
|
|
220
229
|
},
|
|
221
|
-
bounds: (e, t, n) => V(t, q(e.data.stroke), n
|
|
222
|
-
},
|
|
230
|
+
bounds: (e, t, n) => V(t, q(e.data.stroke), n)
|
|
231
|
+
}, ie = /* @__PURE__ */ new Set([
|
|
223
232
|
"rect",
|
|
224
233
|
"ellipse",
|
|
225
234
|
"polygon",
|
|
226
235
|
"star"
|
|
227
236
|
]);
|
|
228
|
-
function
|
|
237
|
+
function Q(e, t) {
|
|
229
238
|
switch (e.shape) {
|
|
230
|
-
case "ellipse": return
|
|
239
|
+
case "ellipse": return S(t);
|
|
231
240
|
case "polygon": {
|
|
232
241
|
let n = t.x + t.width / 2, r = t.y + t.height / 2, i = Math.min(t.width, t.height) / 2;
|
|
233
|
-
return
|
|
242
|
+
return T({
|
|
234
243
|
x: n,
|
|
235
244
|
y: r
|
|
236
245
|
}, i, e.sides ?? 6);
|
|
237
246
|
}
|
|
238
247
|
case "star": {
|
|
239
248
|
let n = t.x + t.width / 2, r = t.y + t.height / 2, i = Math.min(t.width, t.height) / 2;
|
|
240
|
-
return
|
|
249
|
+
return E({
|
|
241
250
|
x: n,
|
|
242
251
|
y: r
|
|
243
252
|
}, i, e.points ?? 5);
|
|
@@ -251,7 +260,7 @@ function $(e, t) {
|
|
|
251
260
|
};
|
|
252
261
|
}
|
|
253
262
|
}
|
|
254
|
-
function
|
|
263
|
+
function ae(e, t) {
|
|
255
264
|
return {
|
|
256
265
|
x: e.x * t.width,
|
|
257
266
|
y: e.y * t.height,
|
|
@@ -259,13 +268,13 @@ function re(e, t) {
|
|
|
259
268
|
h: e.height * t.height
|
|
260
269
|
};
|
|
261
270
|
}
|
|
262
|
-
function
|
|
271
|
+
function oe(e, t, n) {
|
|
263
272
|
if (n && n > 0) return {
|
|
264
273
|
width: Math.abs(e.width) * n / (t?.width || 1),
|
|
265
274
|
height: Math.abs(e.height) * n / (t?.height || 1)
|
|
266
275
|
};
|
|
267
276
|
}
|
|
268
|
-
var
|
|
277
|
+
var $ = {
|
|
269
278
|
id: "kit:image",
|
|
270
279
|
matches: (e) => {
|
|
271
280
|
if (!O(e.pose)) return !1;
|
|
@@ -273,7 +282,7 @@ var ae = {
|
|
|
273
282
|
return typeof t == "string" && t.length > 0;
|
|
274
283
|
},
|
|
275
284
|
paint: (e, t, n) => {
|
|
276
|
-
let r = e.data, i = t, a = n?.resolveImage ? n.resolveImage(e) :
|
|
285
|
+
let r = e.data, i = t, a = n?.resolveImage ? n.resolveImage(e) : g(r.image.src, oe(i, r.image.source, n?.pixelScale));
|
|
277
286
|
if (a) return [{
|
|
278
287
|
kind: "image",
|
|
279
288
|
image: a,
|
|
@@ -282,11 +291,11 @@ var ae = {
|
|
|
282
291
|
w: i.width,
|
|
283
292
|
h: i.height,
|
|
284
293
|
...r.image.opacity === void 0 ? {} : { opacity: r.image.opacity },
|
|
285
|
-
...r.image.source ? { source:
|
|
294
|
+
...r.image.source ? { source: ae(r.image.source, a) } : {},
|
|
286
295
|
...r.image.flipX ? { flipX: !0 } : {},
|
|
287
296
|
...r.image.flipY ? { flipY: !0 } : {}
|
|
288
297
|
}];
|
|
289
|
-
let o = !n?.resolveImage &&
|
|
298
|
+
let o = !n?.resolveImage && _(r.image.src) === "error", s = o ? "#d08a8a" : "#bbbbbb", c = [{
|
|
290
299
|
kind: "path",
|
|
291
300
|
path: {
|
|
292
301
|
kind: "rect",
|
|
@@ -302,7 +311,7 @@ var ae = {
|
|
|
302
311
|
}];
|
|
303
312
|
return o && c.push({
|
|
304
313
|
kind: "path",
|
|
305
|
-
path:
|
|
314
|
+
path: C({
|
|
306
315
|
x: i.x,
|
|
307
316
|
y: i.y
|
|
308
317
|
}, {
|
|
@@ -325,17 +334,17 @@ var ae = {
|
|
|
325
334
|
height: n.height
|
|
326
335
|
};
|
|
327
336
|
},
|
|
328
|
-
bounds: (e, t, n) => V(t,
|
|
329
|
-
},
|
|
337
|
+
bounds: (e, t, n) => V(t, se, n)
|
|
338
|
+
}, se = {
|
|
330
339
|
paint: { color: "#000" },
|
|
331
340
|
width: 1
|
|
332
|
-
},
|
|
341
|
+
}, ce = {
|
|
333
342
|
id: "kit:derived",
|
|
334
343
|
matches: (e) => (e.dependsOn?.length ?? 0) > 0 && e.derivePath !== void 0,
|
|
335
344
|
paint: (e, t, n) => {
|
|
336
345
|
let r = n?.derivedPath;
|
|
337
346
|
if (r == null) return [];
|
|
338
|
-
let i =
|
|
347
|
+
let i = x(r), a = e.data, o = q(a?.stroke), s = K(a?.fill, o === null ? u : null), c = s && f(d(s, i)), l = o && J(o, i);
|
|
339
348
|
return X([{
|
|
340
349
|
kind: "path",
|
|
341
350
|
path: r,
|
|
@@ -352,7 +361,7 @@ var ae = {
|
|
|
352
361
|
...Y(i, n?.scale)
|
|
353
362
|
};
|
|
354
363
|
}
|
|
355
|
-
},
|
|
364
|
+
}, le = {
|
|
356
365
|
id: "kit:rect-fallback",
|
|
357
366
|
matches: (e) => O(e.pose),
|
|
358
367
|
paint: (e, t) => {
|
|
@@ -381,10 +390,10 @@ var ae = {
|
|
|
381
390
|
},
|
|
382
391
|
bounds: (e, t) => V(t, null, void 0)
|
|
383
392
|
};
|
|
384
|
-
function
|
|
385
|
-
j(
|
|
393
|
+
function ue() {
|
|
394
|
+
j(ne), j(ce), j(Z), j(re), j($), j(le);
|
|
386
395
|
}
|
|
387
|
-
|
|
396
|
+
ue();
|
|
388
397
|
//#endregion
|
|
389
398
|
export { k as DEFAULT_INK, I as findNodeShape, B as findShapeBounds, z as findShapeInk, R as findShapeSilhouette, U as getNodeShapes, j as registerNodeShape, H as shapeCoversPoint };
|
|
390
399
|
|