@graview/react 0.1.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/LICENSE +96 -0
- package/README.md +20 -0
- package/dist/activity.d.ts +113 -0
- package/dist/activity.d.ts.map +1 -0
- package/dist/activity.js +207 -0
- package/dist/activity.js.map +1 -0
- package/dist/animation.d.ts +64 -0
- package/dist/animation.d.ts.map +1 -0
- package/dist/animation.js +245 -0
- package/dist/animation.js.map +1 -0
- package/dist/captions.d.ts +43 -0
- package/dist/captions.d.ts.map +1 -0
- package/dist/captions.js +61 -0
- package/dist/captions.js.map +1 -0
- package/dist/channels.d.ts +15 -0
- package/dist/channels.d.ts.map +1 -0
- package/dist/channels.js +114 -0
- package/dist/channels.js.map +1 -0
- package/dist/connectors.d.ts +176 -0
- package/dist/connectors.d.ts.map +1 -0
- package/dist/connectors.js +837 -0
- package/dist/connectors.js.map +1 -0
- package/dist/context.d.ts +348 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +568 -0
- package/dist/context.js.map +1 -0
- package/dist/drawn.d.ts +60 -0
- package/dist/drawn.d.ts.map +1 -0
- package/dist/drawn.js +58 -0
- package/dist/drawn.js.map +1 -0
- package/dist/edge-signs.d.ts +13 -0
- package/dist/edge-signs.d.ts.map +1 -0
- package/dist/edge-signs.js +76 -0
- package/dist/edge-signs.js.map +1 -0
- package/dist/hooks.d.ts +160 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +457 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/keyboard.d.ts +5 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +178 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/kit.d.ts +10 -0
- package/dist/kit.d.ts.map +1 -0
- package/dist/kit.js +32 -0
- package/dist/kit.js.map +1 -0
- package/dist/local-intelligence.d.ts +31 -0
- package/dist/local-intelligence.d.ts.map +1 -0
- package/dist/local-intelligence.js +66 -0
- package/dist/local-intelligence.js.map +1 -0
- package/dist/motion.d.ts +17 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +26 -0
- package/dist/motion.js.map +1 -0
- package/dist/occupants.d.ts +45 -0
- package/dist/occupants.d.ts.map +1 -0
- package/dist/occupants.js +57 -0
- package/dist/occupants.js.map +1 -0
- package/dist/parallel.d.ts +19 -0
- package/dist/parallel.d.ts.map +1 -0
- package/dist/parallel.js +30 -0
- package/dist/parallel.js.map +1 -0
- package/dist/picking.d.ts +30 -0
- package/dist/picking.d.ts.map +1 -0
- package/dist/picking.js +140 -0
- package/dist/picking.js.map +1 -0
- package/dist/plots.d.ts +106 -0
- package/dist/plots.d.ts.map +1 -0
- package/dist/plots.js +306 -0
- package/dist/plots.js.map +1 -0
- package/dist/pointer.d.ts +27 -0
- package/dist/pointer.d.ts.map +1 -0
- package/dist/pointer.js +39 -0
- package/dist/pointer.js.map +1 -0
- package/dist/presence.d.ts +110 -0
- package/dist/presence.d.ts.map +1 -0
- package/dist/presence.js +280 -0
- package/dist/presence.js.map +1 -0
- package/dist/rails.d.ts +11 -0
- package/dist/rails.d.ts.map +1 -0
- package/dist/rails.js +15 -0
- package/dist/rails.js.map +1 -0
- package/dist/resolved-view.d.ts +78 -0
- package/dist/resolved-view.d.ts.map +1 -0
- package/dist/resolved-view.js +365 -0
- package/dist/resolved-view.js.map +1 -0
- package/dist/robot.d.ts +114 -0
- package/dist/robot.d.ts.map +1 -0
- package/dist/robot.js +93 -0
- package/dist/robot.js.map +1 -0
- package/dist/routes.d.ts +50 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +150 -0
- package/dist/routes.js.map +1 -0
- package/dist/scene-camera.d.ts +25 -0
- package/dist/scene-camera.d.ts.map +1 -0
- package/dist/scene-camera.js +130 -0
- package/dist/scene-camera.js.map +1 -0
- package/dist/scene-hand.d.ts +110 -0
- package/dist/scene-hand.d.ts.map +1 -0
- package/dist/scene-hand.js +317 -0
- package/dist/scene-hand.js.map +1 -0
- package/dist/scene-helpers.d.ts +46 -0
- package/dist/scene-helpers.d.ts.map +1 -0
- package/dist/scene-helpers.js +108 -0
- package/dist/scene-helpers.js.map +1 -0
- package/dist/scene-lines.d.ts +76 -0
- package/dist/scene-lines.d.ts.map +1 -0
- package/dist/scene-lines.js +578 -0
- package/dist/scene-lines.js.map +1 -0
- package/dist/scene-root.d.ts +71 -0
- package/dist/scene-root.d.ts.map +1 -0
- package/dist/scene-root.js +790 -0
- package/dist/scene-root.js.map +1 -0
- package/dist/scene.d.ts +17 -0
- package/dist/scene.d.ts.map +1 -0
- package/dist/scene.js +17 -0
- package/dist/scene.js.map +1 -0
- package/dist/seat-marks.d.ts +35 -0
- package/dist/seat-marks.d.ts.map +1 -0
- package/dist/seat-marks.js +43 -0
- package/dist/seat-marks.js.map +1 -0
- package/dist/settings.d.ts +30 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +73 -0
- package/dist/settings.js.map +1 -0
- package/dist/view-boundary.d.ts +33 -0
- package/dist/view-boundary.d.ts.map +1 -0
- package/dist/view-boundary.js +53 -0
- package/dist/view-boundary.js.map +1 -0
- package/dist/view-host.d.ts +57 -0
- package/dist/view-host.d.ts.map +1 -0
- package/dist/view-host.js +474 -0
- package/dist/view-host.js.map +1 -0
- package/dist/view-registry.d.ts +122 -0
- package/dist/view-registry.d.ts.map +1 -0
- package/dist/view-registry.js +20 -0
- package/dist/view-registry.js.map +1 -0
- package/dist/where-drawn.d.ts +151 -0
- package/dist/where-drawn.d.ts.map +1 -0
- package/dist/where-drawn.js +231 -0
- package/dist/where-drawn.js.map +1 -0
- package/package.json +60 -0
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import { easeInOut, interpolate, } from "@graview/layout";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useGraview } from "./context.js";
|
|
4
|
+
const DEFAULT_DURATION = 520;
|
|
5
|
+
function prefersReducedMotion() {
|
|
6
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
7
|
+
return false;
|
|
8
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Tweens between two layouts whenever the view changes.
|
|
12
|
+
*
|
|
13
|
+
* This is the pay-off for layout being a pure function: there is no list of
|
|
14
|
+
* known transitions and no per-navigation animation code. ANY two view states
|
|
15
|
+
* interpolate, so a kind of navigation nobody anticipated animates the same
|
|
16
|
+
* as the ones that were designed — and a node entering the scene grows out of
|
|
17
|
+
* whatever group stood in for it, because the interpolation knows where it
|
|
18
|
+
* came from.
|
|
19
|
+
*
|
|
20
|
+
* Motion is the one thing that makes depth legible. Without it, a plane
|
|
21
|
+
* change is a cut and the viewer has to re-find everything; with it, the eye
|
|
22
|
+
* follows and spatial memory survives the move.
|
|
23
|
+
*/
|
|
24
|
+
export function useAnimatedLayout(target, options = {}) {
|
|
25
|
+
const duration = options.duration ?? DEFAULT_DURATION;
|
|
26
|
+
const enabled = (options.enabled ?? true) && !prefersReducedMotion();
|
|
27
|
+
const from = useRef(target);
|
|
28
|
+
const [current, setCurrent] = useState(() => interpolate(target, target, 1));
|
|
29
|
+
// The LIVE frame, kept in a ref.
|
|
30
|
+
//
|
|
31
|
+
// The effect below is not re-created on the frames it itself causes, so a
|
|
32
|
+
// cleanup closing over `current` sees the frame from when the effect
|
|
33
|
+
// started — which made an interrupted transition resume from where the
|
|
34
|
+
// previous one began, and made every navigation after the first jump back
|
|
35
|
+
// two states before animating forward.
|
|
36
|
+
const latest = useRef(current);
|
|
37
|
+
const frame = useRef(null);
|
|
38
|
+
/*
|
|
39
|
+
* WHEN THIS FLIGHT BEGAN, kept across restarts. A new target arriving
|
|
40
|
+
* mid-flight — the camera re-centring a frame after a click, a host
|
|
41
|
+
* reporting a size, a wheel's worth of events — used to start a fresh
|
|
42
|
+
* tween from the live frame with the whole duration and the ease-in from
|
|
43
|
+
* zero, so a stream of them moved the scene a hair a frame and never
|
|
44
|
+
* arrived: a crawl. The clock belongs to the flight, not the target: a
|
|
45
|
+
* restart tweens from the live frame to the new target over what is LEFT,
|
|
46
|
+
* picking the easing up at the velocity it already had.
|
|
47
|
+
*/
|
|
48
|
+
const clock = useRef(null);
|
|
49
|
+
useEffect(() => {
|
|
50
|
+
if (!enabled || typeof requestAnimationFrame === "undefined") {
|
|
51
|
+
from.current = target;
|
|
52
|
+
const settled = interpolate(target, target, 1);
|
|
53
|
+
latest.current = settled;
|
|
54
|
+
setCurrent(settled);
|
|
55
|
+
/*
|
|
56
|
+
* The same settle tick the tween gets, for the cut.
|
|
57
|
+
*
|
|
58
|
+
* With motion off — reduced-motion, a test, a drag that owns the
|
|
59
|
+
* pointer — the render that draws the new layout still measures the
|
|
60
|
+
* PREVIOUS commit's DOM, so every measured line sat one navigation
|
|
61
|
+
* behind the cards until something else happened to re-render. One
|
|
62
|
+
* more render on the next frame reads the settled geometry.
|
|
63
|
+
*/
|
|
64
|
+
if (typeof requestAnimationFrame === "undefined")
|
|
65
|
+
return;
|
|
66
|
+
const tick = requestAnimationFrame(() => {
|
|
67
|
+
const again = interpolate(target, target, 1);
|
|
68
|
+
latest.current = again;
|
|
69
|
+
setCurrent(again);
|
|
70
|
+
});
|
|
71
|
+
return () => cancelAnimationFrame(tick);
|
|
72
|
+
}
|
|
73
|
+
// Tween from wherever the scene actually IS, not from the last target:
|
|
74
|
+
// interrupting a transition half way must not snap back to its start.
|
|
75
|
+
const now = performance.now();
|
|
76
|
+
const inFlight = clock.current !== null && latest.current.t < 1 && now - clock.current < duration;
|
|
77
|
+
const start = inFlight ? clock.current : now;
|
|
78
|
+
clock.current = start;
|
|
79
|
+
// Where the easing already is, so the rest of the flight continues from
|
|
80
|
+
// that point on the curve rather than easing in again from a standstill.
|
|
81
|
+
const alreadyEased = easeInOut(Math.min(1, (now - start) / duration));
|
|
82
|
+
const origin = from.current;
|
|
83
|
+
const step = (at) => {
|
|
84
|
+
const t = Math.min(1, (at - start) / duration);
|
|
85
|
+
const eased = alreadyEased >= 1 ? 1 : (easeInOut(t) - alreadyEased) / (1 - alreadyEased);
|
|
86
|
+
const next = interpolate(origin, target, Math.max(0, eased));
|
|
87
|
+
latest.current = next;
|
|
88
|
+
setCurrent(next);
|
|
89
|
+
if (t < 1) {
|
|
90
|
+
frame.current = requestAnimationFrame(step);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
clock.current = null;
|
|
94
|
+
from.current = target;
|
|
95
|
+
/*
|
|
96
|
+
* ONE SETTLE TICK after the last frame has painted.
|
|
97
|
+
*
|
|
98
|
+
* Anything that measures the DOM during render — connectors, ties,
|
|
99
|
+
* captions — reads the PREVIOUS commit's geometry, so the render
|
|
100
|
+
* that draws t = 1 measures wherever the scene was a frame earlier.
|
|
101
|
+
* On a smooth tween that is a fraction of a percent; across a
|
|
102
|
+
* dropped frame it is a visible stray line frozen in mid-air. A
|
|
103
|
+
* final render on the next frame measures the settled DOM, and a
|
|
104
|
+
* fresh object identity is what makes React run it.
|
|
105
|
+
*/
|
|
106
|
+
frame.current = requestAnimationFrame(() => {
|
|
107
|
+
const settled = interpolate(target, target, 1);
|
|
108
|
+
latest.current = settled;
|
|
109
|
+
setCurrent(settled);
|
|
110
|
+
frame.current = null;
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
frame.current = requestAnimationFrame(step);
|
|
115
|
+
return () => {
|
|
116
|
+
if (frame.current !== null)
|
|
117
|
+
cancelAnimationFrame(frame.current);
|
|
118
|
+
// Freeze where the interruption caught it, so the next tween starts
|
|
119
|
+
// here — from the live frame, not the one this effect began with.
|
|
120
|
+
const live = latest.current;
|
|
121
|
+
from.current = {
|
|
122
|
+
...target,
|
|
123
|
+
/*
|
|
124
|
+
* INCLUDING THE GROUND IT WAS STANDING ON.
|
|
125
|
+
*
|
|
126
|
+
* Spreading the target carried the DESTINATION's city into the
|
|
127
|
+
* frozen origin, so the next tween interpolated from the new cell
|
|
128
|
+
* and the new origin to themselves: the cards flew and the lattice,
|
|
129
|
+
* the plots and the roads under them were already there. That is
|
|
130
|
+
* the picture flashing to the new place while the buildings walk
|
|
131
|
+
* over to join it.
|
|
132
|
+
*/
|
|
133
|
+
...(live.city ? { city: live.city } : {}),
|
|
134
|
+
nodes: live.nodes.map((node) => ({
|
|
135
|
+
...node,
|
|
136
|
+
plane: Math.round(node.plane),
|
|
137
|
+
})),
|
|
138
|
+
connectors: live.connectors,
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
}, [target, duration, enabled]);
|
|
142
|
+
return current;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* The nodes implicated by the most recent change, for about a second.
|
|
146
|
+
*
|
|
147
|
+
* Human and agent edits arrive through the same subscription carrying the
|
|
148
|
+
* same diff, so the interface cannot render one differently from the other
|
|
149
|
+
* even by accident — which is the point. The renderer highlights an agent's
|
|
150
|
+
* work with exactly the code that highlights yours.
|
|
151
|
+
*/
|
|
152
|
+
export function useTouched(holdMs = 1100) {
|
|
153
|
+
const { store } = useGraview();
|
|
154
|
+
const [touched, setTouched] = useState(() => new Set());
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
let timer = null;
|
|
157
|
+
const unsubscribe = store.subscribe((diff) => {
|
|
158
|
+
setTouched(new Set(diff.touched));
|
|
159
|
+
if (timer)
|
|
160
|
+
clearTimeout(timer);
|
|
161
|
+
timer = setTimeout(() => setTouched(new Set()), holdMs);
|
|
162
|
+
});
|
|
163
|
+
return () => {
|
|
164
|
+
unsubscribe();
|
|
165
|
+
if (timer)
|
|
166
|
+
clearTimeout(timer);
|
|
167
|
+
};
|
|
168
|
+
}, [store, holdMs]);
|
|
169
|
+
return touched;
|
|
170
|
+
}
|
|
171
|
+
const NO_WORK = { marks: new Map(), acts: [] };
|
|
172
|
+
/**
|
|
173
|
+
* WHERE THE SEAT WORKED, MARKED ON THE THINGS THEMSELVES.
|
|
174
|
+
*
|
|
175
|
+
* The robot used to walk to what it wrote and stand there, which is the
|
|
176
|
+
* one thing the body was genuinely good for: attribution in space. The
|
|
177
|
+
* walk is gone; the attribution is not. Every op the log attributes to an
|
|
178
|
+
* agent marks what it wrote for a hold, and the acts stay in a list the
|
|
179
|
+
* companion can offer to fly you to.
|
|
180
|
+
*
|
|
181
|
+
* Read from the OP LOG rather than from the seat's own reports, so it is
|
|
182
|
+
* the same on both render paths, inside a lens, and for a turn that
|
|
183
|
+
* arrived from somewhere else entirely. An undo takes its marks with it:
|
|
184
|
+
* an op that undoes another says so, and what it took back stops being
|
|
185
|
+
* something the seat just did.
|
|
186
|
+
*/
|
|
187
|
+
export function useSeatWork(holdMs = 4000) {
|
|
188
|
+
const { store } = useGraview();
|
|
189
|
+
const [work, setWork] = useState(NO_WORK);
|
|
190
|
+
useEffect(() => {
|
|
191
|
+
let timer = null;
|
|
192
|
+
const unsubscribe = store.subscribe((_diff, ops) => {
|
|
193
|
+
setWork((current) => {
|
|
194
|
+
const marks = new Map(current.marks);
|
|
195
|
+
let acts = [...current.acts];
|
|
196
|
+
for (const op of ops) {
|
|
197
|
+
if (op.undoes !== undefined) {
|
|
198
|
+
/*
|
|
199
|
+
* Taken back: the act leaves the log the companion shows, and
|
|
200
|
+
* the marks it put on things leave with it. A mark over a
|
|
201
|
+
* change that no longer exists is the seat claiming credit for
|
|
202
|
+
* nothing.
|
|
203
|
+
*/
|
|
204
|
+
const undone = acts.find((act) => act.batch === op.undoes || act.wrote.length > 0);
|
|
205
|
+
const taken = acts.filter((act) => op.writes.some((id) => act.wrote.includes(id)));
|
|
206
|
+
for (const act of taken.length > 0 ? taken : undone ? [undone] : []) {
|
|
207
|
+
for (const id of act.wrote)
|
|
208
|
+
marks.delete(id);
|
|
209
|
+
acts = acts.filter((one) => one.batch !== act.batch);
|
|
210
|
+
}
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (op.author.kind !== "agent")
|
|
214
|
+
continue;
|
|
215
|
+
const who = op.author.id ?? "the seat";
|
|
216
|
+
for (const id of op.writes)
|
|
217
|
+
marks.set(id, who);
|
|
218
|
+
const already = acts.find((act) => act.batch === op.batch);
|
|
219
|
+
if (already) {
|
|
220
|
+
acts = acts.map((act) => act.batch === op.batch
|
|
221
|
+
? { ...act, wrote: [...new Set([...act.wrote, ...op.writes])] }
|
|
222
|
+
: act);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
acts = [{ batch: op.batch, who, intent: op.intent, at: op.at, wrote: [...op.writes] }, ...acts].slice(0, 12);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return marks.size === current.marks.size && acts === current.acts && marks.size === 0
|
|
229
|
+
? current
|
|
230
|
+
: { marks, acts };
|
|
231
|
+
});
|
|
232
|
+
if (timer)
|
|
233
|
+
clearTimeout(timer);
|
|
234
|
+
/* The marks fade; the log stays, because "what did it just do" outlives the flash. */
|
|
235
|
+
timer = setTimeout(() => setWork((current) => (current.marks.size === 0 ? current : { ...current, marks: new Map() })), holdMs);
|
|
236
|
+
});
|
|
237
|
+
return () => {
|
|
238
|
+
unsubscribe();
|
|
239
|
+
if (timer)
|
|
240
|
+
clearTimeout(timer);
|
|
241
|
+
};
|
|
242
|
+
}, [store, holdMs]);
|
|
243
|
+
return work;
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=animation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"animation.js","sourceRoot":"","sources":["../src/animation.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,WAAW,GAGZ,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAS1C,MAAM,gBAAgB,GAAG,GAAG,CAAC;AAE7B,SAAS,oBAAoB;IAC3B,IAAI,OAAO,MAAM,KAAK,WAAW,IAAI,CAAC,MAAM,CAAC,UAAU;QAAE,OAAO,KAAK,CAAC;IACtE,OAAO,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,OAAO,CAAC;AACvE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAc,EACd,UAA6B,EAAE;IAE/B,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,gBAAgB,CAAC;IACtD,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAErE,MAAM,IAAI,GAAG,MAAM,CAAS,MAAM,CAAC,CAAC;IACpC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAqB,GAAG,EAAE,CAC9D,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAC/B,CAAC;IACF,iCAAiC;IACjC,EAAE;IACF,0EAA0E;IAC1E,qEAAqE;IACrE,uEAAuE;IACvE,0EAA0E;IAC1E,uCAAuC;IACvC,MAAM,MAAM,GAAG,MAAM,CAAqB,OAAO,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAC1C;;;;;;;;;OASG;IACH,MAAM,KAAK,GAAG,MAAM,CAAgB,IAAI,CAAC,CAAC;IAE1C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,OAAO,IAAI,OAAO,qBAAqB,KAAK,WAAW,EAAE,CAAC;YAC7D,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;YACtB,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;YAC/C,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;YACzB,UAAU,CAAC,OAAO,CAAC,CAAC;YACpB;;;;;;;;eAQG;YACH,IAAI,OAAO,qBAAqB,KAAK,WAAW;gBAAE,OAAO;YACzD,MAAM,IAAI,GAAG,qBAAqB,CAAC,GAAG,EAAE;gBACtC,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;gBAC7C,MAAM,CAAC,OAAO,GAAG,KAAK,CAAC;gBACvB,UAAU,CAAC,KAAK,CAAC,CAAC;YACpB,CAAC,CAAC,CAAC;YACH,OAAO,GAAG,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC;QAC1C,CAAC;QAED,uEAAuE;QACvE,sEAAsE;QACtE,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,KAAK,IAAI,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,GAAG,QAAQ,CAAC;QAClG,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAQ,CAAC,CAAC,CAAC,GAAG,CAAC;QAC9C,KAAK,CAAC,OAAO,GAAG,KAAK,CAAC;QACtB,wEAAwE;QACxE,yEAAyE;QACzE,MAAM,YAAY,GAAG,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC;QAE5B,MAAM,IAAI,GAAG,CAAC,EAAU,EAAE,EAAE;YAC1B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC;YAC/C,MAAM,KAAK,GAAG,YAAY,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC,GAAG,YAAY,CAAC,CAAC;YACzF,MAAM,IAAI,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YAC7D,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;YACtB,UAAU,CAAC,IAAI,CAAC,CAAC;YACjB,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACV,KAAK,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC9C,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;gBACrB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;gBACtB;;;;;;;;;;mBAUG;gBACH,KAAK,CAAC,OAAO,GAAG,qBAAqB,CAAC,GAAG,EAAE;oBACzC,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;oBAC/C,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;oBACzB,UAAU,CAAC,OAAO,CAAC,CAAC;oBACpB,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC;gBACvB,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC,CAAC;QAEF,KAAK,CAAC,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;QAC5C,OAAO,GAAG,EAAE;YACV,IAAI,KAAK,CAAC,OAAO,KAAK,IAAI;gBAAE,oBAAoB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAChE,oEAAoE;YACpE,kEAAkE;YAClE,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC;YAC5B,IAAI,CAAC,OAAO,GAAG;gBACb,GAAG,MAAM;gBACT;;;;;;;;;mBASG;gBACH,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACzC,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBAC/B,GAAG,IAAI;oBACP,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAc;iBAC3C,CAAC,CAAC;gBACH,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC;QACJ,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAEhC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAsB,MAAM,GAAG,IAAI;IAC3D,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAK,CAAC;IAClC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAsB,GAAG,EAAE,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAE7E,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,GAAyC,IAAI,CAAC;QACvD,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE;YAC3C,UAAU,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;YAClC,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE;YACV,WAAW,EAAE,CAAC;YACd,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAEpB,OAAO,OAAO,CAAC;AACjB,CAAC;AAmBD,MAAM,OAAO,GAAa,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;AAEzD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CAAsB,MAAM,GAAG,IAAI;IAC5D,MAAM,EAAE,KAAK,EAAE,GAAG,UAAU,EAAK,CAAC;IAClC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAW,OAAO,CAAC,CAAC;IAEpD,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,KAAK,GAAyC,IAAI,CAAC;QACvD,MAAM,WAAW,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YACjD,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;gBAClB,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBACrC,IAAI,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;gBAC7B,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;oBACrB,IAAI,EAAE,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;wBAC5B;;;;;2BAKG;wBACH,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,MAAM,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;wBACnF,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;wBACnF,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;4BACpE,KAAK,MAAM,EAAE,IAAI,GAAG,CAAC,KAAK;gCAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;4BAC7C,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC;wBACvD,CAAC;wBACD,SAAS;oBACX,CAAC;oBACD,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,OAAO;wBAAE,SAAS;oBACzC,MAAM,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,UAAU,CAAC;oBACvC,KAAK,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM;wBAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;oBAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC;oBAC3D,IAAI,OAAO,EAAE,CAAC;wBACZ,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CACtB,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC,KAAK;4BACpB,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE;4BAC/D,CAAC,CAAC,GAAG,CACR,CAAC;oBACJ,CAAC;yBAAM,CAAC;wBACN,IAAI,GAAG,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC/G,CAAC;gBACH,CAAC;gBACD,OAAO,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,KAAK,OAAO,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,KAAK,CAAC;oBACnF,CAAC,CAAC,OAAO;oBACT,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;YACtB,CAAC,CAAC,CAAC;YACH,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,sFAAsF;YACtF,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QAClI,CAAC,CAAC,CAAC;QACH,OAAO,GAAG,EAAE;YACV,WAAW,EAAE,CAAC;YACd,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IAEpB,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WHERE A RELATION'S CAPTION GOES — pure, so it can be held to.
|
|
3
|
+
*
|
|
4
|
+
* The neighbourhood is grouped by relation, and each group is captioned
|
|
5
|
+
* once, above the first row it occupies. Three things this used to get
|
|
6
|
+
* wrong, all found by a discography whose artist is featured on some songs
|
|
7
|
+
* and produced others:
|
|
8
|
+
*
|
|
9
|
+
* - A group was a CONSECUTIVE run of the frame's nodes, and the frame is
|
|
10
|
+
* sorted by id. "Featured on" After Midnight, "produced" Blue Hour,
|
|
11
|
+
* "featured on" Rent Is Due made three runs and two captions saying the
|
|
12
|
+
* same thing — and, keyed by the edge kind alone, React could not tell
|
|
13
|
+
* the two apart, kept the old elements through the next navigation, and
|
|
14
|
+
* an album's picture went on saying "their songs" from the artist you had
|
|
15
|
+
* left, one caption over every card.
|
|
16
|
+
* - A caption borrowed three hundred pixels whatever stood beside it, so
|
|
17
|
+
* two narrow groups' captions lay across each other.
|
|
18
|
+
* - The borrowing was clamped to the stage and not to the room the rails
|
|
19
|
+
* leave, so the leftmost caption ran under the inspector.
|
|
20
|
+
*/
|
|
21
|
+
export interface CaptionEntry {
|
|
22
|
+
/** Which relation, read from which end: one caption per key. */
|
|
23
|
+
readonly key: string;
|
|
24
|
+
readonly text: string;
|
|
25
|
+
readonly left: number;
|
|
26
|
+
readonly right: number;
|
|
27
|
+
readonly top: number;
|
|
28
|
+
}
|
|
29
|
+
export interface CaptionRun {
|
|
30
|
+
readonly key: string;
|
|
31
|
+
readonly text: string;
|
|
32
|
+
readonly left: number;
|
|
33
|
+
readonly width: number;
|
|
34
|
+
/** The top of the row the caption sits over. */
|
|
35
|
+
readonly top: number;
|
|
36
|
+
}
|
|
37
|
+
/** Wide enough for a full edge description before anything is cut. */
|
|
38
|
+
export declare const MIN_CAPTION = 300;
|
|
39
|
+
export declare function captionRuns(entries: readonly CaptionEntry[], room: {
|
|
40
|
+
readonly left: number;
|
|
41
|
+
readonly right: number;
|
|
42
|
+
}): CaptionRun[];
|
|
43
|
+
//# sourceMappingURL=captions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,YAAY;IAC3B,gEAAgE;IAChE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,sEAAsE;AACtE,eAAO,MAAM,WAAW,MAAM,CAAC;AAO/B,wBAAgB,WAAW,CACzB,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,IAAI,EAAE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACtD,UAAU,EAAE,CAkDd"}
|
package/dist/captions.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Wide enough for a full edge description before anything is cut. */
|
|
2
|
+
export const MIN_CAPTION = 300;
|
|
3
|
+
/** Cards in one row are within this many pixels of each other's top. */
|
|
4
|
+
const SAME_ROW = 12;
|
|
5
|
+
const GAP = 8;
|
|
6
|
+
/** About how wide a caption's words are drawn: 0.75rem capitals, letter-spaced, on a padded ground. */
|
|
7
|
+
const wordsWidth = (text) => text.length * 8.4 + 16;
|
|
8
|
+
export function captionRuns(entries, room) {
|
|
9
|
+
const groups = new Map();
|
|
10
|
+
for (const entry of entries) {
|
|
11
|
+
const held = groups.get(entry.key);
|
|
12
|
+
if (held)
|
|
13
|
+
held.push(entry);
|
|
14
|
+
else
|
|
15
|
+
groups.set(entry.key, [entry]);
|
|
16
|
+
}
|
|
17
|
+
// Each group over the FIRST row it stands in: the rows after it continue it.
|
|
18
|
+
const runs = [...groups.values()].map((members) => {
|
|
19
|
+
const top = Math.min(...members.map((member) => member.top));
|
|
20
|
+
const row = members.filter((member) => member.top - top <= SAME_ROW);
|
|
21
|
+
return {
|
|
22
|
+
key: members[0].key,
|
|
23
|
+
text: members[0].text,
|
|
24
|
+
left: Math.min(...row.map((member) => member.left)),
|
|
25
|
+
right: Math.max(...row.map((member) => member.right)),
|
|
26
|
+
top,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
runs.sort((a, b) => a.top - b.top || a.left - b.left);
|
|
30
|
+
/*
|
|
31
|
+
* What each caption WANTS: its own run, or its words, whichever is wider,
|
|
32
|
+
* centred on the run. A neighbour's ground is borrowed only as far as the
|
|
33
|
+
* neighbour does not want it; where both want the gutter between them,
|
|
34
|
+
* they split it.
|
|
35
|
+
*/
|
|
36
|
+
const want = runs.map((run) => {
|
|
37
|
+
const width = Math.max(run.right - run.left, Math.min(MIN_CAPTION, wordsWidth(run.text)));
|
|
38
|
+
const mid = (run.left + run.right) / 2;
|
|
39
|
+
return { left: mid - width / 2, right: mid + width / 2 };
|
|
40
|
+
});
|
|
41
|
+
return runs.map((run, index) => {
|
|
42
|
+
const beside = runs
|
|
43
|
+
.map((other, at) => ({ other, at }))
|
|
44
|
+
.filter(({ other }) => other !== run && Math.abs(other.top - run.top) <= SAME_ROW);
|
|
45
|
+
const floors = beside
|
|
46
|
+
.filter(({ other }) => other.right <= run.left)
|
|
47
|
+
.map(({ other, at }) => (want[at].right + GAP <= (other.right + run.left) / 2 ? want[at].right + GAP : (other.right + run.left + GAP) / 2));
|
|
48
|
+
const ceilings = beside
|
|
49
|
+
.filter(({ other }) => other.left >= run.right)
|
|
50
|
+
.map(({ other, at }) => (want[at].left - GAP >= (run.right + other.left) / 2 ? want[at].left - GAP : (run.right + other.left - GAP) / 2));
|
|
51
|
+
const floor = Math.max(room.left, ...floors);
|
|
52
|
+
const ceiling = Math.min(room.right, ...ceilings);
|
|
53
|
+
const own = run.right - run.left;
|
|
54
|
+
const desired = want[index].right - want[index].left;
|
|
55
|
+
const width = Math.max(own, Math.min(desired, ceiling - floor));
|
|
56
|
+
const mid = (run.left + run.right) / 2;
|
|
57
|
+
const left = own >= width ? run.left : Math.max(floor, Math.min(mid - width / 2, ceiling - width));
|
|
58
|
+
return { key: run.key, text: run.text, left, width, top: run.top };
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=captions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"captions.js","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Box, Point } from "./routes.js";
|
|
2
|
+
export interface Row {
|
|
3
|
+
readonly top: number;
|
|
4
|
+
readonly bottom: number;
|
|
5
|
+
readonly boxes: readonly Box[];
|
|
6
|
+
}
|
|
7
|
+
/** Boxes grouped into rows by vertical overlap, top to bottom, each row's boxes left to right. */
|
|
8
|
+
export declare function bandRows(band: readonly Box[]): Row[];
|
|
9
|
+
/**
|
|
10
|
+
* The polyline from one chip to another through the band's gutters. `lane`
|
|
11
|
+
* staggers lines that share a channel by a few pixels so two relations
|
|
12
|
+
* along the same gutter do not lie on one another.
|
|
13
|
+
*/
|
|
14
|
+
export declare function channelRoute(from: Box, to: Box, band: readonly Box[], lane?: number): Point[];
|
|
15
|
+
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAiB9C,MAAM,WAAW,GAAG;IAClB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,EAAE,CAAC;CAChC;AAED,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,CAapD;AAgDD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,GAAG,EAAE,EAAE,IAAI,SAAI,GAAG,KAAK,EAAE,CA2BxF"}
|
package/dist/channels.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* A LINE BETWEEN TWO CHIPS OF ONE BAND runs in the gutters.
|
|
3
|
+
*
|
|
4
|
+
* A band of many neighbours is a grid: rows of chips with gaps between the
|
|
5
|
+
* rows and between the chips. An arc between two of them crossed whatever
|
|
6
|
+
* lay between, and clipped under every chip it crossed it was left as
|
|
7
|
+
* confetti — dashes in the gaps that belonged to no visible line. In a
|
|
8
|
+
* grid the honest road is the gutter: leave a chip by its bottom edge,
|
|
9
|
+
* travel along the channel between rows, cross rows through a gap between
|
|
10
|
+
* chips, and arrive at the other chip's top. Nothing is crossed, so
|
|
11
|
+
* nothing needs clipping, and the whole line is one visible thing.
|
|
12
|
+
*/
|
|
13
|
+
const CLEAR = 12;
|
|
14
|
+
/** Boxes grouped into rows by vertical overlap, top to bottom, each row's boxes left to right. */
|
|
15
|
+
export function bandRows(band) {
|
|
16
|
+
const sorted = [...band].sort((a, b) => a.y - b.y || a.x - b.x);
|
|
17
|
+
const rows = [];
|
|
18
|
+
for (const box of sorted) {
|
|
19
|
+
const row = rows.find((r) => box.y < r.bottom && box.y + box.height > r.top);
|
|
20
|
+
if (row) {
|
|
21
|
+
row.boxes.push(box);
|
|
22
|
+
row.top = Math.min(row.top, box.y);
|
|
23
|
+
row.bottom = Math.max(row.bottom, box.y + box.height);
|
|
24
|
+
}
|
|
25
|
+
else
|
|
26
|
+
rows.push({ top: box.y, bottom: box.y + box.height, boxes: [box] });
|
|
27
|
+
}
|
|
28
|
+
for (const row of rows)
|
|
29
|
+
row.boxes.sort((a, b) => a.x - b.x);
|
|
30
|
+
return rows.sort((a, b) => a.top - b.top);
|
|
31
|
+
}
|
|
32
|
+
const same = (a, b) => a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height;
|
|
33
|
+
const rowOf = (rows, box) => rows.findIndex((row) => row.boxes.some((b) => same(b, box)));
|
|
34
|
+
/** The channel between two consecutive rows, or the space just above the first / below the last. */
|
|
35
|
+
function channelBetween(rows, above, below) {
|
|
36
|
+
if (above < 0)
|
|
37
|
+
return rows[0].top - CLEAR * 2;
|
|
38
|
+
if (below >= rows.length)
|
|
39
|
+
return rows[rows.length - 1].bottom + CLEAR * 2;
|
|
40
|
+
return (rows[above].bottom + rows[below].top) / 2;
|
|
41
|
+
}
|
|
42
|
+
/** An x that is clear of every chip in these rows, as near `wanted` as one exists. */
|
|
43
|
+
function clearX(rows, wanted) {
|
|
44
|
+
// Every row's free intervals, intersected: the gaps between chips plus both margins.
|
|
45
|
+
let free = [{ from: -Infinity, to: Infinity }];
|
|
46
|
+
for (const row of rows) {
|
|
47
|
+
const gaps = [];
|
|
48
|
+
let cursor = -Infinity;
|
|
49
|
+
for (const box of row.boxes) {
|
|
50
|
+
gaps.push({ from: cursor, to: box.x - CLEAR });
|
|
51
|
+
cursor = box.x + box.width + CLEAR;
|
|
52
|
+
}
|
|
53
|
+
gaps.push({ from: cursor, to: Infinity });
|
|
54
|
+
const next = [];
|
|
55
|
+
for (const a of free)
|
|
56
|
+
for (const b of gaps) {
|
|
57
|
+
const from = Math.max(a.from, b.from);
|
|
58
|
+
const to = Math.min(a.to, b.to);
|
|
59
|
+
if (to - from >= 0)
|
|
60
|
+
next.push({ from, to });
|
|
61
|
+
}
|
|
62
|
+
free = next;
|
|
63
|
+
}
|
|
64
|
+
let best = wanted;
|
|
65
|
+
let distance = Infinity;
|
|
66
|
+
for (const gap of free) {
|
|
67
|
+
const x = Math.min(Math.max(wanted, gap.from), gap.to);
|
|
68
|
+
// A gap between chips over the band's margin, unless the margin is much nearer:
|
|
69
|
+
// a road down the outside edge, hugging the row's first chip, framed it.
|
|
70
|
+
const margin = gap.from === -Infinity || gap.to === Infinity;
|
|
71
|
+
const d = Math.abs(x - wanted) + (margin ? 60 : 0);
|
|
72
|
+
if (d < distance) {
|
|
73
|
+
distance = d;
|
|
74
|
+
best = x;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return best;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The polyline from one chip to another through the band's gutters. `lane`
|
|
81
|
+
* staggers lines that share a channel by a few pixels so two relations
|
|
82
|
+
* along the same gutter do not lie on one another.
|
|
83
|
+
*/
|
|
84
|
+
export function channelRoute(from, to, band, lane = 0) {
|
|
85
|
+
const rows = bandRows(band.some((b) => same(b, from)) && band.some((b) => same(b, to)) ? band : [...band, from, to]);
|
|
86
|
+
const rf = rowOf(rows, from);
|
|
87
|
+
const rt = rowOf(rows, to);
|
|
88
|
+
const fx = from.x + from.width / 2;
|
|
89
|
+
const tx = to.x + to.width / 2;
|
|
90
|
+
const stagger = ((lane % 3) - 1) * 4;
|
|
91
|
+
if (rf === rt) {
|
|
92
|
+
// A U under the row (or over it, for the last row of several): out, along, and back in.
|
|
93
|
+
const under = rf < rows.length - 1 || rows.length === 1;
|
|
94
|
+
const y = (under ? channelBetween(rows, rf, rf + 1) : channelBetween(rows, rf - 1, rf)) + stagger;
|
|
95
|
+
const a = under ? from.y + from.height : from.y;
|
|
96
|
+
const b = under ? to.y + to.height : to.y;
|
|
97
|
+
return [{ x: fx, y: a }, { x: fx, y }, { x: tx, y }, { x: tx, y: b }];
|
|
98
|
+
}
|
|
99
|
+
const down = rt > rf;
|
|
100
|
+
const step = down ? 1 : -1;
|
|
101
|
+
const start = { x: fx, y: down ? from.y + from.height : from.y };
|
|
102
|
+
const end = { x: tx, y: down ? to.y : to.y + to.height };
|
|
103
|
+
const first = (down ? channelBetween(rows, rf, rf + 1) : channelBetween(rows, rf - 1, rf)) + stagger;
|
|
104
|
+
const last = (down ? channelBetween(rows, rt - 1, rt) : channelBetween(rows, rt, rt + 1)) + stagger;
|
|
105
|
+
if (Math.abs(rt - rf) === 1)
|
|
106
|
+
return [start, { x: fx, y: first }, { x: tx, y: first }, end];
|
|
107
|
+
// Rows in between: cross them through a gap between chips, as near the far chip as one is.
|
|
108
|
+
const between = [];
|
|
109
|
+
for (let r = rf + step; r !== rt; r += step)
|
|
110
|
+
between.push(rows[r]);
|
|
111
|
+
const vx = clearX(between, tx);
|
|
112
|
+
return [start, { x: fx, y: first }, { x: vx, y: first }, { x: vx, y: last }, { x: tx, y: last }, end];
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=channels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.js","sourceRoot":"","sources":["../src/channels.ts"],"names":[],"mappings":"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"}
|