The renderer grows a live d3 sim (createGraphSimulation, shared with the server settle): pointerdown on a node pins fx/fy and pointer capture (preventDefault kills the compat mousedown, so d3-zoom never pans); the first CLICK_SLOP-exceeding move reheats to alphaTarget 0.3; release un-pins and the sim anneals (release-and-relax) — alpha < 0.005 settles it, a 250ms debounced onCommit PUTs the rest state. Verified live: 123fps during a 320ms drag (regions rebuilding every 3rd frame), 85-tick settle, then zero idle frames. A slop-free press stays a click (select, no reheat, no commit). PUT /api/graph/positions sanitizes (finite coords, known ids) and if the graph grew mid-drag runs ONE incremental settle with the client's arrangement as anchors (50-id PUT test: anchored drift 0.15). Cluster regions swap convex hulls for a low-res world-space SPLAT bitmap: per-member radial-gradient discs (alpha 0.2) + intra-cluster edges as round-cap strokes (Minkowski dilation — concave shapes finally render), upscaled with bilinear smoothing (the upscale IS the blur, no ctx.filter: Safari). One tiny blit per frame replaces 32 clusters x 4 offset Path2D polygons re-rasterized at DPR 2 (the old GPU coil-whine path); during the live sim the bitmap rebuilds every 3rd frame. cluster-geometry.ts retires convexHull/offsetPolygon/traceRoundedPath (tests follow; clusterHue stays). Region labels stay (centroid + clusterHue, inverse-gated on zoom).
20 lines
832 B
TypeScript
20 lines
832 B
TypeScript
/**
|
||
* Cluster color identity — pure presentation math for the knowledge-graph
|
||
* regions. (The hull geometry that used to live here — convexHull,
|
||
* outwardNormal, offsetPolygon, traceRoundedPath — was RETIRED with the
|
||
* convex-hull renderer: regions are now a low-res world-space splat
|
||
* bitmap in graph-canvas.ts, which renders concave cluster shapes
|
||
* correctly and costs one blit per frame instead of 32 clusters × 4
|
||
* offset polygons. The file keeps the name for the barrel imports.)
|
||
*/
|
||
|
||
export type Pt = { x: number; y: number };
|
||
|
||
/** Stable hue per cluster id (content-hash): the region keeps its color
|
||
* across reshuffles because the id only changes when the members do. */
|
||
export function clusterHue(id: string): number {
|
||
let h = 0;
|
||
for (const ch of id) h = (h * 31 + ch.charCodeAt(0)) % 360;
|
||
return h;
|
||
}
|