@kanzo-tech/graph 0.14.0 → 0.15.1

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.
Files changed (113) hide show
  1. package/README.md +20 -16
  2. package/dist/core/categories.d.ts +18 -6
  3. package/dist/core/categories.d.ts.map +1 -1
  4. package/dist/core/categories.js +41 -10
  5. package/dist/core/categories.js.map +1 -1
  6. package/dist/core/channels.d.ts +10 -5
  7. package/dist/core/channels.d.ts.map +1 -1
  8. package/dist/core/channels.js +11 -13
  9. package/dist/core/channels.js.map +1 -1
  10. package/dist/core/detail.d.ts +14 -8
  11. package/dist/core/detail.d.ts.map +1 -1
  12. package/dist/core/detail.js +33 -15
  13. package/dist/core/detail.js.map +1 -1
  14. package/dist/core/filter.d.ts +3 -1
  15. package/dist/core/filter.d.ts.map +1 -1
  16. package/dist/core/filter.js +54 -50
  17. package/dist/core/filter.js.map +1 -1
  18. package/dist/core/load.d.ts +58 -0
  19. package/dist/core/load.d.ts.map +1 -0
  20. package/dist/core/load.js +115 -0
  21. package/dist/core/load.js.map +1 -0
  22. package/dist/core/state.d.ts +27 -55
  23. package/dist/core/state.d.ts.map +1 -1
  24. package/dist/core/store.d.ts +1 -3
  25. package/dist/core/store.d.ts.map +1 -1
  26. package/dist/core/store.js +159 -174
  27. package/dist/core/store.js.map +1 -1
  28. package/dist/core/types.d.ts +21 -17
  29. package/dist/core/types.d.ts.map +1 -1
  30. package/dist/index.d.ts +5 -7
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +19 -25
  33. package/dist/index.js.map +1 -1
  34. package/dist/parts/gesture.d.ts +1 -10
  35. package/dist/parts/gesture.d.ts.map +1 -1
  36. package/dist/parts/gesture.js +28 -28
  37. package/dist/parts/gesture.js.map +1 -1
  38. package/dist/parts/graph-canvas.d.ts.map +1 -1
  39. package/dist/parts/graph-canvas.js +119 -108
  40. package/dist/parts/graph-canvas.js.map +1 -1
  41. package/dist/parts/graph-inspector.d.ts +4 -4
  42. package/dist/parts/graph-inspector.d.ts.map +1 -1
  43. package/dist/parts/graph-inspector.js +55 -57
  44. package/dist/parts/graph-inspector.js.map +1 -1
  45. package/dist/parts/graph-legend.d.ts +4 -4
  46. package/dist/parts/graph-legend.d.ts.map +1 -1
  47. package/dist/parts/graph-legend.js +21 -21
  48. package/dist/parts/graph-legend.js.map +1 -1
  49. package/dist/parts/overlays.d.ts +2 -4
  50. package/dist/parts/overlays.d.ts.map +1 -1
  51. package/dist/parts/overlays.js +45 -45
  52. package/dist/parts/overlays.js.map +1 -1
  53. package/dist/react/use-graph-state.d.ts +4 -2
  54. package/dist/react/use-graph-state.d.ts.map +1 -1
  55. package/dist/react/use-graph-state.js +10 -6
  56. package/dist/react/use-graph-state.js.map +1 -1
  57. package/dist/react/use-graph.d.ts +1 -4
  58. package/dist/react/use-graph.d.ts.map +1 -1
  59. package/dist/react/use-graph.js +38 -49
  60. package/dist/react/use-graph.js.map +1 -1
  61. package/dist/render/graph-looks.d.ts.map +1 -1
  62. package/dist/render/graph-looks.js.map +1 -1
  63. package/dist/render/graph-model.d.ts +6 -8
  64. package/dist/render/graph-model.d.ts.map +1 -1
  65. package/dist/render/graph-model.js +51 -57
  66. package/dist/render/graph-model.js.map +1 -1
  67. package/dist/render/graph-sim.d.ts +2 -3
  68. package/dist/render/graph-sim.d.ts.map +1 -1
  69. package/dist/render/graph-sim.js.map +1 -1
  70. package/dist/render/renderer.d.ts +6 -11
  71. package/dist/render/renderer.d.ts.map +1 -1
  72. package/dist/render/renderer.js +120 -173
  73. package/dist/render/renderer.js.map +1 -1
  74. package/dist/section.d.ts.map +1 -1
  75. package/dist/section.js +3 -7
  76. package/dist/section.js.map +1 -1
  77. package/package.json +11 -11
  78. package/dist/core/refine.d.ts +0 -14
  79. package/dist/core/refine.d.ts.map +0 -1
  80. package/dist/core/refine.js +0 -20
  81. package/dist/core/refine.js.map +0 -1
  82. package/dist/core/resident.d.ts +0 -79
  83. package/dist/core/resident.d.ts.map +0 -1
  84. package/dist/core/resident.js +0 -44
  85. package/dist/core/resident.js.map +0 -1
  86. package/dist/core/scheduler.d.ts +0 -42
  87. package/dist/core/scheduler.d.ts.map +0 -1
  88. package/dist/core/scheduler.js +0 -77
  89. package/dist/core/scheduler.js.map +0 -1
  90. package/dist/core/tile-matrix.d.ts +0 -37
  91. package/dist/core/tile-matrix.d.ts.map +0 -1
  92. package/dist/core/tile-matrix.js +0 -49
  93. package/dist/core/tile-matrix.js.map +0 -1
  94. package/dist/core/tile.d.ts +0 -54
  95. package/dist/core/tile.d.ts.map +0 -1
  96. package/dist/core/tile.js +0 -76
  97. package/dist/core/tile.js.map +0 -1
  98. package/dist/core/tileset.d.ts +0 -59
  99. package/dist/core/tileset.d.ts.map +0 -1
  100. package/dist/core/tileset.js +0 -177
  101. package/dist/core/tileset.js.map +0 -1
  102. package/dist/render/adaptive.d.ts +0 -27
  103. package/dist/render/adaptive.d.ts.map +0 -1
  104. package/dist/render/adaptive.js +0 -25
  105. package/dist/render/adaptive.js.map +0 -1
  106. package/dist/render/compose.d.ts +0 -51
  107. package/dist/render/compose.d.ts.map +0 -1
  108. package/dist/render/compose.js +0 -107
  109. package/dist/render/compose.js.map +0 -1
  110. package/dist/render/encode.d.ts +0 -42
  111. package/dist/render/encode.d.ts.map +0 -1
  112. package/dist/render/encode.js +0 -68
  113. package/dist/render/encode.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 type { Box } from \"@fossil-lang/corpus\";\nimport type { Resident, VertexId } from \"../core/resident\";\nimport { denseOf } from \"../core/resident\";\nimport type { GraphSnapshot, GraphStore } from \"../core/store\";\nimport { tileOfDense, type Viewport } from \"../core/tile-matrix\";\nimport type { GraphCommands } from \"../core/types\";\nimport { createComposer, type Composition } from \"./compose\";\nimport { resolveLook, type Look } from \"./graph-looks\";\nimport { appearance, forces, paint } from \"./graph-model\";\nimport { resolveSim, type Sim } from \"./graph-sim\";\nimport { hasWebGL, releaseContext } from \"./webgl\";\n\nexport interface RendererEvents {\n /** After every frame and every camera move — where the overlays repaint. */\n onFrame?: () => void;\n /** A new composition was uploaded. */\n onComposed?: (composition: Composition) => 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 resident(): Resident;\n composition(): Composition | null;\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 FIT_DURATION = 420;\nconst FIT_PADDING = 0.18;\nconst REHEAT = 0.35;\n/** Twentieths: a settle costs twenty reports rather than one per frame. */\nconst PROGRESS_STEPS = 20;\n\nconst corners = (box: Box) => [box.x, box.y, box.x + box.w, box.y + box.h];\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 change of visible tiles recomposes, and dirties positions, links and the per-point arrays;\n * - a look or a theme change dirties 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 * - a snapshot that changed none of those schedules nothing.\n *\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 * a drag needs none, since cosmos.gl moves the dragged point itself. Every callback reads the store's latest options, so a host's inline `onFailure` never rebuilds it.\n */\nexport function createRenderer(host: HTMLDivElement, store: GraphStore, events: RendererEvents = {}): Renderer | null {\n const fail = (message: string) => store.getOptions().onFailure(message);\n if (!hasWebGL()) {\n fail(\"This canvas renders on the GPU, and this browser offers no WebGL context.\");\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 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 const compose = createComposer();\n let composition: Composition | null = null;\n let look: Look = resolveLook(store.getOptions().look);\n let lookPatch = store.getOptions().look;\n const dirty = { compose: true, paint: true, state: true, pinned: true };\n let frame = 0;\n let destroyed = false;\n let framed: GraphSnapshot[\"matrix\"] = null;\n let pendingReveal: VertexId | null = null;\n let last = store.getSnapshot();\n let lastOptions = store.getOptions();\n\n const resident = () => composition?.resident ?? EMPTY;\n\n const viewport = (): { view: Viewport; perPixel: number } | null => {\n const { height, width } = host.getBoundingClientRect();\n if (!graph.isReady || width === 0 || height === 0) return null;\n const [ax, ay] = graph.screenToSpacePosition([0, 0]);\n const [bx, by] = graph.screenToSpacePosition([width, height]);\n const view = { xMin: Math.min(ax, bx), yMin: Math.min(ay, by), xMax: Math.max(ax, bx), yMax: Math.max(ay, by) };\n return { view, perPixel: (view.xMax - view.xMin) / width };\n };\n const observe = () => {\n const camera = viewport();\n if (camera) store.setViewport(camera.view);\n };\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 matrix arrives.\n // `rescalePositions: false` because the corpus's coordinates are the camera's — a rescale\n // between them means the cull and the viewport describe different places.\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 events.onFrame?.();\n },\n onSimulationPause: () => store.report(\"paused\"),\n onSimulationUnpause: () => store.report(\"running\"),\n onSimulationTick: (_alpha, index, position) => {\n progress(graph.progress);\n if (index !== undefined && position) events.onHover?.(position);\n events.onFrame?.();\n },\n onZoom: () => {\n observe();\n events.onFrame?.();\n },\n onPointMouseOver: (index, position) => {\n hovering = index;\n events.onHover?.(position);\n store.hover(resident().at(index) ?? null);\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 onDragEnd: () => {\n const vertex = dragging === null ? undefined : resident().at(dragging);\n dragging = null;\n if (vertex !== undefined) store.pin([...store.getSnapshot().pinned, vertex]);\n },\n onPointClick: (index) => {\n const vertex = resident().at(index);\n if (vertex !== undefined) focusOn(vertex, index);\n },\n onBackgroundClick: () => clear(),\n });\n } catch (error) {\n fail(`The renderer failed to start. (${String(error)})`);\n return null;\n }\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 options = store.getOptions();\n let changed = false;\n if (dirty.compose && snapshot.matrix) {\n dirty.compose = false;\n const next = compose({\n matrix: snapshot.matrix,\n typeIndex: snapshot.typeIndex,\n binding: snapshot.binding,\n modeColumn: snapshot.modeColumn,\n domain: snapshot.domain,\n visible: snapshot.visible,\n cached: snapshot.cached,\n perPixel: viewport()?.perPixel ?? 0,\n });\n if (next) {\n composition = next;\n graph.setPointPositions(next.positions, true);\n graph.setLinks(next.links);\n dirty.paint = true;\n dirty.state = true;\n dirty.pinned = true;\n changed = true;\n events.onComposed?.(next);\n if (pendingReveal !== null && next.resident.indexOf(pendingReveal) !== undefined) {\n const vertex = pendingReveal;\n pendingReveal = null;\n queueMicrotask(() => reveal(vertex));\n }\n }\n const drawn = next && { marks: next.marks, represented: next.represented, domain: next.domain, tally: next.tally };\n store.reportDrawn(snapshot.visible, drawn);\n }\n if (dirty.paint && composition) {\n dirty.paint = false;\n const buffers = paint(composition, 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.setLinkWidths(buffers.linkWidths);\n graph.setConfigPartial(appearance(look, host));\n changed = true;\n }\n if (dirty.state && composition) {\n dirty.state = false;\n const drawn = composition.resident;\n graph.setConfigPartial({\n highlightedPointIndices: snapshot.selection ? drawn.indicesOf(snapshot.selection.vertices) : undefined,\n focusedPointIndex: snapshot.focus === null ? undefined : drawn.indexOf(snapshot.focus),\n });\n }\n if (dirty.pinned && composition) {\n dirty.pinned = false;\n const pinned = composition.resident.indicesOf(snapshot.pinned);\n graph.setPinnedPoints(pinned.length > 0 ? pinned : null);\n }\n if (changed) graph.render();\n events.onFrame?.();\n }\n\n const frameExtent = (snapshot: GraphSnapshot) => {\n const extent = snapshot.matrix?.extent;\n if (!extent || snapshot.matrix === framed) return;\n framed = snapshot.matrix;\n graph.setConfigPartial({ spaceSize: Math.max(extent.w, extent.h) });\n graph.fitViewByPointPositions(corners(extent), 0, FIT_PADDING);\n void graph.ready.then(() => {\n if (!destroyed) observe();\n });\n };\n\n const unsubscribe = store.subscribe(() => {\n const snapshot = store.getSnapshot();\n const options = store.getOptions();\n frameExtent(snapshot);\n if (snapshot.visible !== last.visible || snapshot.binding !== last.binding || snapshot.domain !== last.domain) {\n dirty.compose = true;\n }\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 if (options.simulate) run(REHEAT);\n else graph.pause();\n }\n last = snapshot;\n lastOptions = options;\n if (dirty.compose || dirty.paint || dirty.state || dirty.pinned) schedule();\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 graph.start(alpha);\n }\n\n function focusOn(vertex: VertexId, index: number): void {\n const drawn = resident();\n const around = drawn.verticesAt(graph.getNeighboringPointIndices(index));\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 /** Centre and select one vertex; one that is not drawn is framed by its tile first, then revealed. */\n function reveal(vertex: VertexId): void {\n const index = resident().indexOf(vertex);\n if (index !== undefined) {\n focusOn(vertex, index);\n graph.zoomToPointByIndex(index, 500, 5, true);\n return;\n }\n const matrix = store.getSnapshot().matrix;\n const address = matrix ? tileOfDense(matrix, denseOf(vertex)) : null;\n const box = address && matrix?.tileMatrices[address.z]?.tiles[address.tile]?.bbox;\n if (!box) return;\n pendingReveal = vertex;\n graph.fitViewByPointPositions(corners(box), FIT_DURATION, FIT_PADDING);\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(\"The graph's WebGL context was lost. A browser keeps a limited number of them and drops the oldest; reload the page to get one back.\");\n };\n void graph.ready.then(() => {\n if (!destroyed) host.querySelector(\"canvas\")?.addEventListener(\"webglcontextlost\", onLost);\n });\n store.report(live && graph.isSimulationRunning ? \"running\" : \"settled\");\n frameExtent(last);\n schedule();\n\n return {\n graph,\n resident,\n composition: () => composition,\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() {\n const extent = store.getSnapshot().matrix?.extent;\n if (extent) graph.fitViewByPointPositions(corners(extent), FIT_DURATION, FIT_PADDING);\n else graph.fitView(FIT_DURATION, FIT_PADDING);\n },\n pause: () => graph.pause(),\n resume() {\n const settled = store.getSnapshot().motion === \"settled\";\n if (settled || !live) run(REHEAT);\n else graph.unpause();\n },\n restart() {\n store.pin([]);\n run(1);\n },\n unpin() {\n if (store.getSnapshot().pinned.length === 0) return;\n store.pin([]);\n if (store.getSnapshot().motion === \"running\") graph.start(REHEAT);\n },\n reveal,\n frameBox(box, { duration = FIT_DURATION, padding = FIT_PADDING } = {}) {\n graph.fitViewByPointPositions(corners(box), duration, padding);\n },\n frameSelection() {\n const indices = resident().indicesOf(store.getSnapshot().selection?.vertices ?? []);\n if (indices.length > 0) graph.fitViewByPointIndices(indices, FIT_DURATION, 0.25);\n },\n clear,\n destroy() {\n unsubscribe();\n if (frame) cancelAnimationFrame(frame);\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\nconst EMPTY: Resident = { size: 0, indexOf: () => undefined, at: () => undefined, indicesOf: () => [], verticesAt: () => [] };\n"],"names":["FIT_DURATION","FIT_PADDING","REHEAT","PROGRESS_STEPS","corners","box","createRenderer","host","store","events","fail","message","hasWebGL","sim","resolveSim","live","hovering","dragging","reported","progress","value","bucket","compose","createComposer","composition","look","resolveLook","lookPatch","dirty","frame","destroyed","framed","pendingReveal","last","lastOptions","resident","EMPTY","viewport","height","width","graph","ax","ay","bx","by","view","observe","camera","Graph","forces","_a","_alpha","index","position","_b","event","vertex","focusOn","clear","error","schedule","draw","snapshot","options","changed","next","reveal","drawn","buffers","paint","appearance","pinned","_c","frameExtent","extent","unsubscribe","applyForces","run","patch","moved","key","alpha","around","matrix","address","tileOfDense","denseOf","onLost","shape","found","factor","duration","padding","indices","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 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 { hasWebGL, releaseContext } 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 FIT_DURATION = 420;\nconst FIT_PADDING = 0.18;\nconst REHEAT = 0.35;\n/** Twentieths: a settle costs twenty reports rather than one per frame. */\nconst PROGRESS_STEPS = 20;\n\ntype Extent = NonNullable<Geometry[\"extent\"]>;\nconst corners = (box: Extent) => [box.x, box.y, box.x + box.w, box.y + box.h];\n\n/** The loaded positions, with `NaN` where the page's filter hides a vertex — cosmos.gl draws no such point. */\nfunction shown(geometry: Geometry, mask: Uint8Array | null): Float32Array {\n if (!mask) return geometry.positions;\n const positions = geometry.positions.slice();\n for (let id = 0; id < geometry.size; id++) {\n if (!mask[id]) positions[id * 2] = positions[id * 2 + 1] = Number.NaN;\n }\n return positions;\n}\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 */\nexport function createRenderer(host: HTMLDivElement, store: GraphStore, events: RendererEvents = {}): Renderer | null {\n const fail = (message: string) => store.getOptions().onFailure(message);\n if (!hasWebGL()) {\n fail(\"This canvas renders on the GPU, and this browser offers no WebGL context.\");\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 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 destroyed = false;\n let framed: Geometry | 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 corpus's coordinates are the camera's.\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 events.onFrame?.();\n },\n onSimulationPause: () => store.report(\"paused\"),\n onSimulationUnpause: () => store.report(\"running\"),\n onSimulationTick: (_alpha, index, position) => {\n progress(graph.progress);\n if (index !== undefined && position) events.onHover?.(position);\n events.onFrame?.();\n },\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 onDragEnd: () => {\n const vertex = dragging;\n dragging = null;\n if (vertex !== null) store.pin([...store.getSnapshot().pinned, vertex]);\n },\n onPointClick: (index) => focusOn(index),\n onBackgroundClick: () => clear(),\n });\n } catch (error) {\n fail(`The renderer failed to start. (${String(error)})`);\n return null;\n }\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 frameExtent(geometry);\n graph.setPointPositions(shown(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): void {\n if (geometry === framed || !geometry.extent) return;\n framed = geometry;\n graph.setConfigPartial({ spaceSize: Math.max(geometry.extent.w, geometry.extent.h) });\n graph.fitViewByPointPositions(corners(geometry.extent), 0, FIT_PADDING);\n }\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 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 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 graph.start(alpha);\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(\"The graph's WebGL context was lost. A browser keeps a limited number of them and drops the oldest; reload the page to get one back.\");\n };\n void graph.ready.then(() => {\n if (!destroyed) host.querySelector(\"canvas\")?.addEventListener(\"webglcontextlost\", onLost);\n });\n store.report(live && graph.isSimulationRunning ? \"running\" : \"settled\");\n schedule();\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() {\n const extent = store.getSnapshot().geometry?.extent;\n if (extent) graph.fitViewByPointPositions(corners(extent), FIT_DURATION, FIT_PADDING);\n else graph.fitView(FIT_DURATION, FIT_PADDING);\n },\n pause: () => graph.pause(),\n resume() {\n const settled = store.getSnapshot().motion === \"settled\";\n if (settled || !live) run(REHEAT);\n else graph.unpause();\n },\n restart() {\n store.pin([]);\n run(1);\n },\n unpin() {\n if (store.getSnapshot().pinned.length === 0) return;\n store.pin([]);\n if (store.getSnapshot().motion === \"running\") graph.start(REHEAT);\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 if (frame) cancelAnimationFrame(frame);\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":["FIT_DURATION","FIT_PADDING","REHEAT","PROGRESS_STEPS","corners","box","shown","geometry","mask","positions","id","createRenderer","host","store","events","fail","message","hasWebGL","sim","resolveSim","live","hovering","dragging","reported","progress","value","bucket","look","resolveLook","lookPatch","dirty","frame","destroyed","framed","links","last","lastOptions","size","_a","graph","Graph","forces","_alpha","index","position","_b","event","vertex","focusOn","clear","error","schedule","draw","snapshot","encoding","options","changed","frameExtent","buffers","paint","appearance","unsubscribe","applyForces","run","patch","next","moved","key","alpha","around","onLost","shape","found","factor","extent","vertices","canvas","releaseContext"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../src/section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,KAAK,WAAW,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACpE,KAAK,gBAAgB,GACjB,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,GACxF,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,GAClC,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9E,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpE,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,aAAa,EAAE,eA0I3B,CAAC"}
1
+ {"version":3,"file":"section.d.ts","sourceRoot":"","sources":["../src/section.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,KAAK,WAAW,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACpE,KAAK,gBAAgB,GACjB,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,SAAS;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,CAAC,GACxF,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,CAAC,GAClC,CAAC,WAAW,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9E,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;IACpE,KAAK,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,eAAO,MAAM,aAAa,EAAE,eAsI3B,CAAC"}
package/dist/section.js CHANGED
@@ -53,7 +53,7 @@ const e = {
53
53
  kind: "toggle",
54
54
  label: "Show links",
55
55
  default: "true",
56
- doc: "Draw the edge layer at all. Past a few hundred thousand links it is fog that costs a draw call a frame, and `adaptive` says where that is."
56
+ doc: "Draw the edge layer at all. Past a few hundred thousand links it is fog that costs a draw call a frame."
57
57
  },
58
58
  grid: {
59
59
  kind: "toggle",
@@ -72,12 +72,8 @@ const e = {
72
72
  *
73
73
  * The bounds are cosmos.gl's useful range rather than its legal one, and a stored value outside
74
74
  * them is declined: a slider that used to run to 5 and now stops at 3 must not paint 5 because
75
- * storage remembers it.
76
- *
77
- * **`adaptive(nodes)` still exists and still knows better.** What a corpus of this size wants is
78
- * computed, not chosen, and these defaults are tuned for a few hundred nodes. A host with a
79
- * large corpus should start its users at `adaptive`'s answer through the tenant policy — which
80
- * is the mechanism's own way of saying "start somewhere else" — rather than by writing values
75
+ * storage remembers it. These defaults are tuned for a few hundred nodes; a host with a large
76
+ * corpus starts its users elsewhere through the tenant policy, rather than by writing values
81
77
  * into storage nobody can then reset.
82
78
  */
83
79
  gravity: {
@@ -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, and `adaptive` says where that is.\",\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.\n *\n * **`adaptive(nodes)` still exists and still knows better.** What a corpus of this size wants is\n * computed, not chosen, and these defaults are tuned for a few hundred nodes. A host with a\n * large corpus should start its users at `adaptive`'s answer through the tenant policy — which\n * is the mechanism's own way of saying \"start somewhere else\" — 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;AAAA;AAAA;AAAA;AAAA,IAsBP,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 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;"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kanzo-tech/graph",
3
- "version": "0.14.0",
4
- "description": "Kanzo graph view — a tileset over a fossil corpus's scan, drawn with cosmos.gl, inside the page's Mosaic crossfilter. Sibling of @kanzo-tech/ui, not part of it: the admission rules exclude graphs from the generic vocabulary by name.",
3
+ "version": "0.15.1",
4
+ "description": "Kanzo graph view — a whole fossil corpus, read once through its scan and drawn with cosmos.gl, inside the page's Mosaic crossfilter. 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,19 +22,19 @@
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; `@fossil-lang/corpus` is the backend — the host opens a corpus with its `open` on `@kanzo-tech/mosaic`'s `engine()` and this package draws it through `tileMatrix`, `scan` and `edges`, writing no SQL of its own; `@kanzo-tech/mosaic` carries the crossfilter the graph listens to and publishes into. They were optional while a root barrel with no source and a `./duckdb` entry with one existed side by side; there is one path now and nothing on it is optional (`/docs/design/graph`, *the one host path*). The Mosaic stack itself — mosaic-core, mosaic-sql — is `@kanzo-tech/mosaic`'s peer, declared once there.",
26
- "//fossil": "The floor is `0.3.0-alpha.14`, the release whose `scan(…).read` and `edges` take a list of addresses and answer one batch per tile, and an `Engine.query` that answers in columns and interrupts on abort, over corpora whose `dense_id` is the Hilbert rank. Only types and the writer's role table (`PAYLOAD_*`) are imported; `src/layers.test.ts` holds that.",
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; `@fossil-lang/corpus` is the backend — the host opens a corpus with its `open` on `@kanzo-tech/mosaic`'s `engine()` and this package draws it through its `manifest` and `scan`, writing no SQL of its own; `@kanzo-tech/mosaic` carries the crossfilter the graph listens to and publishes into. They were optional while a root barrel with no source and a `./duckdb` entry with one existed side by side; there is one path now and nothing on it is optional (`/docs/design/graph`, *the one host path*). The Mosaic stack itself — mosaic-core, mosaic-sql — is `@kanzo-tech/mosaic`'s peer, declared once there.",
26
+ "//fossil": "The code reads `fossil/1` — `manifest`, `scan({ table })`, a global dense `dense_id` — which `0.3.0-alpha.15` is the first to publish, so it is the floor. Only types are imported; `src/layers.test.ts` holds that.",
27
27
  "peerDependencies": {
28
28
  "@cosmos.gl/graph": "^3.4.0",
29
- "@fossil-lang/corpus": "^0.3.0-alpha.14",
29
+ "@fossil-lang/corpus": "^0.3.0-alpha.15",
30
30
  "lucide-react": ">=1",
31
31
  "react": "^19.0.0",
32
- "@kanzo-tech/mosaic": "0.14.0",
33
- "@kanzo-tech/ui": "0.14.0"
32
+ "@kanzo-tech/ui": "0.15.1",
33
+ "@kanzo-tech/mosaic": "0.15.1"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@cosmos.gl/graph": "^3.4.0",
37
- "@fossil-lang/corpus": "^0.3.0-alpha.14",
37
+ "@fossil-lang/corpus": "^0.3.0-alpha.15",
38
38
  "@testing-library/dom": "^10.4.1",
39
39
  "@testing-library/react": "^16.3.2",
40
40
  "@types/react": "^19.0.0",
@@ -46,14 +46,14 @@
46
46
  "react": "^19.0.0",
47
47
  "react-dom": "^19.0.0",
48
48
  "rollup-plugin-preserve-directives": "^0.4.0",
49
- "@kanzo-tech/mosaic": "0.14.0"
49
+ "@kanzo-tech/mosaic": "0.15.1"
50
50
  },
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`; budget set just above so real growth trips the gate.",
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.",
52
52
  "size-limit": [
53
53
  {
54
54
  "name": "root barrel (JS)",
55
55
  "path": "dist/index.js",
56
- "limit": "19.5 kB",
56
+ "limit": "15.5 kB",
57
57
  "ignore": [
58
58
  "react",
59
59
  "react-dom",
@@ -1,14 +0,0 @@
1
- import { Tile } from './tile';
2
- /**
3
- * deck.gl's `'best-available'` refinement — `updateTileStateDefault`, the only strategy.
4
- *
5
- * A selected tile with content is drawn. One without is covered by its nearest ancestor holding
6
- * content, and failing that by whatever of its descendants holds some, so a pan never shows a hole.
7
- * A parent is therefore drawn only while a selected child is loading: at rest every selected tile
8
- * holds content and no stand-in is needed.
9
- *
10
- * "Holding content" rather than deck.gl's `isLoaded`, because a tile reloading for a new question
11
- * keeps its old picture until the new one arrives.
12
- */
13
- export declare function refine(tiles: Iterable<Tile>): void;
14
- //# sourceMappingURL=refine.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"refine.d.ts","sourceRoot":"","sources":["../../src/core/refine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAOlD"}
@@ -1,20 +0,0 @@
1
- function f(o) {
2
- const n = [...o], e = /* @__PURE__ */ new Set();
3
- for (const t of n)
4
- t.isSelected && !c(t, e) && i(t, e);
5
- for (const t of n) t.isVisible = e.has(t);
6
- }
7
- function c(o, n) {
8
- for (let e = o; e; e = e.parent)
9
- if (e.content)
10
- return n.add(e), !0;
11
- return !1;
12
- }
13
- function i(o, n) {
14
- for (const e of o.children)
15
- e.content ? n.add(e) : i(e, n);
16
- }
17
- export {
18
- f as refine
19
- };
20
- //# sourceMappingURL=refine.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"refine.js","sources":["../../src/core/refine.ts"],"sourcesContent":["import type { Tile } from \"./tile\";\n\n/**\n * deck.gl's `'best-available'` refinement — `updateTileStateDefault`, the only strategy.\n *\n * A selected tile with content is drawn. One without is covered by its nearest ancestor holding\n * content, and failing that by whatever of its descendants holds some, so a pan never shows a hole.\n * A parent is therefore drawn only while a selected child is loading: at rest every selected tile\n * holds content and no stand-in is needed.\n *\n * \"Holding content\" rather than deck.gl's `isLoaded`, because a tile reloading for a new question\n * keeps its old picture until the new one arrives.\n */\nexport function refine(tiles: Iterable<Tile>): void {\n const all = [...tiles];\n const visible = new Set<Tile>();\n for (const tile of all) {\n if (tile.isSelected && !inAncestors(tile, visible)) inDescendants(tile, visible);\n }\n for (const tile of all) tile.isVisible = visible.has(tile);\n}\n\nfunction inAncestors(start: Tile, visible: Set<Tile>): boolean {\n for (let tile: Tile | null = start; tile; tile = tile.parent) {\n if (tile.content) {\n visible.add(tile);\n return true;\n }\n }\n return false;\n}\n\nfunction inDescendants(tile: Tile, visible: Set<Tile>): void {\n for (const child of tile.children) {\n if (child.content) visible.add(child);\n else inDescendants(child, visible);\n }\n}\n"],"names":["refine","tiles","all","visible","tile","inAncestors","inDescendants","start","child"],"mappings":"AAaO,SAASA,EAAOC,GAA6B;AAClD,QAAMC,IAAM,CAAC,GAAGD,CAAK,GACfE,wBAAc,IAAA;AACpB,aAAWC,KAAQF;AACjB,IAAIE,EAAK,cAAc,CAACC,EAAYD,GAAMD,CAAO,KAAGG,EAAcF,GAAMD,CAAO;AAEjF,aAAWC,KAAQF,EAAK,CAAAE,EAAK,YAAYD,EAAQ,IAAIC,CAAI;AAC3D;AAEA,SAASC,EAAYE,GAAaJ,GAA6B;AAC7D,WAASC,IAAoBG,GAAOH,GAAMA,IAAOA,EAAK;AACpD,QAAIA,EAAK;AACP,aAAAD,EAAQ,IAAIC,CAAI,GACT;AAGX,SAAO;AACT;AAEA,SAASE,EAAcF,GAAYD,GAA0B;AAC3D,aAAWK,KAASJ,EAAK;AACvB,IAAII,EAAM,UAASL,EAAQ,IAAIK,CAAK,IAC/BF,EAAcE,GAAOL,CAAO;AAErC;"}
@@ -1,79 +0,0 @@
1
- /**
2
- * Who is drawn, and where the GPU is drawing them.
3
- *
4
- * **A buffer index numbers the answer, not the corpus.** cosmos.gl addresses every point by its
5
- * position in the arrays it was last handed, so index 7 is whatever the current answer put seventh —
6
- * and a resident set that comes and goes reuses every index while the vertices behind them change.
7
- * Anything that outlives one answer — a selection, a label, a hover, a pin — therefore has to be
8
- * held as an identity and re-resolved against whatever is drawn now.
9
- *
10
- * **A vertex is the pair `(type_idx, dense_id)`.** Not `dense_id` alone: it numbers
11
- * within one vertex type, so a union of two types repeats every value and the same number names two
12
- * different vertices. A `LIMIT` breaks the correspondence between an id and a position regardless of
13
- * how many types there are.
14
- */
15
- /**
16
- * A vertex identity — the pair, packed into one 64-bit integer so it can key a `Map` and a `Set`.
17
- *
18
- * **A `bigint`, which is strictly stronger than the brand it also wears.** A buffer index is a
19
- * `number`; an identity is a `bigint`. Confusing the two therefore stops being a branding
20
- * convention that holds while everyone remembers it and becomes a *primitive* type error — and no
21
- * cast quietly launders one: `7 as VertexId` was legal against `number & brand` and is a compile
22
- * error against `bigint & brand`. Getting one wrong now costs `as unknown as`, which is loud.
23
- *
24
- * **The evidence this is worth the friction, because it is not a precaution we invented.** Across
25
- * every multi-language format surveyed — Arrow, Parquet, Iceberg, Delta, MVT, PMTiles, Zarr,
26
- * GraphAr, H3, S2 — the failure that recurs is a 64-bit value crossing into JavaScript.
27
- * `mapbox/node-s2` is a **binding**, not a port: it calls the same C++ the reference implementation
28
- * does, and it still returned wrong cell ids — issue #92, open since 2017, `1152921504606847000`
29
- * where Java and Go both give `1152921504606846977`. JavaScript's `number` is 53 bits and a cell id
30
- * is 64, and a binding cannot protect a language boundary that cannot hold the value. H3 settled it
31
- * by decree before anyone could get it wrong: `h3-js` types `H3Index` as a string. This is the same
32
- * decree with the type JavaScript grew for it.
33
- *
34
- * **And `>>` means three different things across our three layers.** In JavaScript it converts its
35
- * operand to *32 bits* and takes the shift count modulo 32, so the obvious `dense | (type << 32)`
36
- * is not a lost high word — it is `type | dense`, silently. The packing below cannot be written on
37
- * `number` at all and be right.
38
- *
39
- * What goes to the GPU does not change: positions and buffer indices stay `number` and
40
- * `Float32Array`. The conversion happens at the edge, which is where it belongs.
41
- */
42
- export type VertexId = bigint & {
43
- readonly vertex: unique symbol;
44
- };
45
- export declare function vertexId(type: number, dense: number): VertexId;
46
- /** Both halves come back as `number`: each is 32 bits, and a `number` holds those exactly. */
47
- export declare function typeOf(vertex: VertexId): number;
48
- export declare function denseOf(vertex: VertexId): number;
49
- /**
50
- * The identity↔index map for whatever is drawn right now.
51
- *
52
- * Built once per residency change and never mutated, because that is what a residency change *is*: a
53
- * different set of vertices, in a different order. It belongs to whoever owns residency — that is
54
- * the renderer, which composes the buffers — and is read from there by everything else, because a
55
- * second copy is a second copy that can disagree with the buffers on screen.
56
- */
57
- export interface Resident {
58
- /** How many points are drawn. */
59
- readonly size: number;
60
- /** Where a vertex is drawn, or `undefined` when it is not resident. */
61
- indexOf(vertex: VertexId): number | undefined;
62
- /** Which vertex is drawn at a buffer index, or `undefined` past the end of the answer. */
63
- at(index: number): VertexId | undefined;
64
- /** Where these vertices are drawn, skipping every one that is not resident. */
65
- indicesOf(vertices: Iterable<VertexId>): number[];
66
- /** Which vertices are drawn at these buffer indices, skipping any the answer does not hold. */
67
- verticesAt(indices: Iterable<number>): VertexId[];
68
- }
69
- /**
70
- * The map a composition implies, over its first `size` slots. A composition puts its vertices
71
- * first — then the cells, which have no identity, then the far ends drawn only so an edge has one —
72
- * so nothing hovers, selects or frames a slot past them. Before the first composition nobody is
73
- * resident, which is not an error.
74
- *
75
- * Keyed by the identity itself. `Map` and `Set` compare keys by SameValueZero, which for a `bigint`
76
- * is *value* equality — asserted in `resident.test.ts`, because the whole file rests on it.
77
- */
78
- export declare function residentOf(vertices?: BigUint64Array | null, size?: number): Resident;
79
- //# sourceMappingURL=resident.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resident.d.ts","sourceRoot":"","sources":["../../src/core/resident.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AAYnE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE9D;AAED,8FAA8F;AAC9F,wBAAgB,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAE/C;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAEhD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IAC9C,0FAA0F;IAC1F,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,+EAA+E;IAC/E,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC;IAClD,+FAA+F;IAC/F,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;CACnD;AAID;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,QAAQ,GAAE,cAAc,GAAG,IAAa,EAAE,IAAI,SAAwB,GAAG,QAAQ,CA6B3G"}
@@ -1,44 +0,0 @@
1
- const O = 32n, a = 0xffffffffn;
2
- function g(t, e) {
3
- return BigInt(t) << O | BigInt(e);
4
- }
5
- function h(t) {
6
- return Number(t >> O);
7
- }
8
- function l(t) {
9
- return Number(t & a);
10
- }
11
- const x = new BigUint64Array(0);
12
- function p(t = x, e = (t == null ? void 0 : t.length) ?? 0) {
13
- const r = t ?? x, i = Math.min(e, r.length), u = /* @__PURE__ */ new Map();
14
- for (let n = 0; n < i; n++) u.set(r[n], n);
15
- const c = (n) => n >= 0 && n < i ? r[n] : void 0, d = (n) => u.get(n);
16
- return {
17
- size: i,
18
- indexOf: d,
19
- at: c,
20
- indicesOf(n) {
21
- const o = [];
22
- for (const s of n) {
23
- const f = d(s);
24
- f !== void 0 && o.push(f);
25
- }
26
- return o;
27
- },
28
- verticesAt(n) {
29
- const o = [];
30
- for (const s of n) {
31
- const f = c(s);
32
- f !== void 0 && o.push(f);
33
- }
34
- return o;
35
- }
36
- };
37
- }
38
- export {
39
- l as denseOf,
40
- p as residentOf,
41
- h as typeOf,
42
- g as vertexId
43
- };
44
- //# sourceMappingURL=resident.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"resident.js","sources":["../../src/core/resident.ts"],"sourcesContent":["\n/**\n * Who is drawn, and where the GPU is drawing them.\n *\n * **A buffer index numbers the answer, not the corpus.** cosmos.gl addresses every point by its\n * position in the arrays it was last handed, so index 7 is whatever the current answer put seventh —\n * and a resident set that comes and goes reuses every index while the vertices behind them change.\n * Anything that outlives one answer — a selection, a label, a hover, a pin — therefore has to be\n * held as an identity and re-resolved against whatever is drawn now.\n *\n * **A vertex is the pair `(type_idx, dense_id)`.** Not `dense_id` alone: it numbers\n * within one vertex type, so a union of two types repeats every value and the same number names two\n * different vertices. A `LIMIT` breaks the correspondence between an id and a position regardless of\n * how many types there are.\n */\n\n/**\n * A vertex identity — the pair, packed into one 64-bit integer so it can key a `Map` and a `Set`.\n *\n * **A `bigint`, which is strictly stronger than the brand it also wears.** A buffer index is a\n * `number`; an identity is a `bigint`. Confusing the two therefore stops being a branding\n * convention that holds while everyone remembers it and becomes a *primitive* type error — and no\n * cast quietly launders one: `7 as VertexId` was legal against `number & brand` and is a compile\n * error against `bigint & brand`. Getting one wrong now costs `as unknown as`, which is loud.\n *\n * **The evidence this is worth the friction, because it is not a precaution we invented.** Across\n * every multi-language format surveyed — Arrow, Parquet, Iceberg, Delta, MVT, PMTiles, Zarr,\n * GraphAr, H3, S2 — the failure that recurs is a 64-bit value crossing into JavaScript.\n * `mapbox/node-s2` is a **binding**, not a port: it calls the same C++ the reference implementation\n * does, and it still returned wrong cell ids — issue #92, open since 2017, `1152921504606847000`\n * where Java and Go both give `1152921504606846977`. JavaScript's `number` is 53 bits and a cell id\n * is 64, and a binding cannot protect a language boundary that cannot hold the value. H3 settled it\n * by decree before anyone could get it wrong: `h3-js` types `H3Index` as a string. This is the same\n * decree with the type JavaScript grew for it.\n *\n * **And `>>` means three different things across our three layers.** In JavaScript it converts its\n * operand to *32 bits* and takes the shift count modulo 32, so the obvious `dense | (type << 32)`\n * is not a lost high word — it is `type | dense`, silently. The packing below cannot be written on\n * `number` at all and be right.\n *\n * What goes to the GPU does not change: positions and buffer indices stay `number` and\n * `Float32Array`. The conversion happens at the edge, which is where it belongs.\n */\nexport type VertexId = bigint & { readonly vertex: unique symbol };\n\n/**\n * One type's worth of dense ids.\n *\n * `dense_id` is a `UInt32`, so the type index occupies everything above bit 32 — exactly, for all\n * 2³² of them, which is the whole point of the width. The old packing was `type * 2**32 + dense` in\n * `float64` and ran out of exactness at type index 2²¹.\n */\nconst TYPE_SHIFT = 32n;\nconst DENSE_MASK = 0xffff_ffffn;\n\nexport function vertexId(type: number, dense: number): VertexId {\n return ((BigInt(type) << TYPE_SHIFT) | BigInt(dense)) as VertexId;\n}\n\n/** Both halves come back as `number`: each is 32 bits, and a `number` holds those exactly. */\nexport function typeOf(vertex: VertexId): number {\n return Number(vertex >> TYPE_SHIFT);\n}\n\nexport function denseOf(vertex: VertexId): number {\n return Number(vertex & DENSE_MASK);\n}\n\n/**\n * The identity↔index map for whatever is drawn right now.\n *\n * Built once per residency change and never mutated, because that is what a residency change *is*: a\n * different set of vertices, in a different order. It belongs to whoever owns residency — that is\n * the renderer, which composes the buffers — and is read from there by everything else, because a\n * second copy is a second copy that can disagree with the buffers on screen.\n */\nexport interface Resident {\n /** How many points are drawn. */\n readonly size: number;\n /** Where a vertex is drawn, or `undefined` when it is not resident. */\n indexOf(vertex: VertexId): number | undefined;\n /** Which vertex is drawn at a buffer index, or `undefined` past the end of the answer. */\n at(index: number): VertexId | undefined;\n /** Where these vertices are drawn, skipping every one that is not resident. */\n indicesOf(vertices: Iterable<VertexId>): number[];\n /** Which vertices are drawn at these buffer indices, skipping any the answer does not hold. */\n verticesAt(indices: Iterable<number>): VertexId[];\n}\n\nconst NOBODY = new BigUint64Array(0);\n\n/**\n * The map a composition implies, over its first `size` slots. A composition puts its vertices\n * first — then the cells, which have no identity, then the far ends drawn only so an edge has one —\n * so nothing hovers, selects or frames a slot past them. Before the first composition nobody is\n * resident, which is not an error.\n *\n * Keyed by the identity itself. `Map` and `Set` compare keys by SameValueZero, which for a `bigint`\n * is *value* equality — asserted in `resident.test.ts`, because the whole file rests on it.\n */\nexport function residentOf(vertices: BigUint64Array | null = NOBODY, size = vertices?.length ?? 0): Resident {\n const all = vertices ?? NOBODY;\n const drawn = Math.min(size, all.length);\n const index = new Map<bigint, number>();\n for (let i = 0; i < drawn; i++) index.set(all[i] as bigint, i);\n const at = (i: number): VertexId | undefined => (i >= 0 && i < drawn ? (all[i] as VertexId) : undefined);\n const indexOf = (vertex: VertexId): number | undefined => index.get(vertex);\n\n return {\n size: drawn,\n indexOf,\n at,\n indicesOf(wanted) {\n const found: number[] = [];\n for (const vertex of wanted) {\n const i = indexOf(vertex);\n if (i !== undefined) found.push(i);\n }\n return found;\n },\n verticesAt(indices) {\n const found: VertexId[] = [];\n for (const i of indices) {\n const vertex = at(i);\n if (vertex !== undefined) found.push(vertex);\n }\n return found;\n },\n };\n}\n"],"names":["TYPE_SHIFT","DENSE_MASK","vertexId","type","dense","typeOf","vertex","denseOf","NOBODY","residentOf","vertices","size","all","drawn","index","i","at","indexOf","wanted","found","indices"],"mappings":"AAoDA,MAAMA,IAAa,KACbC,IAAa;AAEZ,SAASC,EAASC,GAAcC,GAAyB;AAC9D,SAAS,OAAOD,CAAI,KAAKH,IAAc,OAAOI,CAAK;AACrD;AAGO,SAASC,EAAOC,GAA0B;AAC/C,SAAO,OAAOA,KAAUN,CAAU;AACpC;AAEO,SAASO,EAAQD,GAA0B;AAChD,SAAO,OAAOA,IAASL,CAAU;AACnC;AAuBA,MAAMO,IAAS,IAAI,eAAe,CAAC;AAW5B,SAASC,EAAWC,IAAkCF,GAAQG,KAAOD,KAAA,gBAAAA,EAAU,WAAU,GAAa;AAC3G,QAAME,IAAMF,KAAYF,GAClBK,IAAQ,KAAK,IAAIF,GAAMC,EAAI,MAAM,GACjCE,wBAAY,IAAA;AAClB,WAASC,IAAI,GAAGA,IAAIF,GAAOE,OAAW,IAAIH,EAAIG,CAAC,GAAaA,CAAC;AAC7D,QAAMC,IAAK,CAACD,MAAqCA,KAAK,KAAKA,IAAIF,IAASD,EAAIG,CAAC,IAAiB,QACxFE,IAAU,CAACX,MAAyCQ,EAAM,IAAIR,CAAM;AAE1E,SAAO;AAAA,IACL,MAAMO;AAAA,IACN,SAAAI;AAAA,IACA,IAAAD;AAAA,IACA,UAAUE,GAAQ;AAChB,YAAMC,IAAkB,CAAA;AACxB,iBAAWb,KAAUY,GAAQ;AAC3B,cAAMH,IAAIE,EAAQX,CAAM;AACxB,QAAIS,MAAM,UAAWI,EAAM,KAAKJ,CAAC;AAAA,MACnC;AACA,aAAOI;AAAA,IACT;AAAA,IACA,WAAWC,GAAS;AAClB,YAAMD,IAAoB,CAAA;AAC1B,iBAAWJ,KAAKK,GAAS;AACvB,cAAMd,IAASU,EAAGD,CAAC;AACnB,QAAIT,MAAW,UAAWa,EAAM,KAAKb,CAAM;AAAA,MAC7C;AACA,aAAOa;AAAA,IACT;AAAA,EAAA;AAEJ;"}
@@ -1,42 +0,0 @@
1
- /**
2
- * loaders.gl's `RequestScheduler`, issuing a **batch** where it issues a request, with one slot:
3
- * DuckDB-WASM is one worker behind one port, so a second statement queues behind the first rather
4
- * than overlapping it, and fossil reads a run of consecutive tiles as one statement only when it is
5
- * handed them in one call (`/docs/design/graph`, *one batch in flight*).
6
- *
7
- * Priorities are asked again each time a slot frees, the debounce settles or `prune` runs. A negative
8
- * priority is a request nobody wants any more: queued, it resolves `null` without ever being issued;
9
- * in flight, its batch is aborted only once no request in it is wanted — a batch that still answers
10
- * someone finishes, and answers everyone in it.
11
- */
12
- /** A request's answer, its batch's failure, or `null` when it was never issued or was aborted. */
13
- export type Outcome<R> = {
14
- readonly value: R;
15
- } | {
16
- readonly error: unknown;
17
- } | null;
18
- export interface SchedulerOptions<T, R> {
19
- /** One call for a batch: an answer per handle, in the order given. */
20
- run: (handles: readonly T[], signal: AbortSignal) => Promise<readonly R[]>;
21
- /** Batches running at once. */
22
- maxRequests?: number;
23
- /** Quiet time, in milliseconds, before the queue is issued — a pan settles before it asks. */
24
- debounceTime?: number;
25
- }
26
- export declare class RequestScheduler<T, R> {
27
- #private;
28
- constructor({ debounceTime, maxRequests, run }: SchedulerOptions<T, R>);
29
- schedule(handle: T, priority: (handle: T) => number): Promise<Outcome<R>>;
30
- /** How many requests are queued, and how many batches are running. */
31
- get size(): {
32
- queued: number;
33
- active: number;
34
- };
35
- /** The caller no longer wants `handle`'s answer: it resolves `null` now, wherever it is. */
36
- cancel(handle: T): void;
37
- /** Drops queued requests nobody wants, and aborts a batch in which nobody wants anything. */
38
- prune(): void;
39
- /** Every queued request resolves `null`, and every running batch is aborted. */
40
- clear(): void;
41
- }
42
- //# sourceMappingURL=scheduler.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../../src/core/scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,kGAAkG;AAClG,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI;IAAE,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAAC;AAepF,MAAM,WAAW,gBAAgB,CAAC,CAAC,EAAE,CAAC;IACpC,sEAAsE;IACtE,GAAG,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC3E,+BAA+B;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8FAA8F;IAC9F,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,gBAAgB,CAAC,CAAC,EAAE,CAAC;;gBAQpB,EAAE,YAAgB,EAAE,WAAe,EAAE,GAAG,EAAE,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC;IAM9E,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IAOzE,sEAAsE;IACtE,IAAI,IAAI,IAAI;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAE7C;IAED,4FAA4F;IAC5F,MAAM,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI;IAgBvB,6FAA6F;IAC7F,KAAK,IAAI,IAAI;IAYb,gFAAgF;IAChF,KAAK,IAAI,IAAI;CA4Cd"}
@@ -1,77 +0,0 @@
1
- var v = (i) => {
2
- throw TypeError(i);
3
- };
4
- var y = (i, t, e) => t.has(i) || v("Cannot " + e);
5
- var s = (i, t, e) => (y(i, t, "read from private field"), e ? e.call(i) : t.get(i)), a = (i, t, e) => t.has(i) ? v("Cannot add the same private member more than once") : t instanceof WeakSet ? t.add(i) : t.set(i, e), n = (i, t, e, r) => (y(i, t, "write to private field"), r ? r.call(i, e) : t.set(i, e), e), p = (i, t, e) => (y(i, t, "access private method"), e);
6
- var g, w, m, l, o, h, u, q, b, z;
7
- class x {
8
- constructor({ debounceTime: t = 0, maxRequests: e = 1, run: r }) {
9
- a(this, u);
10
- a(this, g);
11
- a(this, w);
12
- a(this, m);
13
- a(this, l, []);
14
- a(this, o, /* @__PURE__ */ new Set());
15
- a(this, h, null);
16
- n(this, g, r), n(this, w, e), n(this, m, t);
17
- }
18
- schedule(t, e) {
19
- return new Promise((r) => {
20
- s(this, l).push({ handle: t, priority: e, resolve: r, settled: !1, dropped: !1 }), p(this, u, q).call(this);
21
- });
22
- }
23
- /** How many requests are queued, and how many batches are running. */
24
- get size() {
25
- return { queued: s(this, l).length, active: s(this, o).size };
26
- }
27
- /** The caller no longer wants `handle`'s answer: it resolves `null` now, wherever it is. */
28
- cancel(t) {
29
- n(this, l, s(this, l).filter((e) => e.handle !== t ? !0 : (f(e, null), !1)));
30
- for (const e of s(this, o))
31
- for (const r of e.requests)
32
- r.handle === t && (r.dropped = !0, f(r, null));
33
- this.prune();
34
- }
35
- /** Drops queued requests nobody wants, and aborts a batch in which nobody wants anything. */
36
- prune() {
37
- n(this, l, s(this, l).filter((t) => t.priority(t.handle) >= 0 ? !0 : (f(t, null), !1)));
38
- for (const t of s(this, o))
39
- t.requests.some((r) => !r.dropped && r.priority(r.handle) >= 0) || t.controller.abort();
40
- }
41
- /** Every queued request resolves `null`, and every running batch is aborted. */
42
- clear() {
43
- s(this, h) !== null && clearTimeout(s(this, h)), n(this, h, null);
44
- for (const t of s(this, l)) f(t, null);
45
- n(this, l, []);
46
- for (const t of s(this, o)) t.controller.abort();
47
- }
48
- }
49
- g = new WeakMap(), w = new WeakMap(), m = new WeakMap(), l = new WeakMap(), o = new WeakMap(), h = new WeakMap(), u = new WeakSet(), q = function() {
50
- s(this, h) !== null && clearTimeout(s(this, h)), n(this, h, setTimeout(() => {
51
- n(this, h, null), p(this, u, b).call(this);
52
- }, s(this, m)));
53
- }, b = function() {
54
- if (this.prune(), s(this, o).size >= s(this, w) || s(this, l).length === 0) return;
55
- const t = s(this, l).map((e) => ({ request: e, priority: e.priority(e.handle) }));
56
- t.sort((e, r) => e.priority - r.priority), n(this, l, []), p(this, u, z).call(this, { requests: t.map(({ request: e }) => e), controller: new AbortController() });
57
- }, z = async function(t) {
58
- s(this, o).add(t);
59
- const { controller: e, requests: r } = t;
60
- try {
61
- const c = await s(this, g).call(this, r.map((d) => d.handle), e.signal);
62
- if (c.length !== r.length)
63
- throw new Error(`a batch of ${r.length} was answered with ${c.length}`);
64
- r.forEach((d, T) => f(d, e.signal.aborted ? null : { value: c[T] }));
65
- } catch (c) {
66
- for (const d of r) f(d, e.signal.aborted ? null : { error: c });
67
- } finally {
68
- s(this, o).delete(t), s(this, l).length > 0 && p(this, u, b).call(this);
69
- }
70
- };
71
- function f(i, t) {
72
- i.settled || (i.settled = !0, i.resolve(t));
73
- }
74
- export {
75
- x as RequestScheduler
76
- };
77
- //# sourceMappingURL=scheduler.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"scheduler.js","sources":["../../src/core/scheduler.ts"],"sourcesContent":["/**\n * loaders.gl's `RequestScheduler`, issuing a **batch** where it issues a request, with one slot:\n * DuckDB-WASM is one worker behind one port, so a second statement queues behind the first rather\n * than overlapping it, and fossil reads a run of consecutive tiles as one statement only when it is\n * handed them in one call (`/docs/design/graph`, *one batch in flight*).\n *\n * Priorities are asked again each time a slot frees, the debounce settles or `prune` runs. A negative\n * priority is a request nobody wants any more: queued, it resolves `null` without ever being issued;\n * in flight, its batch is aborted only once no request in it is wanted — a batch that still answers\n * someone finishes, and answers everyone in it.\n */\n\n/** A request's answer, its batch's failure, or `null` when it was never issued or was aborted. */\nexport type Outcome<R> = { readonly value: R } | { readonly error: unknown } | null;\n\ninterface Request<T, R> {\n readonly handle: T;\n readonly priority: (handle: T) => number;\n readonly resolve: (outcome: Outcome<R>) => void;\n settled: boolean;\n dropped: boolean;\n}\n\ninterface Flight<T, R> {\n readonly requests: readonly Request<T, R>[];\n readonly controller: AbortController;\n}\n\nexport interface SchedulerOptions<T, R> {\n /** One call for a batch: an answer per handle, in the order given. */\n run: (handles: readonly T[], signal: AbortSignal) => Promise<readonly R[]>;\n /** Batches running at once. */\n maxRequests?: number;\n /** Quiet time, in milliseconds, before the queue is issued — a pan settles before it asks. */\n debounceTime?: number;\n}\n\nexport class RequestScheduler<T, R> {\n readonly #run: SchedulerOptions<T, R>[\"run\"];\n readonly #max: number;\n readonly #debounce: number;\n #queue: Request<T, R>[] = [];\n #flights = new Set<Flight<T, R>>();\n #timer: ReturnType<typeof setTimeout> | null = null;\n\n constructor({ debounceTime = 0, maxRequests = 1, run }: SchedulerOptions<T, R>) {\n this.#run = run;\n this.#max = maxRequests;\n this.#debounce = debounceTime;\n }\n\n schedule(handle: T, priority: (handle: T) => number): Promise<Outcome<R>> {\n return new Promise((resolve) => {\n this.#queue.push({ handle, priority, resolve, settled: false, dropped: false });\n this.#wake();\n });\n }\n\n /** How many requests are queued, and how many batches are running. */\n get size(): { queued: number; active: number } {\n return { queued: this.#queue.length, active: this.#flights.size };\n }\n\n /** The caller no longer wants `handle`'s answer: it resolves `null` now, wherever it is. */\n cancel(handle: T): void {\n this.#queue = this.#queue.filter((request) => {\n if (request.handle !== handle) return true;\n settle(request, null);\n return false;\n });\n for (const flight of this.#flights) {\n for (const request of flight.requests) {\n if (request.handle !== handle) continue;\n request.dropped = true;\n settle(request, null);\n }\n }\n this.prune();\n }\n\n /** Drops queued requests nobody wants, and aborts a batch in which nobody wants anything. */\n prune(): void {\n this.#queue = this.#queue.filter((request) => {\n if (request.priority(request.handle) >= 0) return true;\n settle(request, null);\n return false;\n });\n for (const flight of this.#flights) {\n const wanted = flight.requests.some((r) => !r.dropped && r.priority(r.handle) >= 0);\n if (!wanted) flight.controller.abort();\n }\n }\n\n /** Every queued request resolves `null`, and every running batch is aborted. */\n clear(): void {\n if (this.#timer !== null) clearTimeout(this.#timer);\n this.#timer = null;\n for (const request of this.#queue) settle(request, null);\n this.#queue = [];\n for (const flight of this.#flights) flight.controller.abort();\n }\n\n #wake(): void {\n if (this.#timer !== null) clearTimeout(this.#timer);\n this.#timer = setTimeout(() => {\n this.#timer = null;\n this.#issue();\n }, this.#debounce);\n }\n\n #issue(): void {\n this.prune();\n if (this.#flights.size >= this.#max || this.#queue.length === 0) return;\n const ranked = this.#queue.map((request) => ({ request, priority: request.priority(request.handle) }));\n ranked.sort((a, b) => a.priority - b.priority);\n this.#queue = [];\n void this.#fly({ requests: ranked.map(({ request }) => request), controller: new AbortController() });\n }\n\n async #fly(flight: Flight<T, R>): Promise<void> {\n this.#flights.add(flight);\n const { controller, requests } = flight;\n try {\n const answers = await this.#run(\n requests.map((request) => request.handle),\n controller.signal,\n );\n if (answers.length !== requests.length) {\n throw new Error(`a batch of ${requests.length} was answered with ${answers.length}`);\n }\n requests.forEach((request, i) => settle(request, controller.signal.aborted ? null : { value: answers[i] as R }));\n } catch (error) {\n for (const request of requests) settle(request, controller.signal.aborted ? null : { error });\n } finally {\n this.#flights.delete(flight);\n if (this.#queue.length > 0) this.#issue();\n }\n }\n}\n\nfunction settle<T, R>(request: Request<T, R>, outcome: Outcome<R>): void {\n if (request.settled) return;\n request.settled = true;\n request.resolve(outcome);\n}\n"],"names":["_run","_max","_debounce","_queue","_flights","_timer","_RequestScheduler_instances","wake_fn","issue_fn","fly_fn","RequestScheduler","debounceTime","maxRequests","run","__privateAdd","__privateSet","handle","priority","resolve","__privateGet","__privateMethod","request","settle","flight","ranked","a","b","controller","requests","answers","i","error","outcome"],"mappings":"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"}