@kanzo-tech/graph 0.25.0 → 0.27.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/README.md +2 -2
- package/dist/core/categories.d.ts +1 -1
- package/dist/core/categories.d.ts.map +1 -1
- package/dist/core/categories.js.map +1 -1
- package/dist/core/channels.d.ts +12 -6
- package/dist/core/channels.d.ts.map +1 -1
- package/dist/core/channels.js +15 -12
- package/dist/core/channels.js.map +1 -1
- package/dist/core/client.d.ts +26 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +62 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/error.d.ts +3 -3
- package/dist/core/error.d.ts.map +1 -1
- package/dist/core/error.js.map +1 -1
- package/dist/core/load.d.ts +30 -39
- package/dist/core/load.d.ts.map +1 -1
- package/dist/core/load.js +63 -117
- package/dist/core/load.js.map +1 -1
- package/dist/core/source.d.ts +90 -0
- package/dist/core/source.d.ts.map +1 -0
- package/dist/core/source.js +105 -0
- package/dist/core/source.js.map +1 -0
- package/dist/core/state.d.ts +19 -20
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js +138 -158
- package/dist/core/store.js.map +1 -1
- package/dist/core/types.d.ts +5 -3
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +20 -18
- package/dist/index.js.map +1 -1
- package/dist/parts/graph-canvas.d.ts.map +1 -1
- package/dist/parts/graph-canvas.js +49 -48
- package/dist/parts/graph-canvas.js.map +1 -1
- package/dist/parts/graph-counts.js +4 -4
- package/dist/parts/graph-counts.js.map +1 -1
- package/dist/parts/graph-inspector.d.ts +3 -3
- package/dist/parts/graph-inspector.d.ts.map +1 -1
- package/dist/parts/graph-inspector.js +45 -43
- package/dist/parts/graph-inspector.js.map +1 -1
- package/dist/parts/graph-search.d.ts +7 -7
- package/dist/parts/graph-search.d.ts.map +1 -1
- package/dist/parts/graph-search.js +60 -69
- package/dist/parts/graph-search.js.map +1 -1
- package/dist/parts/graph-select.d.ts +27 -0
- package/dist/parts/graph-select.d.ts.map +1 -0
- package/dist/parts/graph-select.js +53 -0
- package/dist/parts/graph-select.js.map +1 -0
- package/dist/parts/graph-toolbar.js +1 -1
- package/dist/parts/graph-toolbar.js.map +1 -1
- package/dist/react/use-graph.js +31 -31
- package/dist/react/use-graph.js.map +1 -1
- package/dist/render/camera.d.ts +12 -1
- package/dist/render/camera.d.ts.map +1 -1
- package/dist/render/camera.js +33 -21
- package/dist/render/camera.js.map +1 -1
- package/dist/render/graph-sim.d.ts +1 -1
- package/dist/render/graph-sim.d.ts.map +1 -1
- package/dist/render/graph-sim.js.map +1 -1
- package/dist/render/motion.d.ts +33 -0
- package/dist/render/motion.d.ts.map +1 -0
- package/dist/render/motion.js +19 -0
- package/dist/render/motion.js.map +1 -0
- package/dist/render/placement.d.ts +2 -4
- package/dist/render/placement.d.ts.map +1 -1
- package/dist/render/placement.js +12 -16
- package/dist/render/placement.js.map +1 -1
- package/dist/render/renderer.d.ts +6 -5
- package/dist/render/renderer.d.ts.map +1 -1
- package/dist/render/renderer.js +130 -118
- package/dist/render/renderer.js.map +1 -1
- package/dist/section.js +1 -1
- package/dist/section.js.map +1 -1
- package/package.json +12 -14
- package/dist/core/detail.d.ts +0 -26
- package/dist/core/detail.d.ts.map +0 -1
- package/dist/core/detail.js +0 -63
- package/dist/core/detail.js.map +0 -1
- package/dist/core/filter.d.ts +0 -23
- package/dist/core/filter.d.ts.map +0 -1
- package/dist/core/filter.js +0 -95
- package/dist/core/filter.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.js","sources":["../../src/render/renderer.ts"],"sourcesContent":["import { Graph } from \"@cosmos.gl/graph\";\nimport { GraphError } from \"../core/error\";\nimport type { Geometry } from \"../core/load\";\nimport type { GraphStore } from \"../core/store\";\nimport type { GraphCommands, VertexId } from \"../core/types\";\nimport { resolveLook, type Look } from \"./graph-looks\";\nimport { appearance, forces, paint } from \"./graph-model\";\nimport { resolveSim, type Sim } from \"./graph-sim\";\nimport { createCamera, FIT_DURATION } from \"./camera\";\nimport { cornersOf, placed, placementOf, UNPLACED, type Placement } from \"./placement\";\nimport { releaseContext, webglBox } from \"./webgl\";\n\nexport interface RendererEvents {\n /** After every frame and every camera move — where the overlays repaint. */\n onFrame?: () => void;\n /** Where the hovered point is in space, as cosmos.gl reports it: no GPU readback per hover. */\n onHover?: (position: [number, number] | null) => void;\n}\n\nexport interface Renderer extends GraphCommands {\n readonly graph: Graph;\n /** The theme moved under the canvas: colours are resolved again, nothing else. */\n repaint(): void;\n /** The drawn points inside a screen rectangle or polygon, once the device is ready. */\n hit(shape: { rect: [[number, number], [number, number]] } | { polygon: [number, number][] }): number[];\n destroy(): void;\n}\n\nconst REHEAT = 0.35;\n/** How long a release wakes a paused layout before pausing it again. */\nconst RELEASE_BURST = 1200;\n/** Twentieths: a settle costs twenty reports rather than one per frame. */\nconst PROGRESS_STEPS = 20;\n/**\n * The slowest honest answer for a GPU device: one comes up in milliseconds when it can be made at\n * all, so ten seconds is a device that will not come, not one that is slow.\n */\nconst READY_DEADLINE = 10_000;\n\n/**\n * **cosmos.gl's lifetime, and the frame that renders once.** Built once per element; it subscribes to\n * the store and discharges what changed in one `requestAnimationFrame`:\n *\n * - a new graph uploads positions and links, once per corpus; a filter uploads positions alone;\n * - a binding, a look or a theme change uploads colours, sizes and shapes and nothing else;\n * - a selection, a focus or a pin sets config and uploads nothing, and never calls `render()`:\n * `render()` walks every point and link in JS, and `setConfigPartial` asks for its own frame;\n * - the camera reaches nothing: cosmos.gl moves it, and the overlays follow.\n *\n * A vertex's id is its index here, so nothing is resolved between the store and the buffers.\n * `transitionDuration` is 0: the default animates every upload for 800 ms and keeps the loop awake.\n * The live layout is off unless `simulate` or the toolbar asks, and runs from the current positions.\n * Every callback reads the store's latest options, so a host's inline `onFailure` never rebuilds it.\n * A failure to draw at all marks the store `failed` through `unrenderable`, never `onFailure` alone.\n */\nexport function createRenderer(host: HTMLDivElement, store: GraphStore, events: RendererEvents = {}): Renderer | null {\n let destroyed = false;\n const fail = (error: unknown) => {\n if (!destroyed) store.unrenderable(error);\n };\n const box = webglBox();\n if (box === null) {\n fail(new GraphError(\"graph/no-webgl\", \"This browser offers no WebGL context to draw with.\"));\n return null;\n }\n\n let sim: Sim = resolveSim(store.getOptions().sim);\n let live = store.getOptions().simulate ?? false;\n let hovering: number | null = null;\n let dragging: number | null = null;\n let burst = 0;\n let reported = -1;\n const progress = (value: number) => {\n const bucket = Math.round(value * PROGRESS_STEPS);\n if (bucket === reported) return;\n reported = bucket;\n store.reportProgress(bucket / PROGRESS_STEPS);\n };\n\n let look: Look = resolveLook(store.getOptions().look);\n let lookPatch = store.getOptions().look;\n const dirty = { positions: true, paint: true, state: true, pinned: true };\n let frame = 0;\n let framed: Geometry | null = null;\n let placement: Placement | null = null;\n let links: Float32Array | null = null;\n let last = store.getSnapshot();\n let lastOptions = store.getOptions();\n\n const size = () => store.getSnapshot().geometry?.size ?? 0;\n\n let graph: Graph;\n try {\n graph = new Graph(host, {\n // No `spaceSize` here: the box is the corpus's extent, set when the graph has loaded.\n // `rescalePositions: false` because the placement below is ours, and the corpus's own scale.\n rescalePositions: false,\n transitionDuration: 0,\n enableSimulation: live,\n ...forces(sim),\n // Frames to convergence: alpha reaches its floor after exactly this many rendered frames.\n simulationDecay: 400,\n randomSeed: \"kanzo-discovery\",\n pixelRatio: window.devicePixelRatio || 1,\n enableDrag: true,\n hoveredPointCursor: \"pointer\",\n attribution: \"\",\n onSimulationStart: () => store.report(\"running\"),\n onSimulationEnd: () => {\n store.report(\"settled\");\n progress(1);\n camera.settle();\n events.onFrame?.();\n },\n onSimulationPause: () => store.report(\"paused\"),\n onSimulationUnpause: () => store.report(\"running\"),\n onSimulationTick: (_alpha, index, position) => {\n progress(graph.progress);\n camera.tick();\n if (index !== undefined && position) events.onHover?.(position);\n events.onFrame?.();\n },\n onZoomStart: (_event, userDriven) => taken(userDriven),\n onZoom: () => events.onFrame?.(),\n onPointMouseOver: (index, position) => {\n hovering = index;\n events.onHover?.(position);\n store.hover(index);\n },\n onPointMouseOut: () => {\n hovering = null;\n events.onHover?.(null);\n store.hover(null);\n },\n onDragStart: () => {\n dragging = hovering;\n },\n onDrag: (event) => {\n events.onHover?.(graph.screenToSpacePosition([event.x, event.y]));\n events.onFrame?.();\n },\n // d3-force's drag-to-fix, and only while a layout can move the point back: cosmos.gl moves a\n // dragged point with the simulation off too, and a pin nothing pulls against means nothing.\n onDragEnd: () => {\n const vertex = dragging;\n dragging = null;\n const { motion, pinned } = store.getSnapshot();\n if (vertex !== null && motion !== \"settled\" && !pinned.includes(vertex)) store.pin([...pinned, vertex]);\n },\n onPointClick: (index) => focusOn(index),\n onBackgroundClick: () => clear(),\n });\n } catch (error) {\n fail(new GraphError(\"graph/no-webgl\", \"The renderer failed to start.\", {}, { cause: error }));\n return null;\n }\n const { camera, taken } = createCamera(graph, host);\n\n const schedule = () => {\n if (frame) return;\n frame = requestAnimationFrame(() => {\n frame = 0;\n draw();\n });\n };\n\n function draw(): void {\n const snapshot = store.getSnapshot();\n const { geometry, encoding } = snapshot;\n const options = store.getOptions();\n let changed = false;\n if (dirty.positions && geometry) {\n dirty.positions = false;\n graph.setPointPositions(placed(geometry, frameExtent(geometry), snapshot.mask), true);\n if (geometry.links !== links) {\n links = geometry.links;\n graph.setLinks(links);\n dirty.paint = dirty.state = dirty.pinned = true;\n }\n changed = true;\n }\n if (dirty.paint && geometry && encoding) {\n dirty.paint = false;\n const buffers = paint(geometry, encoding, look, host, options);\n graph.setPointColors(buffers.colors);\n graph.setPointSizes(buffers.sizes);\n graph.setPointShapes(buffers.shapes);\n graph.setLinkColors(buffers.linkColors);\n graph.setConfigPartial(appearance(look, host));\n changed = true;\n }\n if (dirty.state && geometry) {\n dirty.state = false;\n graph.setConfigPartial({\n highlightedPointIndices: snapshot.selection ? snapshot.selection.vertices.filter((id) => id < geometry.size) : undefined,\n focusedPointIndex: snapshot.focus === null || snapshot.focus >= geometry.size ? undefined : snapshot.focus,\n });\n }\n if (dirty.pinned && geometry) {\n dirty.pinned = false;\n graph.setPinnedPoints(snapshot.pinned.length > 0 ? [...snapshot.pinned] : null);\n }\n if (changed) graph.render();\n if (geometry && encoding && !dirty.paint) store.reportDrawn(snapshot);\n events.onFrame?.();\n }\n\n function frameExtent(geometry: Geometry): Placement {\n if (geometry === framed) return placement ?? UNPLACED;\n if (!geometry.extent) return UNPLACED;\n framed = geometry;\n placement = placementOf(geometry.extent, box as number);\n graph.setConfigPartial({ spaceSize: placement.side });\n camera.frame(cornersOf(geometry.extent, placement));\n return placement;\n }\n\n function applyForces(patch: Partial<Sim> | undefined): void {\n const next = resolveSim(patch);\n const moved = Object.keys(next).some((key) => next[key as keyof Sim] !== sim[key as keyof Sim]);\n sim = next;\n if (!live) return;\n graph.setConfigPartial(forces(next));\n if (moved && store.getSnapshot().motion !== \"paused\") graph.start(REHEAT);\n }\n\n /** A layout runs from where the points are: enabling cosmos.gl's simulation keeps its positions. */\n function run(alpha: number): void {\n if (!live) {\n live = true;\n graph.setConfigPartial({ enableSimulation: true, ...forces(sim) });\n }\n camera.run();\n graph.start(alpha);\n }\n\n function endBurst(): void {\n clearTimeout(burst);\n burst = 0;\n }\n\n function focusOn(vertex: VertexId): void {\n const around = graph.getNeighboringPointIndices(vertex) ?? [];\n store.select([vertex, ...around], \"node\", \"Node\");\n store.focus(vertex);\n }\n\n function clear(): void {\n store.select(null);\n store.focus(null);\n }\n\n // cosmos.gl 3.4 queues every setter and command until its device exists (`ensureDevice`), and its\n // two synchronous hit tests answer `[]` until then; only the canvas element has to wait for `ready`.\n graph.setConfigPartial(appearance(look, host));\n graph.render();\n const onLost = (event: Event) => {\n event.preventDefault();\n fail(new GraphError(\"graph/context-lost\", \"The browser took back the WebGL context; reload to get one.\"));\n };\n const noDevice = (data: GraphError[\"data\"], cause?: unknown) =>\n fail(new GraphError(\"graph/no-webgl\", \"No GPU device came up to draw with.\", data, { cause }));\n // `ready` never settles when cosmos.gl cannot make a device, so the deadline is what ends the wait.\n const deadline = setTimeout(() => noDevice({ after: READY_DEADLINE }), READY_DEADLINE);\n void graph.ready.then(\n () => {\n clearTimeout(deadline);\n if (!destroyed) host.querySelector(\"canvas\")?.addEventListener(\"webglcontextlost\", onLost);\n },\n (error: unknown) => {\n clearTimeout(deadline);\n noDevice({}, error);\n },\n );\n store.report(live && graph.isSimulationRunning ? \"running\" : \"settled\");\n schedule();\n\n const unsubscribe = store.subscribe(() => {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n if (snapshot.geometry !== last.geometry || snapshot.mask !== last.mask) dirty.positions = true;\n if (snapshot.encoding !== last.encoding) dirty.paint = true;\n if (options.look !== lookPatch) {\n lookPatch = options.look;\n look = resolveLook(options.look);\n dirty.paint = true;\n }\n if (options.fill !== lastOptions.fill || options.symbol !== lastOptions.symbol || options.stroke !== lastOptions.stroke) {\n dirty.paint = true;\n }\n if (snapshot.selection !== last.selection || snapshot.focus !== last.focus) dirty.state = true;\n if (snapshot.pinned !== last.pinned) dirty.pinned = true;\n if (options.sim !== lastOptions.sim) applyForces(options.sim);\n if ((options.simulate ?? false) !== (lastOptions.simulate ?? false)) {\n endBurst();\n if (options.simulate) run(REHEAT);\n else graph.pause();\n }\n last = snapshot;\n lastOptions = options;\n if (dirty.positions || dirty.paint || dirty.state || dirty.pinned) schedule();\n });\n\n return {\n graph,\n repaint() {\n dirty.paint = true;\n schedule();\n },\n hit(shape) {\n const found = \"rect\" in shape ? graph.findPointsInRect(shape.rect) : graph.findPointsInPolygon(shape.polygon);\n return Array.from(found);\n },\n zoomBy(factor) {\n graph.setZoomLevel(graph.getZoomLevel() * factor, 220);\n },\n fit: () => camera.fit(),\n pause() {\n endBurst();\n graph.pause();\n },\n resume() {\n endBurst();\n const settled = store.getSnapshot().motion === \"settled\";\n if (settled || !live) run(REHEAT);\n else graph.unpause();\n },\n restart() {\n endBurst();\n store.pin([]);\n run(1);\n },\n /**\n * d3's release: unfix, then reheat, so the released points visibly flow back. A running layout\n * takes the heat and goes on; a settled one cools to settled on its own; a paused one gets a\n * bounded burst and is paused again, because the reader paused it.\n */\n unpin() {\n const { motion, pinned } = store.getSnapshot();\n if (pinned.length === 0) return;\n endBurst();\n store.pin([]);\n run(REHEAT);\n if (motion === \"paused\") {\n burst = window.setTimeout(() => {\n burst = 0;\n graph.pause();\n }, RELEASE_BURST);\n }\n },\n reveal(vertex) {\n if (vertex >= size()) return;\n focusOn(vertex);\n graph.zoomToPointByIndex(vertex, 500, 5, true);\n },\n frameSelection() {\n const vertices = (store.getSnapshot().selection?.vertices ?? []).filter((id) => id < size());\n if (vertices.length > 0) graph.fitViewByPointIndices(vertices, FIT_DURATION, 0.25);\n },\n clear,\n destroy() {\n unsubscribe();\n endBurst();\n if (frame) cancelAnimationFrame(frame);\n clearTimeout(deadline);\n camera.destroy();\n destroyed = true;\n // Read here rather than remembered from construction: the element exists only with the device.\n const canvas = host.querySelector(\"canvas\");\n canvas?.removeEventListener(\"webglcontextlost\", onLost);\n graph.destroy();\n releaseContext(canvas);\n },\n };\n}\n"],"names":["REHEAT","RELEASE_BURST","PROGRESS_STEPS","READY_DEADLINE","createRenderer","host","store","events","destroyed","fail","error","box","webglBox","GraphError","sim","resolveSim","live","hovering","dragging","burst","reported","progress","value","bucket","look","resolveLook","lookPatch","dirty","frame","framed","placement","links","last","lastOptions","size","_a","graph","Graph","forces","camera","_alpha","index","position","_b","_event","userDriven","taken","event","vertex","motion","pinned","focusOn","clear","createCamera","schedule","draw","snapshot","geometry","encoding","options","changed","placed","frameExtent","buffers","paint","appearance","id","UNPLACED","placementOf","cornersOf","applyForces","patch","next","moved","key","run","alpha","endBurst","around","onLost","noDevice","data","cause","deadline","unsubscribe","shape","found","factor","vertices","FIT_DURATION","canvas","releaseContext"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"renderer.js","sources":["../../src/render/renderer.ts"],"sourcesContent":["import { Graph } from \"@cosmos.gl/graph\";\nimport { GraphError } from \"../core/error\";\nimport type { Geometry } from \"../core/load\";\nimport type { GraphStore } from \"../core/store\";\nimport type { GraphCommands, Motion, VertexId } from \"../core/types\";\nimport { resolveLook, type Look } from \"./graph-looks\";\nimport { appearance, forces, paint } from \"./graph-model\";\nimport { resolveSim, type Sim } from \"./graph-sim\";\nimport { createCamera, FIT_DURATION } from \"./camera\";\nimport { decayFor, highlighted, LINKS_WHILE_RUNNING, simulating } from \"./motion\";\nimport { cornersOf, placed, placementOf } from \"./placement\";\nimport { releaseContext, webglBox } from \"./webgl\";\n\nexport interface RendererEvents {\n /** After every frame and every camera move — where the overlays repaint. */\n onFrame?: () => void;\n /** Where the hovered point is in space, as cosmos.gl reports it: no GPU readback per hover. */\n onHover?: (position: [number, number] | null) => void;\n}\n\nexport interface Renderer extends GraphCommands {\n readonly graph: Graph;\n /** The theme moved under the canvas: colours are resolved again, nothing else. */\n repaint(): void;\n /** The drawn points inside a screen rectangle or polygon, once the device is ready. */\n hit(shape: { rect: [[number, number], [number, number]] } | { polygon: [number, number][] }): number[];\n destroy(): void;\n}\n\nconst REHEAT = 0.35;\n/** How long a release wakes a paused layout before pausing it again. */\nconst RELEASE_BURST = 1200;\n/** Twentieths: a settle costs twenty reports rather than one per frame. */\nconst PROGRESS_STEPS = 20;\n\n/**\n * The slowest honest answer for a GPU device: one comes up in milliseconds when it can be made at\n * all, so ten seconds is a device that will not come, not one that is slow.\n */\nconst READY_DEADLINE = 10_000;\n\n/**\n * **cosmos.gl's lifetime, and the frame that renders once.** Built once per element; it subscribes to\n * the store and discharges what changed in one `requestAnimationFrame`:\n *\n * - a new graph uploads positions and links, once per corpus and per position binding;\n * - a binding, a look or a theme change uploads colours, sizes, shapes and clusters and nothing else;\n * - a filter, a selection, a focus or a pin sets config and uploads nothing, and never calls\n * `render()`: a vertex the page's filter does not keep is greyed out, Cosmograph's way, so the\n * points never move because a chart was brushed;\n * - the camera reaches nothing: cosmos.gl moves it, and the overlays follow.\n *\n * A vertex's id is its index here, so nothing is resolved between the store and the buffers.\n * `transitionDuration` is 0: the default animates every upload for 800 ms and keeps the loop awake.\n * The layout runs on its own when `x` and `y` are unbound, and from the current positions.\n * Every callback reads the store's latest options, so a host's inline `onFailure` never rebuilds it.\n * A failure to draw at all marks the store `failed` through `unrenderable`, never `onFailure` alone.\n */\nexport function createRenderer(host: HTMLDivElement, store: GraphStore, events: RendererEvents = {}): Renderer | null {\n let destroyed = false;\n const fail = (error: unknown) => {\n if (!destroyed) store.unrenderable(error);\n };\n const box = webglBox();\n if (box === null) {\n fail(new GraphError(\"graph/no-webgl\", \"This browser offers no WebGL context to draw with.\"));\n return null;\n }\n\n let sim: Sim = resolveSim(store.getOptions().sim);\n let live = false;\n /** Whether a layout is moving the points — ours, since cosmos.gl's flag waits for its device. */\n let moving = false;\n let hovering: number | null = null;\n let dragging: number | null = null;\n let burst = 0;\n let reported = -1;\n const progress = (value: number) => {\n const bucket = Math.round(value * PROGRESS_STEPS);\n if (bucket === reported) return;\n reported = bucket;\n store.reportProgress(bucket / PROGRESS_STEPS);\n };\n\n let look: Look = resolveLook(store.getOptions().look);\n let lookPatch = store.getOptions().look;\n const dirty = { positions: true, paint: true, state: true, pinned: true };\n let frame = 0;\n let links: Float32Array | null = null;\n let last = store.getSnapshot();\n let lastOptions = store.getOptions();\n\n const size = () => store.getSnapshot().geometry?.size ?? 0;\n\n let graph: Graph;\n try {\n graph = new Graph(host, {\n // No `spaceSize` here: it is the geometry's, set when the graph has loaded.\n // `rescalePositions: false` because the placement below is ours.\n rescalePositions: false,\n fitViewOnInit: false,\n transitionDuration: 0,\n enableSimulation: live,\n ...forces(sim),\n randomSeed: \"kanzo-discovery\",\n pixelRatio: window.devicePixelRatio || 1,\n enableDrag: true,\n hoveredPointCursor: \"pointer\",\n attribution: \"\",\n onSimulationStart: () => store.report(\"running\"),\n onSimulationEnd: () => {\n moved(\"settled\");\n progress(1);\n camera.settle();\n events.onFrame?.();\n },\n onSimulationPause: () => moved(\"paused\"),\n onSimulationUnpause: () => moved(\"running\"),\n onSimulationTick: (_alpha, index, position) => {\n progress(graph.progress);\n camera.tick();\n if (index !== undefined && position) events.onHover?.(position);\n events.onFrame?.();\n },\n onZoomStart: (_event, userDriven) => taken(userDriven),\n onZoom: () => events.onFrame?.(),\n onPointMouseOver: (index, position) => {\n hovering = index;\n events.onHover?.(position);\n store.hover(index);\n },\n onPointMouseOut: () => {\n hovering = null;\n events.onHover?.(null);\n store.hover(null);\n },\n onDragStart: () => {\n dragging = hovering;\n },\n onDrag: (event) => {\n events.onHover?.(graph.screenToSpacePosition([event.x, event.y]));\n events.onFrame?.();\n },\n // d3-force's drag-to-fix, and only while a layout can move the point back: cosmos.gl moves a\n // dragged point with the simulation off too, and a pin nothing pulls against means nothing.\n onDragEnd: () => {\n const vertex = dragging;\n dragging = null;\n const { motion, pinned } = store.getSnapshot();\n if (vertex !== null && motion !== \"settled\" && !pinned.includes(vertex)) store.pin([...pinned, vertex]);\n },\n onPointClick: (index) => focusOn(index),\n onBackgroundClick: () => clear(),\n });\n } catch (error) {\n fail(new GraphError(\"graph/no-webgl\", \"The renderer failed to start.\", {}, { cause: error }));\n return null;\n }\n const { camera, taken } = createCamera(graph, host, fail);\n\n const schedule = () => {\n if (frame) return;\n frame = requestAnimationFrame(() => {\n frame = 0;\n draw();\n });\n };\n\n function draw(): void {\n const snapshot = store.getSnapshot();\n const { geometry, encoding } = snapshot;\n const options = store.getOptions();\n // Positions wait for the first colours, so a graph's first frame is the drawn one, not a grey one.\n const placing = dirty.positions && encoding ? geometry : null;\n if (placing) {\n dirty.positions = false;\n graph.setPointPositions(position(placing), true);\n if (placing.links !== links) {\n links = placing.links;\n graph.setLinks(links);\n dirty.paint = dirty.state = dirty.pinned = true;\n }\n }\n const painting = dirty.paint && geometry && encoding;\n if (painting) {\n dirty.paint = false;\n const buffers = paint(geometry, encoding, look, host, options);\n graph.setPointColors(buffers.colors);\n graph.setPointSizes(buffers.sizes);\n graph.setPointShapes(buffers.shapes);\n graph.setLinkColors(buffers.linkColors);\n graph.setPointClusters(encoding.clusters ?? []);\n graph.setConfigPartial({ ...appearance(look, host), renderLinks: linksShown() });\n }\n if (dirty.state && geometry) {\n dirty.state = false;\n graph.setConfigPartial({\n ...highlighted(geometry, snapshot.mask, snapshot.selection?.vertices ?? null),\n focusedPointIndex: snapshot.focus === null || snapshot.focus >= geometry.size ? undefined : snapshot.focus,\n });\n }\n if (dirty.pinned && geometry) {\n dirty.pinned = false;\n graph.setPinnedPoints(snapshot.pinned.length > 0 ? [...snapshot.pinned] : null);\n }\n if (painting || placing) graph.render();\n if (placing) layout(placing, simulating(options, placing)); // after render(): cosmos.gl 3.4 turning its simulation on drops unrendered uploads\n if (geometry && encoding && !dirty.paint) store.reportDrawn(snapshot);\n events.onFrame?.();\n }\n\n /** The positions cosmos.gl gets: bound, the data's extent centred in the device's box; unbound, the seeded start. */\n function position(geometry: Geometry): Float32Array {\n const placement = geometry.bound && geometry.extent ? placementOf(geometry.extent, box as number) : null;\n graph.setConfigPartial({ spaceSize: placement?.side ?? geometry.space, simulationDecay: decayFor(geometry.size) });\n if (!placement || !geometry.extent) return geometry.positions;\n camera.frame(cornersOf(geometry.extent, placement));\n return placed(geometry.positions, placement);\n }\n\n /** A new geometry lays itself out when its positions are a start, and stands still when they are data. */\n function layout(geometry: Geometry, running: boolean): void {\n camera.drawn();\n if (running) return run(1);\n if (live) graph.pause();\n if (!geometry.bound) camera.fit();\n }\n\n /** Whether links are drawn now: the look's choice, unless a large layout is running. */\n const linksShown = (): boolean => look.link.render && !(moving && (links?.length ?? 0) / 2 > LINKS_WHILE_RUNNING);\n const showLinks = () => graph.setConfigPartial({ renderLinks: linksShown() });\n function moved(motion: Motion): void {\n moving = motion === \"running\";\n showLinks();\n store.report(motion);\n }\n\n function applyForces(patch: Partial<Sim> | undefined): void {\n const next = resolveSim(patch);\n const moved = Object.keys(next).some((key) => next[key as keyof Sim] !== sim[key as keyof Sim]);\n sim = next;\n if (!live) return;\n graph.setConfigPartial(forces(next));\n if (moved && store.getSnapshot().motion !== \"paused\") graph.start(REHEAT);\n }\n\n /** A layout runs from where the points are: enabling cosmos.gl's simulation keeps its positions. */\n function run(alpha: number): void {\n if (!live) {\n live = true;\n graph.setConfigPartial({ enableSimulation: true, ...forces(sim) });\n }\n camera.run();\n moving = true;\n graph.start(alpha);\n showLinks();\n }\n\n function endBurst(): void {\n clearTimeout(burst);\n burst = 0;\n }\n\n function focusOn(vertex: VertexId): void {\n const around = graph.getNeighboringPointIndices(vertex) ?? [];\n store.select([vertex, ...around], \"node\", \"Node\");\n store.focus(vertex);\n }\n\n function clear(): void {\n store.select(null);\n store.focus(null);\n }\n\n // cosmos.gl 3.4 queues every setter and command until its device exists (`ensureDevice`), and its\n // two synchronous hit tests answer `[]` until then; only the canvas element has to wait for `ready`.\n graph.setConfigPartial(appearance(look, host));\n graph.render();\n const onLost = (event: Event) => {\n event.preventDefault();\n fail(new GraphError(\"graph/context-lost\", \"The browser took back the WebGL context; reload to get one.\"));\n };\n const noDevice = (data: GraphError[\"data\"], cause?: unknown) =>\n fail(new GraphError(\"graph/no-webgl\", \"No GPU device came up to draw with.\", data, { cause }));\n // `ready` never settles when cosmos.gl cannot make a device, so the deadline is what ends the wait.\n const deadline = setTimeout(() => noDevice({ after: READY_DEADLINE }), READY_DEADLINE);\n void graph.ready.then(\n () => {\n clearTimeout(deadline);\n if (!destroyed) host.querySelector(\"canvas\")?.addEventListener(\"webglcontextlost\", onLost);\n camera.ready();\n },\n (error: unknown) => {\n clearTimeout(deadline);\n noDevice({}, error);\n },\n );\n store.report(live && graph.isSimulationRunning ? \"running\" : \"settled\");\n schedule();\n\n const unsubscribe = store.subscribe(() => {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n if (snapshot.geometry !== last.geometry) dirty.positions = true;\n if (snapshot.encoding !== last.encoding) dirty.paint = true;\n if (options.look !== lookPatch) {\n lookPatch = options.look;\n look = resolveLook(options.look);\n dirty.paint = true;\n }\n if (options.fill !== lastOptions.fill || options.symbol !== lastOptions.symbol || options.stroke !== lastOptions.stroke) {\n dirty.paint = true;\n }\n if (snapshot.selection !== last.selection || snapshot.focus !== last.focus || snapshot.mask !== last.mask) dirty.state = true;\n if (snapshot.pinned !== last.pinned) dirty.pinned = true;\n if (options.sim !== lastOptions.sim) applyForces(options.sim);\n const wants = simulating(options, snapshot.geometry);\n if (snapshot.geometry === last.geometry && wants !== simulating(lastOptions, last.geometry)) {\n endBurst();\n if (wants) run(REHEAT);\n else graph.pause();\n }\n last = snapshot;\n lastOptions = options;\n if (dirty.positions || dirty.paint || dirty.state || dirty.pinned) schedule();\n });\n\n return {\n graph,\n repaint() {\n dirty.paint = true;\n schedule();\n },\n hit(shape) {\n const found = \"rect\" in shape ? graph.findPointsInRect(shape.rect) : graph.findPointsInPolygon(shape.polygon);\n return Array.from(found);\n },\n zoomBy(factor) {\n graph.setZoomLevel(graph.getZoomLevel() * factor, 220);\n },\n fit: () => camera.fit(),\n pause() {\n endBurst();\n graph.pause();\n },\n resume() {\n endBurst();\n const settled = store.getSnapshot().motion === \"settled\";\n if (settled || !live) run(REHEAT);\n else graph.unpause();\n },\n restart() {\n endBurst();\n store.pin([]);\n run(1);\n },\n /**\n * d3's release: unfix, then reheat, so the released points visibly flow back. A running layout\n * takes the heat and goes on; a settled one cools to settled on its own; a paused one gets a\n * bounded burst and is paused again, because the reader paused it.\n */\n unpin() {\n const { motion, pinned } = store.getSnapshot();\n if (pinned.length === 0) return;\n endBurst();\n store.pin([]);\n run(REHEAT);\n if (motion === \"paused\") {\n burst = window.setTimeout(() => {\n burst = 0;\n graph.pause();\n }, RELEASE_BURST);\n }\n },\n reveal(vertex) {\n if (vertex >= size()) return;\n focusOn(vertex);\n graph.zoomToPointByIndex(vertex, 500, 5, true);\n },\n frameSelection() {\n const vertices = (store.getSnapshot().selection?.vertices ?? []).filter((id) => id < size());\n if (vertices.length > 0) graph.fitViewByPointIndices(vertices, FIT_DURATION, 0.25);\n },\n clear,\n destroy() {\n unsubscribe();\n endBurst();\n if (frame) cancelAnimationFrame(frame);\n clearTimeout(deadline);\n camera.destroy();\n destroyed = true;\n // Read here rather than remembered from construction: the element exists only with the device.\n const canvas = host.querySelector(\"canvas\");\n canvas?.removeEventListener(\"webglcontextlost\", onLost);\n graph.destroy();\n releaseContext(canvas);\n },\n };\n}\n"],"names":["REHEAT","RELEASE_BURST","PROGRESS_STEPS","READY_DEADLINE","createRenderer","host","store","events","destroyed","fail","error","box","webglBox","GraphError","sim","resolveSim","live","moving","hovering","dragging","burst","reported","progress","value","bucket","look","resolveLook","lookPatch","dirty","frame","links","last","lastOptions","size","_a","graph","Graph","forces","moved","camera","_alpha","index","position","_b","_event","userDriven","taken","event","vertex","motion","pinned","focusOn","clear","createCamera","schedule","draw","snapshot","geometry","encoding","options","placing","painting","buffers","paint","appearance","linksShown","highlighted","layout","simulating","placement","placementOf","decayFor","cornersOf","placed","running","run","LINKS_WHILE_RUNNING","showLinks","applyForces","patch","next","key","alpha","endBurst","around","onLost","noDevice","data","cause","deadline","unsubscribe","wants","shape","found","factor","vertices","id","FIT_DURATION","canvas","releaseContext"],"mappings":"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"}
|
package/dist/section.js
CHANGED
|
@@ -125,7 +125,7 @@ const e = {
|
|
|
125
125
|
kind: "range",
|
|
126
126
|
label: "Cluster pull",
|
|
127
127
|
default: "0.1",
|
|
128
|
-
doc: "Pull toward the
|
|
128
|
+
doc: "Pull toward the centre of the vertex's cluster, when a column is bound to `cluster`. Zero lets the links decide alone.",
|
|
129
129
|
min: 0,
|
|
130
130
|
max: 1,
|
|
131
131
|
step: 0.05
|
package/dist/section.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"section.js","sources":["../src/section.ts"],"sourcesContent":["/**\n * The manifest shape, re-declared structurally rather than imported from `@kanzo-tech/theme`.\n *\n * Third instance of the same call in this repository, and the same reasoning each time: the type is\n * a *shape*, the value is data, and importing it would add a dependency to carry no code. Here it\n * also keeps the arrow pointing one way — a section contributes to the core, and the core does not\n * know it exists, so neither package should have to name the other to make that true.\n *\n * `packages/theme/src/sections.ts` is the definition this conforms to. Two structural declarations\n * can drift; what stops it is that a mismatch is a `tsc` error the moment a host passes this to\n * `validateSection`, which `docs/` does.\n */\ntype PrefCommon_ = { default: string; doc: string; label?: string };\ntype SectionPrefDecl_ =\n | (PrefCommon_ & { kind: \"choice\"; options: readonly { value: string; label: string }[] })\n | (PrefCommon_ & { kind: \"toggle\" })\n | (PrefCommon_ & { kind: \"range\"; min: number; max: number; step: number });\n\ninterface SectionManifest {\n namespace: string;\n version: number;\n tokens?: Readonly<Record<string, { default: string; doc: string }>>;\n prefs?: Readonly<Record<string, SectionPrefDecl_>>;\n}\n\n/**\n * The graph's contribution to a host's preferences — its tokens and its choices.\n *\n * **It was `LOOK_SECTION`, and the name was half of it.** The look is five of the sixteen\n * preferences below; the rest are the edge layer, the dot grid and the six force coefficients, which\n * lived in a `Display` interface and a `Sim` interface with their own defaults and their own\n * hand-rolled sliders. One section, one storage shape, one resolution, one renderer.\n *\n * Reached by subpath — `@kanzo-tech/graph/section` — and never imported by\n * `@kanzo-tech/theme`. That direction is the whole design: contributing is *using* a namespace, not\n * registering a type in the core, so a consumer who never installs this package pays nothing and\n * `packages/ui` gains no reference to the graph.\n *\n * ## Four colour tokens are gone, and the rule that removed them is the same one\n *\n * A name is worth having when a theme would plausibly give it a value **different from the token it\n * comes out of**. If it can only ever repeat one, it is not a name, it is a use. Applied here:\n *\n * · `vignette` defaulted to `--background`, and the rim fades *toward the page* — any other value\n * breaks it. It could never differ, so the canvas reads `--background` directly.\n * · `marquee-edge` and `point-ring-focus` both defaulted to `--primary`. A selection outline IS the\n * brand; two names for \"the brand, solid\" is the duplication, not the flexibility.\n * · `marquee` was `(brand, alpha 5)` — a *dilution*, which is a derivation and not a name. It is\n * `color-mix` where it is drawn.\n *\n * What that costs is the capacity for a tenant to redirect them, and measured against the rule\n * nobody wants it: redirecting `vignette` is breaking it. It is the same rule that removed seventeen\n * level-names from the core's vocabulary, applied to a section rather than to the core — which is\n * the half that had not been done.\n *\n * `grid` survives, and it is the only one that is arguable: a dot grid is decorative and drawn at a\n * different weight from a border, so a theme might plausibly want it fainter. If no theme ever does,\n * it goes too.\n *\n * **A default is a CSS value now, not an object.** It was `{kind, ramp, step}` in three shapes, two\n * of which named a reference tier that no longer exists; `var(--border)` says the same thing with\n * nothing between it and the browser, and the type it mirrored no longer has to be declared\n * structurally in two packages at once.\n */\nexport const GRAPH_SECTION: SectionManifest = {\n namespace: \"graph\",\n version: 1,\n tokens: {\n grid: {\n default: \"var(--border)\",\n doc: \"The dot grid behind the canvas. Decorative, and WCAG 1.4.11 exempts a non-interactive separator by name.\",\n },\n \"point-ring-hover\": {\n default: \"var(--primary)\",\n doc: \"The ring drawn around a hovered point.\",\n },\n },\n prefs: {\n marks: {\n kind: \"choice\",\n label: \"Marks\",\n default: \"dense\",\n doc: \"How much ink a point spends. The legible mark is the one to pair the shape channel with — its radius floor is what keeps shape from corrupting the size ramp beside it.\",\n options: [\n { value: \"dense\", label: \"Dense\" },\n { value: \"legible\", label: \"Legible\" },\n ],\n },\n \"additive-links\": {\n kind: \"toggle\",\n label: \"Additive links\",\n default: \"false\",\n doc: \"Links add where they overlap instead of compositing over one another. Additive light is what makes a dense graph read as flow — and what made 4,280 links at 0.45 swallow 1,543 points on the archive.\",\n },\n \"bowed-links\": {\n kind: \"toggle\",\n label: \"Bowed links\",\n default: \"true\",\n doc: \"Links bow off the straight line by a hint, which is enough to tell two parallel edges apart. Every link curves the same way, so more than a hint reads as a pinwheel.\",\n },\n labels: {\n kind: \"range\",\n label: \"Labels\",\n default: \"26\",\n doc: \"How many of the highest-degree nodes carry a standing label. Zero draws none.\",\n min: 0,\n max: 60,\n step: 2,\n },\n vignette: {\n kind: \"toggle\",\n label: \"Vignette\",\n default: \"false\",\n doc: \"A darkened rim. Mood rather than a reading aid, which is why it is a preference and not a display control.\",\n },\n links: {\n kind: \"toggle\",\n label: \"Show links\",\n default: \"true\",\n doc: \"Draw the edge layer at all. Past a few hundred thousand links it is fog that costs a draw call a frame.\",\n },\n grid: {\n kind: \"toggle\",\n label: \"Dot grid\",\n default: \"true\",\n doc: \"The dot grid behind the graph. It pans and subdivides with the camera, which is what makes a pan read as motion rather than as a redraw.\",\n },\n\n /**\n * The force coefficients, which are preferences and were a second vocabulary.\n *\n * **They are not appearance, and this manifest holds them anyway.** A section's `tokens` are the\n * colours a document may move; its `prefs` are *what the person on the screen decides*, and a\n * reader tuning a layout until it settles is deciding something. They lived in a TS interface\n * with a `DEFAULT_SIM` beside it and six hand-rolled sliders in one showcase's dock — the fourth\n * declaration style in a census of four, for a quarter of the knobs.\n *\n * The bounds are cosmos.gl's useful range rather than its legal one, and a stored value outside\n * them is declined: a slider that used to run to 5 and now stops at 3 must not paint 5 because\n * storage remembers it. These defaults are tuned for a few hundred nodes; a host with a large\n * corpus starts its users elsewhere through the tenant policy, rather than by writing values\n * into storage nobody can then reset.\n */\n gravity: {\n kind: \"range\",\n label: \"Gravity\",\n default: \"0.14\",\n doc: \"Pull toward the centre. It is what stops a disconnected component drifting off the canvas.\",\n min: 0,\n max: 0.5,\n step: 0.01,\n },\n repulsion: {\n kind: \"range\",\n label: \"Repulsion\",\n default: \"1.1\",\n doc: \"How hard every point pushes every other. Bigger graphs need less of it, or they never settle.\",\n min: 0,\n max: 2,\n step: 0.05,\n },\n \"link-spring\": {\n kind: \"range\",\n label: \"Link spring\",\n default: \"0.6\",\n doc: \"How hard a link pulls its two ends together.\",\n min: 0,\n max: 2,\n step: 0.05,\n },\n \"link-distance\": {\n kind: \"range\",\n label: \"Link distance\",\n default: \"18\",\n doc: \"The length a link is happy at, in simulation units.\",\n min: 2,\n max: 60,\n step: 1,\n },\n friction: {\n kind: \"range\",\n label: \"Friction\",\n default: \"0.86\",\n doc: \"How fast motion decays. Under about 0.7 the layout twitches; near 1 it never stops.\",\n min: 0.5,\n max: 0.99,\n step: 0.01,\n },\n cluster: {\n kind: \"range\",\n label: \"Cluster pull\",\n default: \"0.1\",\n doc: \"Pull toward the node's group position on the cluster ring. Zero lets the links decide alone.\",\n min: 0,\n max: 1,\n step: 0.05,\n },\n },\n};\n"],"names":["GRAPH_SECTION"],"mappings":"AAgEO,MAAMA,IAAiC;AAAA,EAC5C,WAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,oBAAoB;AAAA,MAClB,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,EACP;AAAA,EAEF,OAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,SAAS;AAAA,QACP,EAAE,OAAO,SAAS,OAAO,QAAA;AAAA,QACzB,EAAE,OAAO,WAAW,OAAO,UAAA;AAAA,MAAU;AAAA,IACvC;AAAA,IAEF,kBAAkB;AAAA,MAChB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,eAAe;AAAA,MACb,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,UAAU;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,OAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBP,SAAS;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,WAAW;AAAA,MACT,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,eAAe;AAAA,MACb,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,UAAU;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,SAAS;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"section.js","sources":["../src/section.ts"],"sourcesContent":["/**\n * The manifest shape, re-declared structurally rather than imported from `@kanzo-tech/theme`.\n *\n * Third instance of the same call in this repository, and the same reasoning each time: the type is\n * a *shape*, the value is data, and importing it would add a dependency to carry no code. Here it\n * also keeps the arrow pointing one way — a section contributes to the core, and the core does not\n * know it exists, so neither package should have to name the other to make that true.\n *\n * `packages/theme/src/sections.ts` is the definition this conforms to. Two structural declarations\n * can drift; what stops it is that a mismatch is a `tsc` error the moment a host passes this to\n * `validateSection`, which `docs/` does.\n */\ntype PrefCommon_ = { default: string; doc: string; label?: string };\ntype SectionPrefDecl_ =\n | (PrefCommon_ & { kind: \"choice\"; options: readonly { value: string; label: string }[] })\n | (PrefCommon_ & { kind: \"toggle\" })\n | (PrefCommon_ & { kind: \"range\"; min: number; max: number; step: number });\n\ninterface SectionManifest {\n namespace: string;\n version: number;\n tokens?: Readonly<Record<string, { default: string; doc: string }>>;\n prefs?: Readonly<Record<string, SectionPrefDecl_>>;\n}\n\n/**\n * The graph's contribution to a host's preferences — its tokens and its choices.\n *\n * **It was `LOOK_SECTION`, and the name was half of it.** The look is five of the sixteen\n * preferences below; the rest are the edge layer, the dot grid and the six force coefficients, which\n * lived in a `Display` interface and a `Sim` interface with their own defaults and their own\n * hand-rolled sliders. One section, one storage shape, one resolution, one renderer.\n *\n * Reached by subpath — `@kanzo-tech/graph/section` — and never imported by\n * `@kanzo-tech/theme`. That direction is the whole design: contributing is *using* a namespace, not\n * registering a type in the core, so a consumer who never installs this package pays nothing and\n * `packages/ui` gains no reference to the graph.\n *\n * ## Four colour tokens are gone, and the rule that removed them is the same one\n *\n * A name is worth having when a theme would plausibly give it a value **different from the token it\n * comes out of**. If it can only ever repeat one, it is not a name, it is a use. Applied here:\n *\n * · `vignette` defaulted to `--background`, and the rim fades *toward the page* — any other value\n * breaks it. It could never differ, so the canvas reads `--background` directly.\n * · `marquee-edge` and `point-ring-focus` both defaulted to `--primary`. A selection outline IS the\n * brand; two names for \"the brand, solid\" is the duplication, not the flexibility.\n * · `marquee` was `(brand, alpha 5)` — a *dilution*, which is a derivation and not a name. It is\n * `color-mix` where it is drawn.\n *\n * What that costs is the capacity for a tenant to redirect them, and measured against the rule\n * nobody wants it: redirecting `vignette` is breaking it. It is the same rule that removed seventeen\n * level-names from the core's vocabulary, applied to a section rather than to the core — which is\n * the half that had not been done.\n *\n * `grid` survives, and it is the only one that is arguable: a dot grid is decorative and drawn at a\n * different weight from a border, so a theme might plausibly want it fainter. If no theme ever does,\n * it goes too.\n *\n * **A default is a CSS value now, not an object.** It was `{kind, ramp, step}` in three shapes, two\n * of which named a reference tier that no longer exists; `var(--border)` says the same thing with\n * nothing between it and the browser, and the type it mirrored no longer has to be declared\n * structurally in two packages at once.\n */\nexport const GRAPH_SECTION: SectionManifest = {\n namespace: \"graph\",\n version: 1,\n tokens: {\n grid: {\n default: \"var(--border)\",\n doc: \"The dot grid behind the canvas. Decorative, and WCAG 1.4.11 exempts a non-interactive separator by name.\",\n },\n \"point-ring-hover\": {\n default: \"var(--primary)\",\n doc: \"The ring drawn around a hovered point.\",\n },\n },\n prefs: {\n marks: {\n kind: \"choice\",\n label: \"Marks\",\n default: \"dense\",\n doc: \"How much ink a point spends. The legible mark is the one to pair the shape channel with — its radius floor is what keeps shape from corrupting the size ramp beside it.\",\n options: [\n { value: \"dense\", label: \"Dense\" },\n { value: \"legible\", label: \"Legible\" },\n ],\n },\n \"additive-links\": {\n kind: \"toggle\",\n label: \"Additive links\",\n default: \"false\",\n doc: \"Links add where they overlap instead of compositing over one another. Additive light is what makes a dense graph read as flow — and what made 4,280 links at 0.45 swallow 1,543 points on the archive.\",\n },\n \"bowed-links\": {\n kind: \"toggle\",\n label: \"Bowed links\",\n default: \"true\",\n doc: \"Links bow off the straight line by a hint, which is enough to tell two parallel edges apart. Every link curves the same way, so more than a hint reads as a pinwheel.\",\n },\n labels: {\n kind: \"range\",\n label: \"Labels\",\n default: \"26\",\n doc: \"How many of the highest-degree nodes carry a standing label. Zero draws none.\",\n min: 0,\n max: 60,\n step: 2,\n },\n vignette: {\n kind: \"toggle\",\n label: \"Vignette\",\n default: \"false\",\n doc: \"A darkened rim. Mood rather than a reading aid, which is why it is a preference and not a display control.\",\n },\n links: {\n kind: \"toggle\",\n label: \"Show links\",\n default: \"true\",\n doc: \"Draw the edge layer at all. Past a few hundred thousand links it is fog that costs a draw call a frame.\",\n },\n grid: {\n kind: \"toggle\",\n label: \"Dot grid\",\n default: \"true\",\n doc: \"The dot grid behind the graph. It pans and subdivides with the camera, which is what makes a pan read as motion rather than as a redraw.\",\n },\n\n /**\n * The force coefficients, which are preferences and were a second vocabulary.\n *\n * **They are not appearance, and this manifest holds them anyway.** A section's `tokens` are the\n * colours a document may move; its `prefs` are *what the person on the screen decides*, and a\n * reader tuning a layout until it settles is deciding something. They lived in a TS interface\n * with a `DEFAULT_SIM` beside it and six hand-rolled sliders in one showcase's dock — the fourth\n * declaration style in a census of four, for a quarter of the knobs.\n *\n * The bounds are cosmos.gl's useful range rather than its legal one, and a stored value outside\n * them is declined: a slider that used to run to 5 and now stops at 3 must not paint 5 because\n * storage remembers it. These defaults are tuned for a few hundred nodes; a host with a large\n * corpus starts its users elsewhere through the tenant policy, rather than by writing values\n * into storage nobody can then reset.\n */\n gravity: {\n kind: \"range\",\n label: \"Gravity\",\n default: \"0.14\",\n doc: \"Pull toward the centre. It is what stops a disconnected component drifting off the canvas.\",\n min: 0,\n max: 0.5,\n step: 0.01,\n },\n repulsion: {\n kind: \"range\",\n label: \"Repulsion\",\n default: \"1.1\",\n doc: \"How hard every point pushes every other. Bigger graphs need less of it, or they never settle.\",\n min: 0,\n max: 2,\n step: 0.05,\n },\n \"link-spring\": {\n kind: \"range\",\n label: \"Link spring\",\n default: \"0.6\",\n doc: \"How hard a link pulls its two ends together.\",\n min: 0,\n max: 2,\n step: 0.05,\n },\n \"link-distance\": {\n kind: \"range\",\n label: \"Link distance\",\n default: \"18\",\n doc: \"The length a link is happy at, in simulation units.\",\n min: 2,\n max: 60,\n step: 1,\n },\n friction: {\n kind: \"range\",\n label: \"Friction\",\n default: \"0.86\",\n doc: \"How fast motion decays. Under about 0.7 the layout twitches; near 1 it never stops.\",\n min: 0.5,\n max: 0.99,\n step: 0.01,\n },\n cluster: {\n kind: \"range\",\n label: \"Cluster pull\",\n default: \"0.1\",\n doc: \"Pull toward the centre of the vertex's cluster, when a column is bound to `cluster`. Zero lets the links decide alone.\",\n min: 0,\n max: 1,\n step: 0.05,\n },\n },\n};\n"],"names":["GRAPH_SECTION"],"mappings":"AAgEO,MAAMA,IAAiC;AAAA,EAC5C,WAAW;AAAA,EACX,SAAS;AAAA,EACT,QAAQ;AAAA,IACN,MAAM;AAAA,MACJ,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,oBAAoB;AAAA,MAClB,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,EACP;AAAA,EAEF,OAAO;AAAA,IACL,OAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,SAAS;AAAA,QACP,EAAE,OAAO,SAAS,OAAO,QAAA;AAAA,QACzB,EAAE,OAAO,WAAW,OAAO,UAAA;AAAA,MAAU;AAAA,IACvC;AAAA,IAEF,kBAAkB;AAAA,MAChB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,eAAe;AAAA,MACb,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,QAAQ;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,UAAU;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,OAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA,IAEP,MAAM;AAAA,MACJ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,IAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAkBP,SAAS;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,WAAW;AAAA,MACT,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,eAAe;AAAA,MACb,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,iBAAiB;AAAA,MACf,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,UAAU;AAAA,MACR,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,IAER,SAAS;AAAA,MACP,MAAM;AAAA,MACN,OAAO;AAAA,MACP,SAAS;AAAA,MACT,KAAK;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL,MAAM;AAAA,IAAA;AAAA,EACR;AAEJ;"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanzo-tech/graph",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Kanzo graph view — a
|
|
3
|
+
"version": "0.27.0",
|
|
4
|
+
"description": "Kanzo graph view — a fossil corpus attached to the page's DuckDB, read through the page's Mosaic coordinator as one more client, laid out and drawn with cosmos.gl on the GPU. Sibling of @kanzo-tech/ui, not part of it: the admission rules exclude graphs from the generic vocabulary by name.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"sideEffects": false,
|
|
@@ -22,45 +22,43 @@
|
|
|
22
22
|
},
|
|
23
23
|
"./package.json": "./package.json"
|
|
24
24
|
},
|
|
25
|
-
"//peers": "All required. cosmos.gl draws; `lucide-react` is the icon set the parts draw their buttons with, `@kanzo-tech/ui`'s own peer; `@
|
|
26
|
-
"//fossil": "The
|
|
25
|
+
"//peers": "All required. cosmos.gl draws and lays out; `lucide-react` is the icon set the parts draw their buttons with, `@kanzo-tech/ui`'s own peer; `@kanzo-tech/mosaic` is the coordinator the graph reads through as a client and the crossfilter it listens to and publishes into. The Mosaic stack itself — mosaic-core, mosaic-sql — is `@kanzo-tech/mosaic`'s peer, declared once there.",
|
|
26
|
+
"//fossil": "The graph reads a corpus fossil's `open` (`@fossil-lang/corpus` ≥ 0.3.0-alpha.24) attached under a name — its tables, `fossil_tables` and `fossil_columns` — with SQL through the coordinator. It imports nothing of fossil's: the contract is the catalog, `/docs/format`.",
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"@cosmos.gl/graph": "^3.4.0",
|
|
29
|
-
"@fossil-lang/corpus": "^0.3.0-alpha.19",
|
|
30
29
|
"lucide-react": ">=1",
|
|
31
30
|
"react": "^19.0.0",
|
|
32
|
-
"@kanzo-tech/mosaic": "0.
|
|
33
|
-
"@kanzo-tech/ui": "0.
|
|
31
|
+
"@kanzo-tech/mosaic": "0.27.0",
|
|
32
|
+
"@kanzo-tech/ui": "0.27.0"
|
|
34
33
|
},
|
|
35
34
|
"devDependencies": {
|
|
36
35
|
"@cosmos.gl/graph": "^3.4.0",
|
|
37
|
-
"@
|
|
36
|
+
"@duckdb/duckdb-wasm": "1.33.1-dev57.0",
|
|
38
37
|
"@testing-library/dom": "^10.4.1",
|
|
39
38
|
"@testing-library/react": "^16.3.2",
|
|
40
39
|
"@testing-library/user-event": "^14.6.1",
|
|
41
40
|
"@types/react": "^19.0.0",
|
|
42
41
|
"@types/react-dom": "^19.0.0",
|
|
43
|
-
"@uwdata/mosaic-core": "^0.
|
|
44
|
-
"@uwdata/mosaic-sql": "^0.
|
|
42
|
+
"@uwdata/mosaic-core": "^0.32.0",
|
|
43
|
+
"@uwdata/mosaic-sql": "^0.32.0",
|
|
45
44
|
"jsdom": "^25.0.0",
|
|
46
45
|
"lucide-react": "^1.23.0",
|
|
47
46
|
"react": "^19.0.0",
|
|
48
47
|
"react-dom": "^19.0.0",
|
|
49
48
|
"rollup-plugin-preserve-directives": "^0.4.0",
|
|
50
|
-
"@kanzo-tech/mosaic": "0.
|
|
49
|
+
"@kanzo-tech/mosaic": "0.27.0"
|
|
51
50
|
},
|
|
52
|
-
"//size-limit": "Budgets our code only: `ignore` mirrors the peers the build externalises in vite.config.ts, cosmos.gl included (about 190 kB gzipped on its own, and the consumer pays it once whatever this package does). First measured 2026-09-30 at 19.07 kB, before the lag work of `perf/phase1-lag`; 19.13 kB before the whole-corpus store deleted the tileset, 15.29 kB after it, and the budget follows it down so real growth trips the gate. Raised to 18 kB on 2026-10-01 as a decision: 17.71 kB after GraphCounts, GraphSearch and GraphLooks moved in from the workspace showcase (their code left the host, it did not appear from nowhere) and the drag-to-fix release. Raised to 18.5 kB on 2026-10-02 as a decision (Ángel): 18.01 kB once the layout's square placement and the camera that follows a running layout landed.",
|
|
51
|
+
"//size-limit": "Budgets our code only: `ignore` mirrors the peers the build externalises in vite.config.ts, cosmos.gl included (about 190 kB gzipped on its own, and the consumer pays it once whatever this package does). First measured 2026-09-30 at 19.07 kB, before the lag work of `perf/phase1-lag`; 19.13 kB before the whole-corpus store deleted the tileset, 15.29 kB after it, and the budget follows it down so real growth trips the gate. Raised to 18 kB on 2026-10-01 as a decision: 17.71 kB after GraphCounts, GraphSearch and GraphLooks moved in from the workspace showcase (their code left the host, it did not appear from nowhere) and the drag-to-fix release. Raised to 18.5 kB on 2026-10-02 as a decision (Ángel): 18.01 kB once the layout's square placement and the camera that follows a running layout landed. Raised to 19 kB on 2026-10-03 as a decision (Ángel): 18.58 kB once GraphSelect moved in from the host (keasy and the workspace showcase drop their copies) and the camera stopped reading positions cosmos.gl had not uploaded.",
|
|
53
52
|
"size-limit": [
|
|
54
53
|
{
|
|
55
54
|
"name": "root barrel (JS)",
|
|
56
55
|
"path": "dist/index.js",
|
|
57
|
-
"limit": "
|
|
56
|
+
"limit": "19 kB",
|
|
58
57
|
"ignore": [
|
|
59
58
|
"react",
|
|
60
59
|
"react-dom",
|
|
61
60
|
"react/jsx-runtime",
|
|
62
61
|
"@cosmos.gl/graph",
|
|
63
|
-
"@fossil-lang/corpus",
|
|
64
62
|
"@kanzo-tech/mosaic",
|
|
65
63
|
"@kanzo-tech/ui",
|
|
66
64
|
"lucide-react"
|
package/dist/core/detail.d.ts
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { Corpus } from '@fossil-lang/corpus';
|
|
2
|
-
import { Geometry } from './load';
|
|
3
|
-
import { VertexId } from './types';
|
|
4
|
-
/** One vertex's row, as its table's properties order it — every column but the key and the position. */
|
|
5
|
-
export interface VertexDetail {
|
|
6
|
-
readonly vertex: VertexId;
|
|
7
|
-
/** The vertex table it belongs to. */
|
|
8
|
-
readonly table: string;
|
|
9
|
-
readonly fields: readonly {
|
|
10
|
-
readonly name: string;
|
|
11
|
-
readonly value: unknown;
|
|
12
|
-
}[];
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* **Detail is fetched, not carried.** The loaded graph holds positions and channels; the rest of a
|
|
16
|
-
* row is asked for when a reader focuses the vertex — a scan of its table, filtered to its key.
|
|
17
|
-
*/
|
|
18
|
-
export declare function readVertex(corpus: Corpus, geometry: Geometry, vertex: VertexId, signal?: AbortSignal): Promise<VertexDetail | null>;
|
|
19
|
-
/**
|
|
20
|
-
* **A label's text, for the few vertices that carry one** — `title` where the vertex's table has the
|
|
21
|
-
* column, and the table's declared `identity` where it does not. One scan per table they fall in.
|
|
22
|
-
*/
|
|
23
|
-
export declare function readTitles(corpus: Corpus, geometry: Geometry, vertices: readonly VertexId[], title: string | undefined, signal: AbortSignal): Promise<Map<VertexId, string>>;
|
|
24
|
-
/** **Every drawn vertex's text, by id** — what a search filters. One scan per drawn table, two columns. */
|
|
25
|
-
export declare function readEveryTitle(corpus: Corpus, geometry: Geometry, title: string | undefined, signal: AbortSignal): Promise<string[]>;
|
|
26
|
-
//# sourceMappingURL=detail.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detail.d.ts","sourceRoot":"","sources":["../../src/core/detail.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAe,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAY,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,wGAAwG;AACxG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,sCAAsC;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CAChF;AAKD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,MAAM,EAAE,QAAQ,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAa9B;AAMD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,QAAQ,EAAE,EAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAqBhC;AAED,2GAA2G;AAC3G,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,QAAQ,EAClB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,EAAE,WAAW,GAClB,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBnB"}
|
package/dist/core/detail.js
DELETED
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { together as h } from "./load.js";
|
|
2
|
-
const k = (o, e) => e < o.size ? o.tables[o.table[e]] : void 0;
|
|
3
|
-
async function C(o, e, r, y) {
|
|
4
|
-
var f, c;
|
|
5
|
-
const s = k(e, r);
|
|
6
|
-
if (!s) return null;
|
|
7
|
-
const u = /* @__PURE__ */ new Set([s.key, (f = s.position) == null ? void 0 : f.x, (c = s.position) == null ? void 0 : c.y]), a = s.properties.map((t) => t.name).filter((t) => !u.has(t)), i = o.scan({ table: s.name, filter: { column: s.key, op: "=", value: r }, select: [s.key, ...a], limit: 1 }), n = (await i.read(i.plan(), { signal: y })).find((t) => t.numRows > 0);
|
|
8
|
-
return n ? {
|
|
9
|
-
vertex: r,
|
|
10
|
-
table: s.name,
|
|
11
|
-
fields: a.map((t) => {
|
|
12
|
-
var m;
|
|
13
|
-
return { name: t, value: ((m = n.getChild(t)) == null ? void 0 : m.toArray()[0]) ?? null };
|
|
14
|
-
})
|
|
15
|
-
} : null;
|
|
16
|
-
}
|
|
17
|
-
const b = (o, e) => e !== void 0 && o.properties.some((r) => r.name === e) ? e : o.identity;
|
|
18
|
-
async function v(o, e, r, y, s) {
|
|
19
|
-
const u = /* @__PURE__ */ new Map();
|
|
20
|
-
for (const i of r) {
|
|
21
|
-
const n = k(e, i);
|
|
22
|
-
n && u.set(n, [...u.get(n) ?? [], i]);
|
|
23
|
-
}
|
|
24
|
-
const a = /* @__PURE__ */ new Map();
|
|
25
|
-
return await h(
|
|
26
|
-
s,
|
|
27
|
-
(i) => Promise.all(
|
|
28
|
-
[...u].map(async ([n, f]) => {
|
|
29
|
-
var m, d;
|
|
30
|
-
const c = b(n, y), t = o.scan({ table: n.name, filter: { column: n.key, op: "in", values: f }, select: [n.key, c] });
|
|
31
|
-
for (const l of await t.read(t.plan(), { signal: i })) {
|
|
32
|
-
const p = ((m = l.getChild(n.key)) == null ? void 0 : m.toArray()) ?? [], g = ((d = l.getChild(c)) == null ? void 0 : d.toArray()) ?? [];
|
|
33
|
-
for (let w = 0; w < l.numRows; w++) a.set(Number(p[w]), String(g[w] ?? ""));
|
|
34
|
-
}
|
|
35
|
-
})
|
|
36
|
-
)
|
|
37
|
-
), a;
|
|
38
|
-
}
|
|
39
|
-
async function x(o, e, r, y) {
|
|
40
|
-
const s = new Array(e.size).fill("");
|
|
41
|
-
return await h(
|
|
42
|
-
y,
|
|
43
|
-
(u) => Promise.all(
|
|
44
|
-
e.tables.map(async (a) => {
|
|
45
|
-
var f, c;
|
|
46
|
-
const i = b(a, r), n = o.scan({ table: a.name, select: [a.key, i] });
|
|
47
|
-
for (const t of await n.read(n.plan(), { signal: u })) {
|
|
48
|
-
const m = ((f = t.getChild(a.key)) == null ? void 0 : f.toArray()) ?? [], d = ((c = t.getChild(i)) == null ? void 0 : c.toArray()) ?? [];
|
|
49
|
-
for (let l = 0; l < t.numRows; l++) {
|
|
50
|
-
const p = Number(m[l]);
|
|
51
|
-
p < e.size && (s[p] = String(d[l] ?? ""));
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
})
|
|
55
|
-
)
|
|
56
|
-
), s;
|
|
57
|
-
}
|
|
58
|
-
export {
|
|
59
|
-
x as readEveryTitle,
|
|
60
|
-
v as readTitles,
|
|
61
|
-
C as readVertex
|
|
62
|
-
};
|
|
63
|
-
//# sourceMappingURL=detail.js.map
|
package/dist/core/detail.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"detail.js","sources":["../../src/core/detail.ts"],"sourcesContent":["import type { Corpus, VertexTable } from \"@fossil-lang/corpus\";\nimport { together, type Geometry } from \"./load\";\nimport type { VertexId } from \"./types\";\n\n/** One vertex's row, as its table's properties order it — every column but the key and the position. */\nexport interface VertexDetail {\n readonly vertex: VertexId;\n /** The vertex table it belongs to. */\n readonly table: string;\n readonly fields: readonly { readonly name: string; readonly value: unknown }[];\n}\n\nconst tableOf = (geometry: Geometry, vertex: VertexId): VertexTable | undefined =>\n vertex < geometry.size ? geometry.tables[geometry.table[vertex] as number] : undefined;\n\n/**\n * **Detail is fetched, not carried.** The loaded graph holds positions and channels; the rest of a\n * row is asked for when a reader focuses the vertex — a scan of its table, filtered to its key.\n */\nexport async function readVertex(\n corpus: Corpus,\n geometry: Geometry,\n vertex: VertexId,\n signal?: AbortSignal,\n): Promise<VertexDetail | null> {\n const table = tableOf(geometry, vertex);\n if (!table) return null;\n const hidden = new Set([table.key, table.position?.x, table.position?.y]);\n const names = table.properties.map((p) => p.name).filter((name) => !hidden.has(name));\n const scan = corpus.scan({ table: table.name, filter: { column: table.key, op: \"=\", value: vertex }, select: [table.key, ...names], limit: 1 });\n const rows = (await scan.read(scan.plan(), { signal })).find((batch) => batch.numRows > 0);\n if (!rows) return null;\n return {\n vertex,\n table: table.name,\n fields: names.map((name) => ({ name, value: rows.getChild(name)?.toArray()[0] ?? null })),\n };\n}\n\n/** The column a vertex's text is read from: `title` where its table has it, else the table's `identity`. */\nconst titleColumn = (table: VertexTable, title: string | undefined): string =>\n title !== undefined && table.properties.some((p) => p.name === title) ? title : table.identity;\n\n/**\n * **A label's text, for the few vertices that carry one** — `title` where the vertex's table has the\n * column, and the table's declared `identity` where it does not. One scan per table they fall in.\n */\nexport async function readTitles(\n corpus: Corpus,\n geometry: Geometry,\n vertices: readonly VertexId[],\n title: string | undefined,\n signal: AbortSignal,\n): Promise<Map<VertexId, string>> {\n const byTable = new Map<VertexTable, VertexId[]>();\n for (const vertex of vertices) {\n const table = tableOf(geometry, vertex);\n if (table) byTable.set(table, [...(byTable.get(table) ?? []), vertex]);\n }\n const found = new Map<VertexId, string>();\n await together(signal, (signal) =>\n Promise.all(\n [...byTable].map(async ([table, ids]) => {\n const column = titleColumn(table, title);\n const scan = corpus.scan({ table: table.name, filter: { column: table.key, op: \"in\", values: ids }, select: [table.key, column] });\n for (const batch of await scan.read(scan.plan(), { signal })) {\n const keys = batch.getChild(table.key)?.toArray() ?? [];\n const texts = batch.getChild(column)?.toArray() ?? [];\n for (let i = 0; i < batch.numRows; i++) found.set(Number(keys[i]), String(texts[i] ?? \"\"));\n }\n }),\n ),\n );\n return found;\n}\n\n/** **Every drawn vertex's text, by id** — what a search filters. One scan per drawn table, two columns. */\nexport async function readEveryTitle(\n corpus: Corpus,\n geometry: Geometry,\n title: string | undefined,\n signal: AbortSignal,\n): Promise<string[]> {\n const titles = new Array<string>(geometry.size).fill(\"\");\n await together(signal, (signal) =>\n Promise.all(\n geometry.tables.map(async (table) => {\n const column = titleColumn(table, title);\n const scan = corpus.scan({ table: table.name, select: [table.key, column] });\n for (const batch of await scan.read(scan.plan(), { signal })) {\n const keys = batch.getChild(table.key)?.toArray() ?? [];\n const texts = batch.getChild(column)?.toArray() ?? [];\n for (let i = 0; i < batch.numRows; i++) {\n const id = Number(keys[i]);\n if (id < geometry.size) titles[id] = String(texts[i] ?? \"\");\n }\n }\n }),\n ),\n );\n return titles;\n}\n"],"names":["tableOf","geometry","vertex","readVertex","corpus","signal","table","hidden","_a","_b","names","p","name","scan","rows","batch","titleColumn","title","readTitles","vertices","byTable","found","together","ids","column","keys","texts","i","readEveryTitle","titles","id"],"mappings":"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"}
|
package/dist/core/filter.d.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Filter } from '@fossil-lang/corpus';
|
|
2
|
-
import { MosaicClient, Selection } from '@kanzo-tech/mosaic';
|
|
3
|
-
/** One mosaic-sql expression node → one `Filter`. */
|
|
4
|
-
export declare function translate(node: unknown): Filter;
|
|
5
|
-
/** Every column a filter names, once each. */
|
|
6
|
-
export declare function columnsOf(filter: Filter): string[];
|
|
7
|
-
/**
|
|
8
|
-
* The page's filter for the graph, or `undefined` for none. `selection.predicate` skips the clause
|
|
9
|
-
* the graph published itself, which is the exemption the next function takes back.
|
|
10
|
-
*/
|
|
11
|
-
export declare function filterFor(selection: Selection, self: MosaicClient): Filter | undefined;
|
|
12
|
-
/**
|
|
13
|
-
* An identity for `clients`, and nothing more: it is never connected, so the coordinator never
|
|
14
|
-
* queries on its behalf.
|
|
15
|
-
*/
|
|
16
|
-
export declare function graphClient(): MosaicClient;
|
|
17
|
-
/**
|
|
18
|
-
* **The reader's pick, published** — naming the graph in `clients`, so the crossfilter skips it for
|
|
19
|
-
* the graph and applies it to every chart. A canvas that draws only what survives would otherwise
|
|
20
|
-
* answer a lasso of thirteen by removing the other 1,530.
|
|
21
|
-
*/
|
|
22
|
-
export declare function publish(selection: Selection, self: MosaicClient, column: string, ids: readonly number[] | null): void;
|
|
23
|
-
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/core/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAgB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAiEhF,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAyC/C;AAID,8CAA8C;AAC9C,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAMlD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAItF;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,YAAY,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,MAAM,EACd,GAAG,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAC5B,IAAI,CAON"}
|
package/dist/core/filter.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { MosaicClient as f, clausePoints as m } from "@kanzo-tech/mosaic";
|
|
2
|
-
import { GraphError as h } from "./error.js";
|
|
3
|
-
const O = {
|
|
4
|
-
"=": "=",
|
|
5
|
-
"==": "=",
|
|
6
|
-
"IS NOT DISTINCT FROM": "=",
|
|
7
|
-
"<>": "!=",
|
|
8
|
-
"!=": "!=",
|
|
9
|
-
"<": "<",
|
|
10
|
-
"<=": "<=",
|
|
11
|
-
">": ">",
|
|
12
|
-
">=": ">="
|
|
13
|
-
}, y = { "=": "=", "!=": "!=", "<": ">", "<=": ">=", ">": "<", ">=": "<=" }, o = (r) => {
|
|
14
|
-
throw new h(
|
|
15
|
-
"graph/untranslatable-filter",
|
|
16
|
-
`the graph cannot express this crossfilter clause as a filter on the corpus: ${String(r)}`
|
|
17
|
-
);
|
|
18
|
-
};
|
|
19
|
-
function a(r) {
|
|
20
|
-
const t = r;
|
|
21
|
-
return (t == null ? void 0 : t.type) === "COLUMN_REF" && typeof t.name == "string" ? t.name : null;
|
|
22
|
-
}
|
|
23
|
-
function s(r) {
|
|
24
|
-
const t = r, n = (t == null ? void 0 : t.type) === "LITERAL" || (t == null ? void 0 : t.type) === "PARAM" ? t.value : o(r);
|
|
25
|
-
if (typeof n == "number" || typeof n == "bigint" || typeof n == "string" || typeof n == "boolean")
|
|
26
|
-
return n;
|
|
27
|
-
if (n instanceof Date) {
|
|
28
|
-
const e = n.toISOString();
|
|
29
|
-
return e.endsWith("T00:00:00.000Z") ? e.slice(0, 10) : e.replace("T", " ").replace("Z", "");
|
|
30
|
-
}
|
|
31
|
-
return o(r);
|
|
32
|
-
}
|
|
33
|
-
function A(r) {
|
|
34
|
-
const t = r;
|
|
35
|
-
return (Array.isArray(r) ? r : Array.isArray(t == null ? void 0 : t.values) ? t.values : o(r)).map(s);
|
|
36
|
-
}
|
|
37
|
-
function c(r) {
|
|
38
|
-
const t = r;
|
|
39
|
-
if (Array.isArray(r)) return i(r.map(c));
|
|
40
|
-
switch (t == null ? void 0 : t.type) {
|
|
41
|
-
case "LOGICAL_OPERATOR": {
|
|
42
|
-
const n = (t.clauses ?? []).map(c);
|
|
43
|
-
return t.op === "OR" ? { or: n } : i(n);
|
|
44
|
-
}
|
|
45
|
-
case "UNARY":
|
|
46
|
-
return t.op === "NOT" ? { not: c(t.expr) } : o(r);
|
|
47
|
-
case "UNARY_POSTFIX": {
|
|
48
|
-
const n = a(t.expr) ?? o(r);
|
|
49
|
-
return t.op === "IS NULL" ? { column: n, op: "is null" } : t.op === "IS NOT NULL" ? { column: n, op: "not null" } : o(r);
|
|
50
|
-
}
|
|
51
|
-
case "BINARY": {
|
|
52
|
-
const n = O[String(t.op).toUpperCase()] ?? o(r), e = a(t.left);
|
|
53
|
-
return e !== null ? { column: e, op: n, value: s(t.right) } : { column: a(t.right) ?? o(r), op: y[n], value: s(t.left) };
|
|
54
|
-
}
|
|
55
|
-
case "BETWEEN":
|
|
56
|
-
case "NOT_BETWEEN": {
|
|
57
|
-
const n = a(t.expr) ?? o(r), [e, u] = t.extent ?? o(r), p = i([
|
|
58
|
-
{ column: n, op: ">=", value: s(e) },
|
|
59
|
-
{ column: n, op: "<=", value: s(u) }
|
|
60
|
-
]);
|
|
61
|
-
return t.type === "BETWEEN" ? p : { not: p };
|
|
62
|
-
}
|
|
63
|
-
case "IN":
|
|
64
|
-
return { column: a(t.expr) ?? o(r), op: "in", values: A(t.values) };
|
|
65
|
-
default:
|
|
66
|
-
return o(r);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
const i = (r) => r.length === 1 ? r[0] : { and: r };
|
|
70
|
-
function l(r) {
|
|
71
|
-
return "column" in r ? [r.column] : "and" in r ? [...new Set(r.and.flatMap(l))] : "or" in r ? [...new Set(r.or.flatMap(l))] : "not" in r ? l(r.not) : [];
|
|
72
|
-
}
|
|
73
|
-
function v(r, t) {
|
|
74
|
-
const n = r.predicate(t), e = (Array.isArray(n) ? n : [n]).filter((u) => u != null);
|
|
75
|
-
return e.length === 0 ? void 0 : c(e);
|
|
76
|
-
}
|
|
77
|
-
function E() {
|
|
78
|
-
return new f();
|
|
79
|
-
}
|
|
80
|
-
function R(r, t, n, e) {
|
|
81
|
-
r.update(
|
|
82
|
-
m([n], e && e.length > 0 ? e.map((u) => [u]) : void 0, {
|
|
83
|
-
source: t,
|
|
84
|
-
clients: /* @__PURE__ */ new Set([t])
|
|
85
|
-
})
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
export {
|
|
89
|
-
l as columnsOf,
|
|
90
|
-
v as filterFor,
|
|
91
|
-
E as graphClient,
|
|
92
|
-
R as publish,
|
|
93
|
-
c as translate
|
|
94
|
-
};
|
|
95
|
-
//# sourceMappingURL=filter.js.map
|
package/dist/core/filter.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filter.js","sources":["../../src/core/filter.ts"],"sourcesContent":["import type { Filter, Literal } from \"@fossil-lang/corpus\";\nimport { MosaicClient, clausePoints, type Selection } from \"@kanzo-tech/mosaic\";\nimport { GraphError } from \"./error\";\n\n/**\n * **The page's crossfilter, as scan's typed filter.** The graph listens to the `Selection` rather\n * than being a client of the coordinator: a client hands the coordinator SQL to run, and the graph\n * has none — it hands fossil a `Filter` and fossil binds it. So this takes the half of Mosaic's\n * protocol that is about filtering: the `value` event, and `selection.predicate(client)`.\n *\n * The nodes are read by their `type`, never by importing mosaic-sql's classes: what arrives is\n * whatever the page's copy of mosaic-sql built.\n */\n\ninterface Node {\n readonly type?: string;\n readonly op?: string;\n readonly [field: string]: unknown;\n}\n\nconst COMPARISONS: Record<string, \"=\" | \"!=\" | \"<\" | \"<=\" | \">\" | \">=\"> = {\n \"=\": \"=\",\n \"==\": \"=\",\n \"IS NOT DISTINCT FROM\": \"=\",\n \"<>\": \"!=\",\n \"!=\": \"!=\",\n \"<\": \"<\",\n \"<=\": \"<=\",\n \">\": \">\",\n \">=\": \">=\",\n};\nconst MIRRORED = { \"=\": \"=\", \"!=\": \"!=\", \"<\": \">\", \"<=\": \">=\", \">\": \"<\", \">=\": \"<=\" } as const;\n\n/** A predicate this cannot express as a `Filter` — reported, never dropped. */\nconst fail = (what: unknown): never => {\n throw new GraphError(\n \"graph/untranslatable-filter\",\n `the graph cannot express this crossfilter clause as a filter on the corpus: ${String(what)}`,\n );\n};\n\nfunction columnOf(node: unknown): string | null {\n const n = node as Node | null;\n if (n?.type === \"COLUMN_REF\" && typeof n.name === \"string\") return n.name;\n return null;\n}\n\nfunction literalOf(node: unknown): Literal {\n const n = node as Node | null;\n const value = n?.type === \"LITERAL\" || n?.type === \"PARAM\" ? n.value : fail(node);\n if (typeof value === \"number\" || typeof value === \"bigint\" || typeof value === \"string\" || typeof value === \"boolean\") {\n return value;\n }\n if (value instanceof Date) {\n const iso = value.toISOString();\n return iso.endsWith(\"T00:00:00.000Z\") ? iso.slice(0, 10) : iso.replace(\"T\", \" \").replace(\"Z\", \"\");\n }\n return fail(node);\n}\n\nfunction valuesOf(node: unknown): Literal[] {\n const n = node as Node | null;\n const list = Array.isArray(node) ? node : Array.isArray(n?.values) ? n.values : fail(node);\n return (list as unknown[]).map(literalOf);\n}\n\n/** One mosaic-sql expression node → one `Filter`. */\nexport function translate(node: unknown): Filter {\n const n = node as Node | null;\n if (Array.isArray(node)) return and(node.map(translate));\n switch (n?.type) {\n case \"LOGICAL_OPERATOR\": {\n const clauses = ((n.clauses as unknown[] | undefined) ?? []).map(translate);\n return n.op === \"OR\" ? { or: clauses } : and(clauses);\n }\n case \"UNARY\":\n if (n.op === \"NOT\") return { not: translate(n.expr) };\n return fail(node);\n case \"UNARY_POSTFIX\": {\n const column = columnOf(n.expr) ?? fail(node);\n if (n.op === \"IS NULL\") return { column, op: \"is null\" };\n if (n.op === \"IS NOT NULL\") return { column, op: \"not null\" };\n return fail(node);\n }\n case \"BINARY\": {\n const op = COMPARISONS[String(n.op).toUpperCase()] ?? fail(node);\n const left = columnOf(n.left);\n if (left !== null) return { column: left, op, value: literalOf(n.right) };\n const right = columnOf(n.right) ?? fail(node);\n return { column: right, op: MIRRORED[op], value: literalOf(n.left) };\n }\n case \"BETWEEN\":\n case \"NOT_BETWEEN\": {\n const column = columnOf(n.expr) ?? fail(node);\n const [lo, hi] = (n.extent as unknown[] | undefined) ?? fail(node);\n const within: Filter = and([\n { column, op: \">=\", value: literalOf(lo) },\n { column, op: \"<=\", value: literalOf(hi) },\n ]);\n return n.type === \"BETWEEN\" ? within : { not: within };\n }\n case \"IN\": {\n const column = columnOf(n.expr) ?? fail(node);\n return { column, op: \"in\", values: valuesOf(n.values) };\n }\n default:\n return fail(node);\n }\n}\n\nconst and = (clauses: Filter[]): Filter => (clauses.length === 1 ? (clauses[0] as Filter) : { and: clauses });\n\n/** Every column a filter names, once each. */\nexport function columnsOf(filter: Filter): string[] {\n if (\"column\" in filter) return [filter.column];\n if (\"and\" in filter) return [...new Set(filter.and.flatMap(columnsOf))];\n if (\"or\" in filter) return [...new Set(filter.or.flatMap(columnsOf))];\n if (\"not\" in filter) return columnsOf(filter.not);\n return [];\n}\n\n/**\n * The page's filter for the graph, or `undefined` for none. `selection.predicate` skips the clause\n * the graph published itself, which is the exemption the next function takes back.\n */\nexport function filterFor(selection: Selection, self: MosaicClient): Filter | undefined {\n const predicate = selection.predicate(self) as unknown;\n const clauses = (Array.isArray(predicate) ? predicate : [predicate]).filter((p) => p !== undefined && p !== null);\n return clauses.length === 0 ? undefined : translate(clauses);\n}\n\n/**\n * An identity for `clients`, and nothing more: it is never connected, so the coordinator never\n * queries on its behalf.\n */\nexport function graphClient(): MosaicClient {\n return new MosaicClient();\n}\n\n/**\n * **The reader's pick, published** — naming the graph in `clients`, so the crossfilter skips it for\n * the graph and applies it to every chart. A canvas that draws only what survives would otherwise\n * answer a lasso of thirteen by removing the other 1,530.\n */\nexport function publish(\n selection: Selection,\n self: MosaicClient,\n column: string,\n ids: readonly number[] | null,\n): void {\n selection.update(\n clausePoints([column], ids && ids.length > 0 ? ids.map((d) => [d]) : undefined, {\n source: self,\n clients: new Set([self]),\n }),\n );\n}\n"],"names":["COMPARISONS","MIRRORED","fail","what","GraphError","columnOf","node","n","literalOf","value","iso","valuesOf","translate","and","clauses","column","op","left","lo","hi","within","columnsOf","filter","filterFor","selection","self","predicate","p","graphClient","MosaicClient","publish","ids","clausePoints","d"],"mappings":"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"}
|