@prnt/dagr-explorer 0.1.3
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 +93 -0
- package/LICENSE +21 -0
- package/README.md +441 -0
- package/dist/base.d.ts +63 -0
- package/dist/base.d.ts.map +1 -0
- package/dist/base.js +20 -0
- package/dist/base.js.map +1 -0
- package/dist/camera.d.ts +61 -0
- package/dist/camera.d.ts.map +1 -0
- package/dist/camera.js +142 -0
- package/dist/camera.js.map +1 -0
- package/dist/context.d.ts +110 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +71 -0
- package/dist/context.js.map +1 -0
- package/dist/dagr-explorer.d.ts +41 -0
- package/dist/dagr-explorer.d.ts.map +1 -0
- package/dist/dagr-explorer.js +13 -0
- package/dist/dagr-explorer.js.map +1 -0
- package/dist/errors.d.ts +55 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/explorer-details.d.ts +44 -0
- package/dist/explorer-details.d.ts.map +1 -0
- package/dist/explorer-details.js +76 -0
- package/dist/explorer-details.js.map +1 -0
- package/dist/explorer-search.d.ts +31 -0
- package/dist/explorer-search.d.ts.map +1 -0
- package/dist/explorer-search.js +86 -0
- package/dist/explorer-search.js.map +1 -0
- package/dist/explorer-toolbar.d.ts +17 -0
- package/dist/explorer-toolbar.d.ts.map +1 -0
- package/dist/explorer-toolbar.js +44 -0
- package/dist/explorer-toolbar.js.map +1 -0
- package/dist/explorer-trace-toggle.d.ts +16 -0
- package/dist/explorer-trace-toggle.d.ts.map +1 -0
- package/dist/explorer-trace-toggle.js +8 -0
- package/dist/explorer-trace-toggle.js.map +1 -0
- package/dist/explorer-viewport.d.ts +69 -0
- package/dist/explorer-viewport.d.ts.map +1 -0
- package/dist/explorer-viewport.js +69 -0
- package/dist/explorer-viewport.js.map +1 -0
- package/dist/explorer-views.d.ts +24 -0
- package/dist/explorer-views.d.ts.map +1 -0
- package/dist/explorer-views.js +16 -0
- package/dist/explorer-views.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +33 -0
- package/dist/index.js.map +1 -0
- package/dist/isomorphic-layout-effect.d.ts +7 -0
- package/dist/isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/isomorphic-layout-effect.js +7 -0
- package/dist/isomorphic-layout-effect.js.map +1 -0
- package/dist/labels.d.ts +67 -0
- package/dist/labels.d.ts.map +1 -0
- package/dist/labels.js +50 -0
- package/dist/labels.js.map +1 -0
- package/dist/layout.d.ts +82 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +244 -0
- package/dist/layout.js.map +1 -0
- package/dist/navigation.d.ts +20 -0
- package/dist/navigation.d.ts.map +1 -0
- package/dist/navigation.js +44 -0
- package/dist/navigation.js.map +1 -0
- package/dist/root.d.ts +89 -0
- package/dist/root.d.ts.map +1 -0
- package/dist/root.js +401 -0
- package/dist/root.js.map +1 -0
- package/dist/search.d.ts +19 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +31 -0
- package/dist/search.js.map +1 -0
- package/dist/size.d.ts +12 -0
- package/dist/size.d.ts.map +1 -0
- package/dist/size.js +20 -0
- package/dist/size.js.map +1 -0
- package/dist/svg-base.d.ts +33 -0
- package/dist/svg-base.d.ts.map +1 -0
- package/dist/svg-base.js +89 -0
- package/dist/svg-base.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/use-explorer-camera.d.ts +56 -0
- package/dist/use-explorer-camera.d.ts.map +1 -0
- package/dist/use-explorer-camera.js +641 -0
- package/dist/use-explorer-camera.js.map +1 -0
- package/dist/use-explorer.d.ts +23 -0
- package/dist/use-explorer.d.ts.map +1 -0
- package/dist/use-explorer.js +26 -0
- package/dist/use-explorer.js.map +1 -0
- package/dist/validate.d.ts +20 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +99 -0
- package/dist/validate.js.map +1 -0
- package/dist/viewport-surface.d.ts +90 -0
- package/dist/viewport-surface.d.ts.map +1 -0
- package/dist/viewport-surface.js +485 -0
- package/dist/viewport-surface.js.map +1 -0
- package/dist/visible-set.d.ts +65 -0
- package/dist/visible-set.d.ts.map +1 -0
- package/dist/visible-set.js +168 -0
- package/dist/visible-set.js.map +1 -0
- package/package.json +62 -0
- package/src/base.ts +67 -0
- package/src/camera.ts +206 -0
- package/src/context.ts +168 -0
- package/src/dagr-explorer.tsx +85 -0
- package/src/errors.ts +85 -0
- package/src/explorer-details.tsx +156 -0
- package/src/explorer-search.tsx +140 -0
- package/src/explorer-toolbar.tsx +77 -0
- package/src/explorer-trace-toggle.tsx +34 -0
- package/src/explorer-viewport.tsx +181 -0
- package/src/explorer-views.tsx +61 -0
- package/src/index.ts +76 -0
- package/src/isomorphic-layout-effect.ts +7 -0
- package/src/labels.ts +109 -0
- package/src/layout.ts +298 -0
- package/src/navigation.ts +51 -0
- package/src/root.tsx +544 -0
- package/src/search.ts +36 -0
- package/src/size.ts +23 -0
- package/src/svg-base.tsx +173 -0
- package/src/types.ts +69 -0
- package/src/use-explorer-camera.ts +675 -0
- package/src/use-explorer.ts +32 -0
- package/src/validate.ts +173 -0
- package/src/viewport-surface.tsx +650 -0
- package/src/visible-set.ts +225 -0
- package/styles.css +253 -0
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* The explorer's viewport: a pannable, zoomable surface with a base layer
|
|
4
|
+
* and a windowed DOM overlay, driven by props.
|
|
5
|
+
*
|
|
6
|
+
* Internal. M5.6d wraps it with the root's context as the public
|
|
7
|
+
* `ExplorerViewport` part, which is why everything here arrives as a prop.
|
|
8
|
+
*
|
|
9
|
+
* **React renders only when the visible set changes, or a prop does.**
|
|
10
|
+
* `useExplorerCamera` writes the plane's transform on each frame and calls
|
|
11
|
+
* back here. The callback computes the visible set and keeps the previous
|
|
12
|
+
* one, by reference, when `sameVisibleSet` says nothing changed, so a pan
|
|
13
|
+
* inside the overscan margin is a style write and no React work. A node
|
|
14
|
+
* button is placed in world coordinates once, when it mounts, and the plane
|
|
15
|
+
* carries it.
|
|
16
|
+
*
|
|
17
|
+
* **Most frames skip the scan.** The set was computed over the view plus a
|
|
18
|
+
* margin on every side, so while the view stays inside half that margin, at
|
|
19
|
+
* the same scale, every node it can show is already in the set. A frame
|
|
20
|
+
* like that does not call `computeVisibleSet` at all.
|
|
21
|
+
*
|
|
22
|
+
* **One listener per gesture, on the viewport.** No node has a listener of
|
|
23
|
+
* its own. A click on a button resolves to that node, a click anywhere else
|
|
24
|
+
* resolves through the layout, so a base mark (which has no element the
|
|
25
|
+
* overlay owns) is clickable at every tier.
|
|
26
|
+
*
|
|
27
|
+
* The plane is a composited layer only while the camera moves, which the
|
|
28
|
+
* camera hook decides, and never through `translateZ`. A cached raster of
|
|
29
|
+
* text enlarged by the camera goes blurry, so at rest there is none.
|
|
30
|
+
*
|
|
31
|
+
* **The graph is one tab stop.** Exactly one node button has `tabIndex` 0:
|
|
32
|
+
* the selected node, else the last node focused from the keyboard, else the
|
|
33
|
+
* node nearest the viewport center as of the last scan, else (before there
|
|
34
|
+
* is a camera) the first node. It is pinned, so it is always mounted, and so
|
|
35
|
+
* is the node that has focus and the node an arrow is moving focus to. An
|
|
36
|
+
* arrow on a focused node moves focus to `nearestInDirection`: the target is
|
|
37
|
+
* pinned, mounted, focused, and only then does the old node lose its pin, so
|
|
38
|
+
* focus never falls to the page in between. A node focused from the keyboard
|
|
39
|
+
* is revealed by the least pan; one focused by a pointer moves nothing.
|
|
40
|
+
*
|
|
41
|
+
* **Nothing reads the DOM in render,** so the surface renders on a server:
|
|
42
|
+
* the base draws every mark, the plane is hidden, and no node has a button.
|
|
43
|
+
*/
|
|
44
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
45
|
+
import { visibleWorld } from './camera.js';
|
|
46
|
+
import { nearestInDirection } from './navigation.js';
|
|
47
|
+
import { useIsomorphicLayoutEffect } from './isomorphic-layout-effect.js';
|
|
48
|
+
import { svgBase } from './svg-base.js';
|
|
49
|
+
import { useExplorerCamera } from './use-explorer-camera.js';
|
|
50
|
+
import { DEFAULT_MAX_OVERLAY_NODES, DEFAULT_TIERS, OVERSCAN, computeVisibleSet, indexLayout, nearestToCenter, nodeAtPoint, sameVisibleSet, } from './visible-set.js';
|
|
51
|
+
const NODE = '[data-dagr-explorer="node"]';
|
|
52
|
+
const NO_DIMMED = new Set();
|
|
53
|
+
const NO_GROUPS = [];
|
|
54
|
+
const ARROWS = {
|
|
55
|
+
ArrowUp: 'up',
|
|
56
|
+
ArrowDown: 'down',
|
|
57
|
+
ArrowLeft: 'left',
|
|
58
|
+
ArrowRight: 'right',
|
|
59
|
+
};
|
|
60
|
+
const usable = (value) => value !== undefined && Number.isFinite(value) && value >= 0;
|
|
61
|
+
/**
|
|
62
|
+
* A pair of gates with each bad or missing one replaced by its default. Per
|
|
63
|
+
* gate rather than all or nothing, so one mistyped number does not discard
|
|
64
|
+
* the other.
|
|
65
|
+
*/
|
|
66
|
+
function tiersOf(summary, rich) {
|
|
67
|
+
return {
|
|
68
|
+
summary: usable(summary) ? summary : DEFAULT_TIERS.summary,
|
|
69
|
+
rich: usable(rich) ? rich : DEFAULT_TIERS.rich,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* What the base draws before there is a camera: every node as a mark and
|
|
74
|
+
* every routed edge, and no overlay. It is what a server can render, and on
|
|
75
|
+
* the client it is replaced on the first frame. The plane is hidden until
|
|
76
|
+
* then, so it is never seen unscaled. Once there is a camera, a new layout's
|
|
77
|
+
* first render is windowed from it instead, so a swap to a large graph never
|
|
78
|
+
* commits every node.
|
|
79
|
+
*/
|
|
80
|
+
function everythingAsMarks(index) {
|
|
81
|
+
return {
|
|
82
|
+
overlay: new Map(),
|
|
83
|
+
baseNodes: index.nodeIds,
|
|
84
|
+
edges: index.edgeIds.filter((_, i) => index.edgeBounds[i] !== null),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const IN_GROUP = (groupLabel) => `in ${groupLabel}`;
|
|
88
|
+
function defaultName(node, groups, inGroup) {
|
|
89
|
+
return [node.label, ...groups.map((group) => inGroup(group.label))].join(', ');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The world rect a view may move within without a scan: the view at scan
|
|
93
|
+
* time, grown by half the overscan on each side. The scan itself covered the
|
|
94
|
+
* full overscan, so a node in the actual view is a node the scan saw.
|
|
95
|
+
*/
|
|
96
|
+
function slack(world) {
|
|
97
|
+
const margin = OVERSCAN / 2;
|
|
98
|
+
return {
|
|
99
|
+
x: world.x - world.width * margin,
|
|
100
|
+
y: world.y - world.height * margin,
|
|
101
|
+
width: world.width * (1 + margin * 2),
|
|
102
|
+
height: world.height * (1 + margin * 2),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const inside = (inner, outer) => inner.x >= outer.x &&
|
|
106
|
+
inner.y >= outer.y &&
|
|
107
|
+
inner.x + inner.width <= outer.x + outer.width &&
|
|
108
|
+
inner.y + inner.height <= outer.y + outer.height;
|
|
109
|
+
/** The node button for `id` inside `viewport`, if it is mounted. */
|
|
110
|
+
function nodeButton(viewport, id) {
|
|
111
|
+
for (const element of viewport.querySelectorAll(NODE)) {
|
|
112
|
+
if (element instanceof HTMLElement && element.dataset['nodeId'] === id)
|
|
113
|
+
return element;
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
export function ViewportSurface(props) {
|
|
118
|
+
const { label, view, layout, selectedId = null, dimmed = NO_DIMMED, pinned, tiers, maxOverlayNodes, base = svgBase, renderNode, nodeAriaLabel, inGroup = IN_GROUP, onNodeActivate, onNodeZoom, controlsRef, cameraSourceRef, describedBy, className, style, } = props;
|
|
119
|
+
const viewportRef = useRef(null);
|
|
120
|
+
const planeRef = useRef(null);
|
|
121
|
+
const index = useMemo(() => indexLayout(layout), [layout]);
|
|
122
|
+
const [shown, setShown] = useState(() => ({ index, set: everythingAsMarks(index), center: null }));
|
|
123
|
+
const shownRef = useRef(shown);
|
|
124
|
+
const lastViewportRef = useRef(null);
|
|
125
|
+
// The last drawn camera, read where the controls do not exist yet: the
|
|
126
|
+
// pins decide the options, which `onFrame` and so the camera depend on.
|
|
127
|
+
const lastCameraRef = useRef(null);
|
|
128
|
+
const scanRef = useRef(null);
|
|
129
|
+
const [listeners] = useState(() => new Set());
|
|
130
|
+
// Focus. `focusedId` has focus now, by any means. `keyedId` last had focus
|
|
131
|
+
// from the keyboard, and is the tab target's fallback. `movingTo` is where
|
|
132
|
+
// an arrow is moving focus, until its button mounts and takes it.
|
|
133
|
+
const [focusedId, setFocusedId] = useState(null);
|
|
134
|
+
const [keyedId, setKeyedId] = useState(null);
|
|
135
|
+
const [movingTo, setMovingTo] = useState(null);
|
|
136
|
+
const movingRef = useRef(null);
|
|
137
|
+
// A layout the camera has not drawn yet. Its set comes from the camera on
|
|
138
|
+
// screen, and the camera's own effect replaces it once it has placed the
|
|
139
|
+
// new layout.
|
|
140
|
+
const pending = shown.index !== index;
|
|
141
|
+
const pendingCenter = useMemo(() => {
|
|
142
|
+
if (!pending)
|
|
143
|
+
return null;
|
|
144
|
+
const camera = lastCameraRef.current;
|
|
145
|
+
const viewport = lastViewportRef.current;
|
|
146
|
+
return camera === null || viewport === null ? null : nearestToCenter(index, camera, viewport);
|
|
147
|
+
}, [pending, index]);
|
|
148
|
+
const center = pending ? pendingCenter : shown.center;
|
|
149
|
+
const has = (id) => id !== null && layout.boxes.has(id);
|
|
150
|
+
const tabTarget = has(selectedId)
|
|
151
|
+
? selectedId
|
|
152
|
+
: has(keyedId)
|
|
153
|
+
? keyedId
|
|
154
|
+
: (center ?? index.nodeIds[0] ?? null);
|
|
155
|
+
// The options, keyed by value, so a caller that re-creates `pinned` or
|
|
156
|
+
// `tiers` on every render does not recompute the set on every render.
|
|
157
|
+
const summary = tiers?.summary;
|
|
158
|
+
const rich = tiers?.rich;
|
|
159
|
+
const cap = usable(maxOverlayNodes) ? Math.floor(maxOverlayNodes) : DEFAULT_MAX_OVERLAY_NODES;
|
|
160
|
+
const pins = [...(pinned ?? [])];
|
|
161
|
+
for (const id of [selectedId, tabTarget, focusedId, movingTo]) {
|
|
162
|
+
if (has(id) && !pins.includes(id))
|
|
163
|
+
pins.push(id);
|
|
164
|
+
}
|
|
165
|
+
const pinKey = JSON.stringify(pins);
|
|
166
|
+
const options = useMemo(() => ({
|
|
167
|
+
tiers: tiersOf(summary, rich),
|
|
168
|
+
maxOverlayNodes: cap,
|
|
169
|
+
pinned: JSON.parse(pinKey),
|
|
170
|
+
}), [summary, rich, cap, pinKey]);
|
|
171
|
+
/**
|
|
172
|
+
* Brings the visible set up to date with a camera, scanning only when it
|
|
173
|
+
* can have changed. The node nearest the center is found at the same scan,
|
|
174
|
+
* so between scans it can trail the camera by up to half the overscan.
|
|
175
|
+
*/
|
|
176
|
+
const refresh = useCallback((camera, viewport) => {
|
|
177
|
+
const world = visibleWorld(camera, viewport);
|
|
178
|
+
const scan = scanRef.current;
|
|
179
|
+
if (scan !== null &&
|
|
180
|
+
scan.index === index &&
|
|
181
|
+
scan.options === options &&
|
|
182
|
+
scan.scale === camera.scale &&
|
|
183
|
+
inside(world, scan.within)) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
const next = computeVisibleSet(index, camera, viewport, options);
|
|
187
|
+
scanRef.current = { index, options, scale: camera.scale, within: slack(world) };
|
|
188
|
+
const center = nearestToCenter(index, camera, viewport);
|
|
189
|
+
const previous = shownRef.current;
|
|
190
|
+
if (previous.index === index && previous.center === center && sameVisibleSet(previous.set, next))
|
|
191
|
+
return;
|
|
192
|
+
const value = { index, set: next, center };
|
|
193
|
+
shownRef.current = value;
|
|
194
|
+
setShown(value);
|
|
195
|
+
}, [index, options]);
|
|
196
|
+
const onFrame = useCallback((camera, viewport) => {
|
|
197
|
+
lastViewportRef.current = viewport;
|
|
198
|
+
lastCameraRef.current = camera;
|
|
199
|
+
// First, so a base that draws its own camera moves in step with the plane.
|
|
200
|
+
for (const listener of [...listeners])
|
|
201
|
+
listener(camera);
|
|
202
|
+
refresh(camera, viewport);
|
|
203
|
+
}, [refresh, listeners]);
|
|
204
|
+
const controls = useExplorerCamera({ viewportRef, planeRef, layout, onFrame });
|
|
205
|
+
const cameraSource = useMemo(() => ({
|
|
206
|
+
get: () => controls.getCamera(),
|
|
207
|
+
subscribe(listener) {
|
|
208
|
+
// Wrapped, so one listener subscribed twice is two subscriptions,
|
|
209
|
+
// each ended by its own unsubscribe.
|
|
210
|
+
const own = (camera) => listener(camera);
|
|
211
|
+
listeners.add(own);
|
|
212
|
+
return () => {
|
|
213
|
+
listeners.delete(own);
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
}), [controls, listeners]);
|
|
217
|
+
// A prop that changes the set without moving the camera: pins, tiers, the
|
|
218
|
+
// cap. The camera's own effects have run by now, so a new layout has
|
|
219
|
+
// already been placed and drawn through the new `onFrame`, and this finds
|
|
220
|
+
// nothing to change. No frame was drawn, so the base's listeners hear
|
|
221
|
+
// nothing.
|
|
222
|
+
useEffect(() => {
|
|
223
|
+
const camera = controls.getCamera();
|
|
224
|
+
const viewport = lastViewportRef.current;
|
|
225
|
+
if (camera !== null && viewport !== null)
|
|
226
|
+
refresh(camera, viewport);
|
|
227
|
+
}, [controls, refresh]);
|
|
228
|
+
useEffect(() => {
|
|
229
|
+
if (controlsRef === undefined)
|
|
230
|
+
return undefined;
|
|
231
|
+
controlsRef.current = controls;
|
|
232
|
+
return () => {
|
|
233
|
+
if (controlsRef.current === controls)
|
|
234
|
+
controlsRef.current = null;
|
|
235
|
+
};
|
|
236
|
+
}, [controls, controlsRef]);
|
|
237
|
+
useEffect(() => {
|
|
238
|
+
if (cameraSourceRef === undefined)
|
|
239
|
+
return undefined;
|
|
240
|
+
cameraSourceRef.current = cameraSource;
|
|
241
|
+
return () => {
|
|
242
|
+
if (cameraSourceRef.current === cameraSource)
|
|
243
|
+
cameraSourceRef.current = null;
|
|
244
|
+
};
|
|
245
|
+
}, [cameraSource, cameraSourceRef]);
|
|
246
|
+
// The click handlers read the latest props through a ref, so the listeners
|
|
247
|
+
// are attached once per viewport and not on every render.
|
|
248
|
+
const latest = useRef({ index, onNodeActivate, onNodeZoom });
|
|
249
|
+
useEffect(() => {
|
|
250
|
+
latest.current = { index, onNodeActivate, onNodeZoom };
|
|
251
|
+
});
|
|
252
|
+
useEffect(() => {
|
|
253
|
+
const viewport = viewportRef.current;
|
|
254
|
+
if (viewport === null)
|
|
255
|
+
return undefined;
|
|
256
|
+
const resolve = (event) => {
|
|
257
|
+
if (event.target instanceof Element) {
|
|
258
|
+
const node = event.target.closest(NODE);
|
|
259
|
+
const id = node instanceof HTMLElement ? node.dataset['nodeId'] : undefined;
|
|
260
|
+
if (node instanceof HTMLElement && id !== undefined && viewport.contains(node)) {
|
|
261
|
+
return { id, trigger: node };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const box = viewport.getBoundingClientRect();
|
|
265
|
+
const world = controls.screenToWorld({
|
|
266
|
+
x: event.clientX - box.left - viewport.clientLeft,
|
|
267
|
+
y: event.clientY - box.top - viewport.clientTop,
|
|
268
|
+
});
|
|
269
|
+
if (world === null)
|
|
270
|
+
return null;
|
|
271
|
+
const id = nodeAtPoint(latest.current.index, world);
|
|
272
|
+
return id === null ? null : { id, trigger: null };
|
|
273
|
+
};
|
|
274
|
+
const onClick = (event) => {
|
|
275
|
+
const hit = resolve(event);
|
|
276
|
+
if (hit === null) {
|
|
277
|
+
if (!viewport.contains(document.activeElement))
|
|
278
|
+
viewport.focus({ preventScroll: true });
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
latest.current.onNodeActivate?.(hit.id, hit.trigger);
|
|
282
|
+
};
|
|
283
|
+
const onDoubleClick = (event) => {
|
|
284
|
+
const hit = resolve(event);
|
|
285
|
+
if (hit !== null)
|
|
286
|
+
latest.current.onNodeZoom?.(hit.id);
|
|
287
|
+
};
|
|
288
|
+
viewport.addEventListener('click', onClick);
|
|
289
|
+
viewport.addEventListener('dblclick', onDoubleClick);
|
|
290
|
+
return () => {
|
|
291
|
+
viewport.removeEventListener('click', onClick);
|
|
292
|
+
viewport.removeEventListener('dblclick', onDoubleClick);
|
|
293
|
+
};
|
|
294
|
+
}, [controls]);
|
|
295
|
+
// Keys and focus. Whether a focus came from the keyboard is whether the
|
|
296
|
+
// last input anywhere on the page was a key, heard in the capture phase on
|
|
297
|
+
// the document, so a Tab pressed outside the graph counts.
|
|
298
|
+
useEffect(() => {
|
|
299
|
+
const viewport = viewportRef.current;
|
|
300
|
+
if (viewport === null)
|
|
301
|
+
return undefined;
|
|
302
|
+
const doc = viewport.ownerDocument;
|
|
303
|
+
let keyed = false;
|
|
304
|
+
const onAnyKey = () => {
|
|
305
|
+
keyed = true;
|
|
306
|
+
};
|
|
307
|
+
const onAnyPointer = () => {
|
|
308
|
+
keyed = false;
|
|
309
|
+
};
|
|
310
|
+
const nodeOf = (target) => {
|
|
311
|
+
if (!(target instanceof Element))
|
|
312
|
+
return null;
|
|
313
|
+
const element = target.closest(NODE);
|
|
314
|
+
const id = element instanceof HTMLElement ? element.dataset['nodeId'] : undefined;
|
|
315
|
+
return element instanceof HTMLElement && id !== undefined && viewport.contains(element) ? { id, element } : null;
|
|
316
|
+
};
|
|
317
|
+
// Set only on a change, so focus moving about the graph costs no render
|
|
318
|
+
// when the pins it decides are the same.
|
|
319
|
+
let focused = null;
|
|
320
|
+
let lastKeyed = null;
|
|
321
|
+
const focus = (id) => {
|
|
322
|
+
if (id === focused)
|
|
323
|
+
return;
|
|
324
|
+
focused = id;
|
|
325
|
+
setFocusedId(id);
|
|
326
|
+
};
|
|
327
|
+
const onFocusIn = (event) => {
|
|
328
|
+
const hit = nodeOf(event.target);
|
|
329
|
+
focus(hit === null ? null : hit.id);
|
|
330
|
+
if (hit === null || !keyed)
|
|
331
|
+
return;
|
|
332
|
+
if (hit.id !== lastKeyed) {
|
|
333
|
+
lastKeyed = hit.id;
|
|
334
|
+
setKeyedId(hit.id);
|
|
335
|
+
}
|
|
336
|
+
const { index: current } = latest.current;
|
|
337
|
+
const box = current.nodeBoxes[current.nodeIds.indexOf(hit.id)];
|
|
338
|
+
if (box !== undefined)
|
|
339
|
+
controls.revealBox(box);
|
|
340
|
+
};
|
|
341
|
+
const onFocusOut = (event) => {
|
|
342
|
+
if (nodeOf(event.relatedTarget) === null)
|
|
343
|
+
focus(null);
|
|
344
|
+
};
|
|
345
|
+
const onKeyDown = (event) => {
|
|
346
|
+
// Modified keys are the browser's, and a key the camera took is taken.
|
|
347
|
+
if (event.defaultPrevented || event.ctrlKey || event.metaKey || event.altKey)
|
|
348
|
+
return;
|
|
349
|
+
const hit = nodeOf(event.target);
|
|
350
|
+
// Keys typed into content a host renders inside a node are the host's.
|
|
351
|
+
if (hit === null || event.target !== hit.element)
|
|
352
|
+
return;
|
|
353
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
354
|
+
// Handled here rather than left to the button's own click, so a key
|
|
355
|
+
// inspects exactly once and a held key inspects once.
|
|
356
|
+
event.preventDefault();
|
|
357
|
+
if (!event.repeat)
|
|
358
|
+
latest.current.onNodeActivate?.(hit.id, hit.element);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
const direction = ARROWS[event.key];
|
|
362
|
+
// Shift with an arrow pans, which the camera does.
|
|
363
|
+
if (direction === undefined || event.shiftKey)
|
|
364
|
+
return;
|
|
365
|
+
event.preventDefault();
|
|
366
|
+
const next = nearestInDirection(latest.current.index, hit.id, direction);
|
|
367
|
+
if (next === null)
|
|
368
|
+
return;
|
|
369
|
+
movingRef.current = next;
|
|
370
|
+
setMovingTo(next);
|
|
371
|
+
};
|
|
372
|
+
// A button fires its Space click on keyup, and Firefox has not always
|
|
373
|
+
// cancelled that click when only keydown was prevented. Keydown has
|
|
374
|
+
// already activated, so the keyup is prevented too.
|
|
375
|
+
const onKeyUp = (event) => {
|
|
376
|
+
if (event.key !== ' ')
|
|
377
|
+
return;
|
|
378
|
+
const hit = nodeOf(event.target);
|
|
379
|
+
if (hit !== null && event.target === hit.element)
|
|
380
|
+
event.preventDefault();
|
|
381
|
+
};
|
|
382
|
+
// The viewport clips and never scrolls. A browser scrolls it anyway to
|
|
383
|
+
// show a node that takes focus from Tab, which would offset everything
|
|
384
|
+
// from the camera, so any scroll is put back.
|
|
385
|
+
const onScroll = () => {
|
|
386
|
+
if (viewport.scrollTop !== 0)
|
|
387
|
+
viewport.scrollTop = 0;
|
|
388
|
+
if (viewport.scrollLeft !== 0)
|
|
389
|
+
viewport.scrollLeft = 0;
|
|
390
|
+
};
|
|
391
|
+
doc.addEventListener('keydown', onAnyKey, true);
|
|
392
|
+
doc.addEventListener('pointerdown', onAnyPointer, true);
|
|
393
|
+
doc.addEventListener('mousedown', onAnyPointer, true);
|
|
394
|
+
viewport.addEventListener('focusin', onFocusIn);
|
|
395
|
+
viewport.addEventListener('focusout', onFocusOut);
|
|
396
|
+
viewport.addEventListener('keydown', onKeyDown);
|
|
397
|
+
viewport.addEventListener('keyup', onKeyUp);
|
|
398
|
+
viewport.addEventListener('scroll', onScroll);
|
|
399
|
+
return () => {
|
|
400
|
+
doc.removeEventListener('keydown', onAnyKey, true);
|
|
401
|
+
doc.removeEventListener('pointerdown', onAnyPointer, true);
|
|
402
|
+
doc.removeEventListener('mousedown', onAnyPointer, true);
|
|
403
|
+
viewport.removeEventListener('focusin', onFocusIn);
|
|
404
|
+
viewport.removeEventListener('focusout', onFocusOut);
|
|
405
|
+
viewport.removeEventListener('keydown', onKeyDown);
|
|
406
|
+
viewport.removeEventListener('keyup', onKeyUp);
|
|
407
|
+
viewport.removeEventListener('scroll', onScroll);
|
|
408
|
+
};
|
|
409
|
+
}, [controls]);
|
|
410
|
+
// An arrow's target takes focus in the first commit that mounts it. The
|
|
411
|
+
// node it leaves stays pinned, because it still has focus, until then.
|
|
412
|
+
useIsomorphicLayoutEffect(() => {
|
|
413
|
+
const want = movingRef.current;
|
|
414
|
+
const viewport = viewportRef.current;
|
|
415
|
+
if (want === null || viewport === null)
|
|
416
|
+
return;
|
|
417
|
+
if (!layout.boxes.has(want) || !viewport.contains(viewport.ownerDocument.activeElement)) {
|
|
418
|
+
// Gone from the data, or focus left the graph while it mounted.
|
|
419
|
+
movingRef.current = null;
|
|
420
|
+
setMovingTo(null);
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
const element = nodeButton(viewport, want);
|
|
424
|
+
if (element === null)
|
|
425
|
+
return;
|
|
426
|
+
movingRef.current = null;
|
|
427
|
+
element.focus({ preventScroll: true });
|
|
428
|
+
setMovingTo(null);
|
|
429
|
+
});
|
|
430
|
+
const first = useMemo(() => {
|
|
431
|
+
if (!pending)
|
|
432
|
+
return null;
|
|
433
|
+
const camera = controls.getCamera();
|
|
434
|
+
const viewport = lastViewportRef.current;
|
|
435
|
+
return camera === null || viewport === null
|
|
436
|
+
? everythingAsMarks(index)
|
|
437
|
+
: computeVisibleSet(index, camera, viewport, options);
|
|
438
|
+
}, [pending, controls, index, options]);
|
|
439
|
+
const visible = first ?? shown.set;
|
|
440
|
+
const emphasis = useMemo(() => ({ selectedId, dimmed }), [selectedId, dimmed]);
|
|
441
|
+
const nodes = useMemo(() => new Map(view.nodes.map((node) => [node.id, node])), [view.nodes]);
|
|
442
|
+
const groupsOf = useMemo(() => {
|
|
443
|
+
const map = new Map();
|
|
444
|
+
for (const group of view.groups ?? []) {
|
|
445
|
+
for (const id of new Set(group.nodeIds)) {
|
|
446
|
+
const list = map.get(id);
|
|
447
|
+
if (list === undefined)
|
|
448
|
+
map.set(id, [group]);
|
|
449
|
+
else
|
|
450
|
+
list.push(group);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return map;
|
|
454
|
+
}, [view.groups]);
|
|
455
|
+
const overlay = [];
|
|
456
|
+
for (const [id, tier] of visible.overlay) {
|
|
457
|
+
const node = nodes.get(id);
|
|
458
|
+
const box = layout.boxes.get(id);
|
|
459
|
+
if (node === undefined || box === undefined)
|
|
460
|
+
continue;
|
|
461
|
+
const selected = id === selectedId;
|
|
462
|
+
const isDimmed = dimmed.has(id);
|
|
463
|
+
const groups = groupsOf.get(id) ?? NO_GROUPS;
|
|
464
|
+
overlay.push(_jsx("button", { type: "button", tabIndex: id === tabTarget ? 0 : -1, "data-dagr-explorer": "node", "data-node-id": id, "data-tier": tier, "data-selected": selected ? 'true' : undefined, "data-dimmed": isDimmed ? 'true' : undefined, "aria-pressed": selected, "aria-label": nodeAriaLabel === undefined ? defaultName(node, groups, inGroup) : nodeAriaLabel(node, { groups }), style: { position: 'absolute', left: box.x, top: box.y, width: box.width, height: box.height }, children: renderNode === undefined ? node.label : renderNode(node, { tier, selected, dimmed: isDimmed }) }, id));
|
|
465
|
+
}
|
|
466
|
+
const Layer = base.Layer;
|
|
467
|
+
const layer = (_jsx(Layer, { view: view, layout: layout, visible: visible, emphasis: emphasis, camera: cameraSource }));
|
|
468
|
+
return (_jsxs("div", { ref: viewportRef, "data-dagr-explorer": "viewport", role: "region", "aria-label": label, "aria-describedby": describedBy, tabIndex: -1, className: className, style: {
|
|
469
|
+
height: 'var(--dagr-explorer-height, 480px)',
|
|
470
|
+
...style,
|
|
471
|
+
// Last, so a caller cannot break the graph: the plane and the nodes
|
|
472
|
+
// are absolutely positioned against this element and clipped by it.
|
|
473
|
+
position: 'relative',
|
|
474
|
+
overflow: 'hidden',
|
|
475
|
+
}, children: [base.space === 'viewport' ? layer : null, _jsxs("div", { ref: planeRef, "data-dagr-explorer": "plane", style: {
|
|
476
|
+
position: 'absolute',
|
|
477
|
+
left: 0,
|
|
478
|
+
top: 0,
|
|
479
|
+
width: layout.width,
|
|
480
|
+
height: layout.height,
|
|
481
|
+
transformOrigin: '0 0',
|
|
482
|
+
visibility: 'hidden',
|
|
483
|
+
}, children: [base.space === 'plane' ? layer : null, overlay] })] }));
|
|
484
|
+
}
|
|
485
|
+
//# sourceMappingURL=viewport-surface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viewport-surface.js","sourceRoot":"","sources":["../src/viewport-surface.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which nodes get a DOM element, which are left to the base layer, and which
|
|
3
|
+
* edges are in view: the explorer's virtualization, as one pure function.
|
|
4
|
+
*
|
|
5
|
+
* A node's tier comes from its width on screen in CSS pixels, with half-open
|
|
6
|
+
* gates, the rule `@prnt/dagr-render`'s rich nodes use. Below the `summary`
|
|
7
|
+
* gate it is a mark and has NO element: the base layer draws it.
|
|
8
|
+
*
|
|
9
|
+
* **The scan is linear on purpose.** Testing 10,000 boxes costs about half a
|
|
10
|
+
* millisecond per call (0.4 to 0.6 ms measured in `packages/explorer/bench`,
|
|
11
|
+
* the output lists included), well inside a 16 ms frame. The renderer's overlay scans the same way and names a spatial
|
|
12
|
+
* index as the fix if a measurement ever asks for one.
|
|
13
|
+
*
|
|
14
|
+
* Internal to the package. Only the tier types and `ExplorerVisibleSet` are
|
|
15
|
+
* exported from the entry, as types: a base layer is given a visible set.
|
|
16
|
+
*/
|
|
17
|
+
import type { ExplorerBox, ExplorerLayout } from './layout.js';
|
|
18
|
+
import type { Vec2 } from '@prnt/dagr-render/core';
|
|
19
|
+
import type { ExplorerCamera, ExplorerViewportSize } from './camera.js';
|
|
20
|
+
export type ExplorerTier = 'summary' | 'rich';
|
|
21
|
+
export interface ExplorerTiers {
|
|
22
|
+
readonly summary: number;
|
|
23
|
+
readonly rich: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const DEFAULT_TIERS: ExplorerTiers;
|
|
26
|
+
export declare const DEFAULT_MAX_OVERLAY_NODES = 200;
|
|
27
|
+
export declare const OVERSCAN = 0.25;
|
|
28
|
+
export interface LayoutIndex {
|
|
29
|
+
readonly nodeIds: readonly string[];
|
|
30
|
+
readonly nodeBoxes: readonly ExplorerBox[];
|
|
31
|
+
readonly edgeIds: readonly string[];
|
|
32
|
+
/** `null` for an edge with no route, which is never in view. */
|
|
33
|
+
readonly edgeBounds: readonly (ExplorerBox | null)[];
|
|
34
|
+
}
|
|
35
|
+
export declare function indexLayout(layout: ExplorerLayout): LayoutIndex;
|
|
36
|
+
export interface VisibleSetOptions {
|
|
37
|
+
readonly tiers?: ExplorerTiers | undefined;
|
|
38
|
+
readonly maxOverlayNodes?: number | undefined;
|
|
39
|
+
/** Node ids that are always overlay nodes, exempt from the cap. */
|
|
40
|
+
readonly pinned?: readonly string[] | undefined;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* What is in view: the nodes with an element, the nodes and edges a base
|
|
44
|
+
* layer draws. Exported as a type, and experimental like the base-layer seam
|
|
45
|
+
* that is given it: it may change until a native base confirms it.
|
|
46
|
+
*/
|
|
47
|
+
export interface ExplorerVisibleSet {
|
|
48
|
+
/** Overlay nodes and their tier, in data order. */
|
|
49
|
+
readonly overlay: ReadonlyMap<string, ExplorerTier>;
|
|
50
|
+
/** Nodes in view that the base layer draws as marks, in data order. */
|
|
51
|
+
readonly baseNodes: readonly string[];
|
|
52
|
+
/** Edges whose route is in view, in data order. */
|
|
53
|
+
readonly edges: readonly string[];
|
|
54
|
+
}
|
|
55
|
+
export declare function computeVisibleSet(index: LayoutIndex, camera: ExplorerCamera, viewport: ExplorerViewportSize, options?: VisibleSetOptions): ExplorerVisibleSet;
|
|
56
|
+
/**
|
|
57
|
+
* Whether two sets hold the same nodes at the same tiers, and the same marks
|
|
58
|
+
* and edges in the same order. Overlay order is not compared:
|
|
59
|
+
* `computeVisibleSet` always emits the overlay in the index's data order, so
|
|
60
|
+
* two sets over one index cannot differ in order alone.
|
|
61
|
+
*/
|
|
62
|
+
export declare function sameVisibleSet(a: ExplorerVisibleSet, b: ExplorerVisibleSet): boolean;
|
|
63
|
+
export declare function nearestToCenter(index: LayoutIndex, camera: ExplorerCamera, viewport: ExplorerViewportSize): string | null;
|
|
64
|
+
export declare function nodeAtPoint(index: LayoutIndex, point: Vec2): string | null;
|
|
65
|
+
//# sourceMappingURL=visible-set.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"visible-set.d.ts","sourceRoot":"","sources":["../src/visible-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAEnD,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAExE,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,MAAM,CAAC;AAC9C,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AACD,eAAO,MAAM,aAAa,EAAE,aAAyD,CAAC;AACtF,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAC7C,eAAO,MAAM,QAAQ,OAAO,CAAC;AAE7B,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,SAAS,EAAE,SAAS,WAAW,EAAE,CAAC;IAC3C,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,gEAAgE;IAChE,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,CAAC;CACtD;AAED,wBAAgB,WAAW,CAAC,MAAM,EAAE,cAAc,GAAG,WAAW,CA2B/D;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CACjD;AAED;;;;GAIG;AACH,MAAM,WAAW,kBAAkB;IACjC,mDAAmD;IACnD,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACpD,uEAAuE;IACvE,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,mDAAmD;IACnD,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAYD,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,iBAAsB,GAC9B,kBAAkB,CAuDpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,kBAAkB,EAAE,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAmBpF;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,oBAAoB,GAC7B,MAAM,GAAG,IAAI,CAiBf;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,IAAI,CAa1E"}
|