@kanzo-tech/graph 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -7
- package/dist/bounded.d.ts +119 -69
- package/dist/bounded.d.ts.map +1 -1
- package/dist/bounded.js +13 -34
- package/dist/bounded.js.map +1 -1
- package/dist/duck-source.d.ts +60 -72
- package/dist/duck-source.d.ts.map +1 -1
- package/dist/duck-source.js +185 -255
- package/dist/duck-source.js.map +1 -1
- package/dist/graph-canvas.d.ts +1 -1
- package/dist/graph-canvas.js.map +1 -1
- package/dist/graph-looks.d.ts +63 -18
- package/dist/graph-looks.d.ts.map +1 -1
- package/dist/graph-looks.js +37 -26
- package/dist/graph-looks.js.map +1 -1
- package/dist/graph-model.d.ts +2 -2
- package/dist/graph-model.d.ts.map +1 -1
- package/dist/graph-model.js +19 -14
- package/dist/graph-model.js.map +1 -1
- package/dist/graph-sim.d.ts +15 -1
- package/dist/graph-sim.d.ts.map +1 -1
- package/dist/graph-sim.js +17 -13
- package/dist/graph-sim.js.map +1 -1
- package/dist/index.d.ts +14 -14
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -48
- package/dist/index.js.map +1 -1
- package/dist/obligations.d.ts +1 -3
- package/dist/obligations.d.ts.map +1 -1
- package/dist/shape-glyph.d.ts +30 -0
- package/dist/shape-glyph.d.ts.map +1 -0
- package/dist/shape-glyph.js +15 -0
- package/dist/shape-glyph.js.map +1 -0
- package/dist/slice-client.d.ts.map +1 -1
- package/dist/slice-client.js +36 -36
- package/dist/slice-client.js.map +1 -1
- package/dist/use-graph-overlays.d.ts +21 -30
- package/dist/use-graph-overlays.d.ts.map +1 -1
- package/dist/use-graph-overlays.js +39 -37
- package/dist/use-graph-overlays.js.map +1 -1
- package/dist/use-graph.d.ts +38 -12
- package/dist/use-graph.d.ts.map +1 -1
- package/dist/use-graph.js +62 -61
- package/dist/use-graph.js.map +1 -1
- package/dist/use-query-loop.d.ts +8 -4
- package/dist/use-query-loop.d.ts.map +1 -1
- package/dist/use-query-loop.js +93 -96
- package/dist/use-query-loop.js.map +1 -1
- package/dist/use-renderer.d.ts.map +1 -1
- package/dist/use-renderer.js +69 -66
- package/dist/use-renderer.js.map +1 -1
- package/package.json +11 -5
- package/dist/memory-source.d.ts +0 -32
- package/dist/memory-source.d.ts.map +0 -1
- package/dist/memory-source.js +0 -134
- package/dist/memory-source.js.map +0 -1
package/dist/graph-looks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-looks.js","sources":["../src/graph-looks.ts"],"sourcesContent":["// Three registers the same graph can be *drawn* in. Not three palettes, and — since a channel is a\n// binding on the request — not three encodings either.\n//\n// **A look is form and nothing else.** No colours: colour belongs to the theme's categorical\n// scheme, the way it belongs to a chart, so every surface showing the same categories gets the same\n// answer. And no encoding: what a channel carries is bound by whoever draws the graph, under Plot's\n// names. A look that decided whether identity reached the GPU as colour or as shape was a theme\n// reaching into an encoding — Vega-Lite states the general rule, that `config` sets defaults for\n// marks, scales, axes and legends and may not touch `encoding` — and its concrete cost was a `fill`\n// binding that painted nothing under the look named Ink.\n//\n// This is the grammar-of-graphics split, and it is the reference model rather than a local idea:\n// in Observable Plot colour is a property of the **scale**, never of the mark, and the mark carries\n// the channels. A look is the mark's geometry.\n//\n// The three names survive as **recommended pairings** — a form plus the bindings that were bundled\n// with it — offered by the host that draws the graph. A host offering three arrangements it authored\n// is not the same act as a preference silently discarding the caller's binding.\n\n/**\n * cosmos.gl's `setPointShapes` enum — the members this canvas draws.\n *\n * The library ships nine: `0` Circle … `4` Pentagon, `5` Hexagon, `6` Star, `7` Cross, `8` None.\n * `None` is missing here on purpose: the point fragment shader `discard`s a `NONE` point that\n * carries no image, so \"past capacity\" spelled as `None` would delete the node from the picture.\n * A category nobody can name is still a node with edges.\n */\nexport const SHAPE = { circle: 0, square: 1, triangle: 2, diamond: 3, cross: 7 } as const;\n\nexport type ShapeId = (typeof SHAPE)[keyof typeof SHAPE];\n\n/**\n * The shape scale, in slot order — the sibling of the colour scale.\n *\n * Plot calls this channel `symbol` and gives it its own legend, which is the tell that it is a peer\n * of colour rather than a decoration. Four slots and no cycling: a fifth category cannot wear circle\n * again without claiming to be the first one.\n *\n * **Four because the shape channel's measured capacity is five, not because small shapes stop being\n * distinguishable.** Giovannangeli et al. (arXiv 2103.06084) put the ceiling at **5 for shape**\n * against **7 for colour**; `SHAPE_ORDER`'s four plus `SHAPE_OTHER` is exactly five distinguishable\n * glyphs, and the two scales differ in cardinality because the channels do. The colour side already\n * says the same thing from the other end — Dracula's document publishes `--chart-capacity: 7`.\n *\n * **This comment used to give the size argument, and the size argument is wrong.** It said a\n * pentagon, a hexagon and a circle are one dot at Ink's floor. Smart & Szafir (CHI 2019,\n * doi:10.1145/3290605.3300899) measured 16 shapes across 6 mark sizes from 6 to 50 px and found\n * shape discrimination *robust* to size: the only significant variation is at 6 px, and it is 4.5\n * accuracy points against 50 px. The conclusion survived the argument that was given for it, which\n * is the most dangerous shape a comment can have — see `OBLIGATIONS` in `./obligations.ts` for what\n * the floor actually protects.\n */\nexport const SHAPE_ORDER: ShapeId[] = [SHAPE.circle, SHAPE.square, SHAPE.triangle, SHAPE.diamond];\n\n/**\n * What a category past the scale wears — the shape channel's `--muted-foreground`.\n *\n * No slot wears it, which is the whole point: it says *not one of the four* rather than repeating\n * the first one. This is the half that used to be missing, and the comment above was false without\n * it — `SHAPE_ORDER[4]` is `undefined`, and the fallback was `circle`.\n */\nexport const SHAPE_OTHER: ShapeId = SHAPE.cross;\n\n/**\n * The geometry a canvas draws — and nothing else.\n *\n * **No `id`, no `label`, no `blurb`.** Those three were a picker's metadata, and the picker was a\n * list of three names that turned out to be two pictures. What a person chooses is declared in\n * `section.ts` as axes and resolved by `lookFrom`; what a renderer consumes is this.\n */\nexport interface Look {\n /** Radius at the lowest degree in the corpus, and at the highest. */\n size: [number, number];\n link: {\n /**\n * Whether the edge layer is drawn at all.\n *\n * It was `Display.links`, a second vocabulary for the picture that sat beside this one with its\n * own default and its own switch. A form that draws no links is a form.\n */\n render: boolean;\n opacity: number;\n width: number;\n /**\n * How far a link bows off the straight line, as a fraction of its length. `0` is straight.\n *\n * Keep it small. Every link curves the same way, so at cosmos.gl's default of `0.5` a few\n * hundred of them read as one pinwheel and the picture looks like it is spinning — motion\n * where there is structure. A hint is enough to tell two parallel edges apart.\n */\n curve: number;\n /**\n * Whether links **add** where they overlap, instead of compositing over one another.\n *\n * cosmos.gl's default is on, which is a choice nobody here made and which the archive made\n * visible: 4,280 grey links at 0.45 summed to a white spray that swallowed 1,543 points of\n * 2–9 px. Every point was uploaded, none was legible, and the picture read as *the nodes are\n * not rendering*.\n *\n * On, it is a real register rather than a bug — additive light is what makes a dense graph read\n * as flow — so it belongs to the form that wants it and not to the renderer's defaults.\n */\n blend: boolean;\n /**\n * Screen lengths between which a link fades out — depth, for free.\n *\n * Keep the far end generous. cosmos.gl measures this in *screen* pixels, so a range that\n * looks reasonable while zoomed in erases the whole edge layer when you zoom out, which\n * reads as \"Show links stopped working\".\n */\n fade: [number, number];\n };\n /** How many of the highest-degree nodes carry a standing label. */\n labels: number;\n /** A darkened rim. Mood rather than a reading aid, which is why it is form and not display. */\n vignette: boolean;\n /**\n * The dot grid behind the graph, which pans and subdivides with the camera.\n *\n * Beside `vignette` because it is the same kind of thing — the backdrop a form sits on — and it\n * arrived from the same place the rim did not: a `Display` interface that spelled the backdrop,\n * the edge layer and two multipliers as a second set of appearance controls.\n */\n grid: boolean;\n // **There is no `pointScale` and no `linkOpacity`**, and they are the two fields `Display` had that\n // this does not. Each was a reader's multiplier over a number this builder already computes from\n // the axis that owns it — `size` from `marks`, `link.opacity` from `marks` — so the panel offered\n // two ways to say one thing and the second could always overrule the measurement. The measured\n // pair (0.28 legible, 0.42 dense) is the whole argument of `marks`; a slider on top of it is the\n // post-process `graph-model.ts` forbids one layer down, wearing a preference's clothes.\n //\n // What is lost with them is the fit-to-corpus case, and it was never a preference: `adaptive`\n // scales a mark by node count, and a computed fit belongs to the tenant's starting point — which\n // is a policy, and which is now expressible.\n\n // There is no `filter`, and its absence is a rule rather than an omission. Nebula carried\n // `saturate(1.1)` on the canvas element — the one thing left in a Look that touched hue, and a\n // chroma multiplier is colour wearing geometry's clothes. Measured over Kanzo's eight slots\n // (2026-08-13, `saturate(1.1)` through the same filter engine the browser applies): it moved\n // every slot, by ΔE 0.85 to **8.05**, which is the size of the separation `deriveScheme`\n // *guarantees* between two different categories. It did not break that separation here —\n // the closest pair went from ΔE 32.36 to 30.38, with room to spare — so the reason it is gone\n // is not a failure it caused, it is that a look must not be able to cause one. The whole claim\n // of the colour layer is that what ships is what was derived and measured; a post-process on\n // the canvas voids it silently, and `graph-model.ts` already forbids the same move one layer\n // down (\"nudging one on the way to the GPU voids all three\").\n}\n\n/**\n * The form a canvas draws, from the axes a person chose.\n *\n * **One function and no table of constants**, which is the shape the axes forced and the reason\n * the three named looks are gone. They were three parallel tables of ten fields; six of those\n * fields separated two of the three by 7–17%, under this file's own threshold for a difference\n * meaning anything — a luminance JND of 6.48–11.30 ΔL*. What is left of them is this: every number\n * appears once, where the axis that owns it is read, and the axis is declared next door in\n * `section.ts` for a panel to draw.\n *\n * **Link opacity and width ride the mark**, and that is what the numbers said rather than a tidy\n * guess: 0.42 and 0.45 on the two dense forms against 0.28 on the legible one. A form that spends\n * more ink on points cannot also spend it on edges.\n *\n * **The legible mark's radius is the whole reason that mark exists.** Its floor protects the other\n * two channels from shape rather than shape from smallness, which is why it is the one to pair\n * `symbol` with: spending shape on identity *and* size on degree at once is what Giovannangeli et\n * al. (arXiv 2103.06084) measure as dropping performance drastically under even minor heterogeneity,\n * and smaller marks worsen it both ways — the luminance JND above, and a square reported larger than\n * any other shape at equal area in 82% of trials (Smart & Szafir, CHI 2019). Not \"a triangle and a\n * square are the same dot below four pixels\", which is what this said for months and is false; see\n * `SHAPE_ORDER` for the measurement that refutes it.\n *\n * **The values are strings because a contributed preference is a string**, in all three kinds, so an\n * unrecognised namespace rides through a write untouched. Parsing what a kind means is the reader's\n * job and it is two lines; `@kanzo-tech/theme` exports the same two, and importing them would add a\n * dependency to this package to carry no code — the same call `GRAPH_SECTION` already makes about the\n * manifest type.\n *\n * A key that is missing, or that carries a value the section never offered, takes the manifest's\n * default. Those defaults are what a graph drew before any of this existed.\n */\nexport function lookFrom(values: Readonly<Record<string, string | undefined>> = {}): Look {\n const on = (key: string, fallback: boolean) => {\n const value = values[key];\n return value === undefined ? fallback : value === \"true\";\n };\n const legible = values.marks === \"legible\";\n const labels = Number.parseFloat(values.labels ?? \"\");\n return {\n size: legible ? [4, 13] : [2, 8],\n link: {\n render: on(\"links\", true),\n opacity: legible ? 0.28 : 0.42,\n width: legible ? 0.5 : 0.6,\n // A hint, and `obligations.ts` says why: every link bows the same way, so cosmos.gl's default\n // of 0.5 reads as one pinwheel. A toggle rather than a range because a reader wants two\n // pictures — straight, and told apart — not a number to tune.\n curve: on(\"bowed-links\", true) ? 0.12 : 0,\n blend: on(\"additive-links\", false),\n // Shared by every form. It was three ranges within ±10% of each other, which is the\n // definition of a field nobody chose.\n fade: [200, 1400],\n },\n labels: Number.isFinite(labels) ? labels : 26,\n vignette: on(\"vignette\", false),\n grid: on(\"grid\", true),\n };\n}\n\n/** What a canvas draws when nobody has chosen anything. */\nexport const DEFAULT_LOOK: Look = lookFrom();\n\n/** The SVG path for a shape glyph inside a 12×12 box — the legend draws what the canvas draws. */\nexport const SHAPE_PATH: Record<ShapeId, string> = {\n [SHAPE.circle]: \"M6 1.6a4.4 4.4 0 1 0 0 8.8 4.4 4.4 0 0 0 0-8.8Z\",\n [SHAPE.square]: \"M2 2h8v8H2Z\",\n [SHAPE.triangle]: \"M6 1.6 10.6 10H1.4Z\",\n [SHAPE.diamond]: \"M6 1 11 6l-5 5-5-5Z\",\n // The proportions are cosmos.gl's own `crossDistance`: a plus with arms at 0.8 of the radius and\n // a bar 0.3 thick, so the legend's glyph is the shape the shader draws.\n [SHAPE.cross]: \"M4.2 1.2h3.6v3h3v3.6h-3v3H4.2v-3h-3V4.2h3Z\",\n};\n"],"names":["SHAPE","SHAPE_ORDER","SHAPE_OTHER","lookFrom","values","on","key","fallback","value","legible","labels","DEFAULT_LOOK","SHAPE_PATH"],"mappings":"AA2BO,MAAMA,IAAQ,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,SAAS,GAAG,OAAO,EAAA,GAyBhEC,IAAyB,CAACD,EAAM,QAAQA,EAAM,QAAQA,EAAM,UAAUA,EAAM,OAAO,GASnFE,IAAuBF,EAAM;AAuHnC,SAASG,EAASC,IAAuD,IAAU;AACxF,QAAMC,IAAK,CAACC,GAAaC,MAAsB;AAC7C,UAAMC,IAAQJ,EAAOE,CAAG;AACxB,WAAOE,MAAU,SAAYD,IAAWC,MAAU;AAAA,EACpD,GACMC,IAAUL,EAAO,UAAU,WAC3BM,IAAS,OAAO,WAAWN,EAAO,UAAU,EAAE;AACpD,SAAO;AAAA,IACL,MAAMK,IAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AAAA,IAC/B,MAAM;AAAA,MACJ,QAAQJ,EAAG,SAAS,EAAI;AAAA,MACxB,SAASI,IAAU,OAAO;AAAA,MAC1B,OAAOA,IAAU,MAAM;AAAA;AAAA;AAAA;AAAA,MAIvB,OAAOJ,EAAG,eAAe,EAAI,IAAI,OAAO;AAAA,MACxC,OAAOA,EAAG,kBAAkB,EAAK;AAAA;AAAA;AAAA,MAGjC,MAAM,CAAC,KAAK,IAAI;AAAA,IAAA;AAAA,IAElB,QAAQ,OAAO,SAASK,CAAM,IAAIA,IAAS;AAAA,IAC3C,UAAUL,EAAG,YAAY,EAAK;AAAA,IAC9B,MAAMA,EAAG,QAAQ,EAAI;AAAA,EAAA;AAEzB;AAGO,MAAMM,IAAqBR,EAAA,GAGrBS,IAAsC;AAAA,EACjD,CAACZ,EAAM,MAAM,GAAG;AAAA,EAChB,CAACA,EAAM,MAAM,GAAG;AAAA,EAChB,CAACA,EAAM,QAAQ,GAAG;AAAA,EAClB,CAACA,EAAM,OAAO,GAAG;AAAA;AAAA;AAAA,EAGjB,CAACA,EAAM,KAAK,GAAG;AACjB;"}
|
|
1
|
+
{"version":3,"file":"graph-looks.js","sources":["../src/graph-looks.ts"],"sourcesContent":["// Three registers the same graph can be *drawn* in. Not three palettes, and — since a channel is a\n// binding on the request — not three encodings either.\n//\n// **A look is form and nothing else.** No colours: colour belongs to the theme's categorical\n// scheme, the way it belongs to a chart, so every surface showing the same categories gets the same\n// answer. And no encoding: what a channel carries is bound by whoever draws the graph, under Plot's\n// names. A look that decided whether identity reached the GPU as colour or as shape was a theme\n// reaching into an encoding — Vega-Lite states the general rule, that `config` sets defaults for\n// marks, scales, axes and legends and may not touch `encoding` — and its concrete cost was a `fill`\n// binding that painted nothing under the look named Ink.\n//\n// This is the grammar-of-graphics split, and it is the reference model rather than a local idea:\n// in Observable Plot colour is a property of the **scale**, never of the mark, and the mark carries\n// the channels. A look is the mark's geometry.\n//\n// The three names survive as **recommended pairings** — a form plus the bindings that were bundled\n// with it — offered by the host that draws the graph. A host offering three arrangements it authored\n// is not the same act as a preference silently discarding the caller's binding.\n\n/**\n * The glyphs this canvas draws — **by name**, because a name is what the concept is.\n *\n * This was five exports of one idea: a `SHAPE` object mapping names to numbers, a `ShapeId` type\n * that was the union of those numbers, `SHAPE_ORDER`, `SHAPE_OTHER` and `SHAPE_PATH` keyed by them.\n * The numbers were never ours. They are cosmos.gl's `setPointShapes` enum indices, and the jump from\n * `3` (diamond) to `7` (cross) is what gives that away — there is no `4`, `5` or `6` here because\n * Pentagon, Hexagon and Star are members this canvas does not draw. Publishing them made the\n * renderer's internal numbering part of a contract, so a host held `3` where it meant *diamond*, and\n * an upstream enum that renumbered would have moved every legend on every page silently.\n *\n * A string union says the same thing, reads at the call site — `<ShapeGlyph shape=\"cross\" />` — and\n * makes the mapping this file's private business, which is what it always was.\n */\nexport type Shape = \"circle\" | \"square\" | \"triangle\" | \"diamond\" | \"cross\";\n\n/**\n * The name → cosmos.gl enum index, and the one place that translation happens.\n *\n * `None` (`8`) has no name here on purpose: the point fragment shader `discard`s a `NONE` point that\n * carries no image, so \"past capacity\" spelled as `None` would delete the node from the picture, and\n * a category nobody can name is still a node with edges. `obligations.ts` grades that.\n *\n * Module-scoped and off the barrel. `buffers` reads it on the way to the GPU; nothing else needs it,\n * and anything that did would be reaching for the enum this type exists to hide.\n */\nexport const SHAPE_INDEX: Record<Shape, number> = {\n circle: 0,\n square: 1,\n triangle: 2,\n diamond: 3,\n cross: 7,\n};\n\n/**\n * The shape scale, in slot order — the sibling of the colour scale.\n *\n * Plot calls this channel `symbol` and gives it its own legend, which is the tell that it is a peer\n * of colour rather than a decoration. Four slots and no cycling: a fifth category cannot wear circle\n * again without claiming to be the first one.\n *\n * **Four because the shape channel's measured capacity is five, not because small shapes stop being\n * distinguishable.** Giovannangeli et al. (arXiv 2103.06084) put the ceiling at **5 for shape**\n * against **7 for colour**; `SHAPE_ORDER`'s four plus `SHAPE_OTHER` is exactly five distinguishable\n * glyphs, and the two scales differ in cardinality because the channels do. The colour side already\n * says the same thing from the other end — Dracula's document publishes `--chart-capacity: 7`.\n *\n * **This comment used to give the size argument, and the size argument is wrong.** It said a\n * pentagon, a hexagon and a circle are one dot at Ink's floor. Smart & Szafir (CHI 2019,\n * doi:10.1145/3290605.3300899) measured 16 shapes across 6 mark sizes from 6 to 50 px and found\n * shape discrimination *robust* to size: the only significant variation is at 6 px, and it is 4.5\n * accuracy points against 50 px. The conclusion survived the argument that was given for it, which\n * is the most dangerous shape a comment can have — see `OBLIGATIONS` in `./obligations.ts` for what\n * the floor actually protects.\n */\nexport const SHAPE_ORDER: Shape[] = [\"circle\", \"square\", \"triangle\", \"diamond\"];\n\n/**\n * What a category past the scale wears — the shape channel's `--muted-foreground`.\n *\n * No slot wears it, which is the whole point: it says *not one of the four* rather than repeating\n * the first one. This is the half that used to be missing, and the comment above was false without\n * it — `SHAPE_ORDER[4]` is `undefined`, and the fallback was `circle`.\n */\nexport const SHAPE_OTHER: Shape = \"cross\";\n\n/**\n * The geometry a canvas draws — and nothing else.\n *\n * **No `id`, no `label`, no `blurb`.** Those three were a picker's metadata, and the picker was a\n * list of three names that turned out to be two pictures. What a person chooses is declared in\n * `section.ts` as axes and resolved by `lookFrom`; what a renderer consumes is this.\n */\nexport interface Look {\n /** Radius at the lowest degree in the corpus, and at the highest. */\n size: [number, number];\n link: {\n /**\n * Whether the edge layer is drawn at all.\n *\n * It was `Display.links`, a second vocabulary for the picture that sat beside this one with its\n * own default and its own switch. A form that draws no links is a form.\n */\n render: boolean;\n opacity: number;\n width: number;\n /**\n * How far a link bows off the straight line, as a fraction of its length. `0` is straight.\n *\n * Keep it small. Every link curves the same way, so at cosmos.gl's default of `0.5` a few\n * hundred of them read as one pinwheel and the picture looks like it is spinning — motion\n * where there is structure. A hint is enough to tell two parallel edges apart.\n */\n curve: number;\n /**\n * Whether links **add** where they overlap, instead of compositing over one another.\n *\n * cosmos.gl's default is on, which is a choice nobody here made and which the archive made\n * visible: 4,280 grey links at 0.45 summed to a white spray that swallowed 1,543 points of\n * 2–9 px. Every point was uploaded, none was legible, and the picture read as *the nodes are\n * not rendering*.\n *\n * On, it is a real register rather than a bug — additive light is what makes a dense graph read\n * as flow — so it belongs to the form that wants it and not to the renderer's defaults.\n */\n blend: boolean;\n /**\n * Screen lengths between which a link fades out — depth, for free.\n *\n * Keep the far end generous. cosmos.gl measures this in *screen* pixels, so a range that\n * looks reasonable while zoomed in erases the whole edge layer when you zoom out, which\n * reads as \"Show links stopped working\".\n */\n fade: [number, number];\n };\n /** How many of the highest-degree nodes carry a standing label. */\n labels: number;\n /** A darkened rim. Mood rather than a reading aid, which is why it is form and not display. */\n vignette: boolean;\n /**\n * The dot grid behind the graph, which pans and subdivides with the camera.\n *\n * Beside `vignette` because it is the same kind of thing — the backdrop a form sits on — and it\n * arrived from the same place the rim did not: a `Display` interface that spelled the backdrop,\n * the edge layer and two multipliers as a second set of appearance controls.\n */\n grid: boolean;\n // **There is no `pointScale` and no `linkOpacity`**, and they are the two fields `Display` had that\n // this does not. Each was a reader's multiplier over a number this builder already computes from\n // the axis that owns it — `size` from `marks`, `link.opacity` from `marks` — so the panel offered\n // two ways to say one thing and the second could always overrule the measurement. The measured\n // pair (0.28 legible, 0.42 dense) is the whole argument of `marks`; a slider on top of it is the\n // post-process `graph-model.ts` forbids one layer down, wearing a preference's clothes.\n //\n // What is lost with them is the fit-to-corpus case, and it was never a preference: `adaptive`\n // scales a mark by node count, and a computed fit belongs to the tenant's starting point — which\n // is a policy, and which is now expressible.\n\n // There is no `filter`, and its absence is a rule rather than an omission. Nebula carried\n // `saturate(1.1)` on the canvas element — the one thing left in a Look that touched hue, and a\n // chroma multiplier is colour wearing geometry's clothes. Measured over Kanzo's eight slots\n // (2026-08-13, `saturate(1.1)` through the same filter engine the browser applies): it moved\n // every slot, by ΔE 0.85 to **8.05**, which is the size of the separation `deriveScheme`\n // *guarantees* between two different categories. It did not break that separation here —\n // the closest pair went from ΔE 32.36 to 30.38, with room to spare — so the reason it is gone\n // is not a failure it caused, it is that a look must not be able to cause one. The whole claim\n // of the colour layer is that what ships is what was derived and measured; a post-process on\n // the canvas voids it silently, and `graph-model.ts` already forbids the same move one layer\n // down (\"nudging one on the way to the GPU voids all three\").\n}\n\n/**\n * The form a canvas draws, from the axes a person chose.\n *\n * **One function and no table of constants**, which is the shape the axes forced and the reason\n * the three named looks are gone. They were three parallel tables of ten fields; six of those\n * fields separated two of the three by 7–17%, under this file's own threshold for a difference\n * meaning anything — a luminance JND of 6.48–11.30 ΔL*. What is left of them is this: every number\n * appears once, where the axis that owns it is read, and the axis is declared next door in\n * `section.ts` for a panel to draw.\n *\n * **Link opacity and width ride the mark**, and that is what the numbers said rather than a tidy\n * guess: 0.42 and 0.45 on the two dense forms against 0.28 on the legible one. A form that spends\n * more ink on points cannot also spend it on edges.\n *\n * **The legible mark's radius is the whole reason that mark exists.** Its floor protects the other\n * two channels from shape rather than shape from smallness, which is why it is the one to pair\n * `symbol` with: spending shape on identity *and* size on degree at once is what Giovannangeli et\n * al. (arXiv 2103.06084) measure as dropping performance drastically under even minor heterogeneity,\n * and smaller marks worsen it both ways — the luminance JND above, and a square reported larger than\n * any other shape at equal area in 82% of trials (Smart & Szafir, CHI 2019). Not \"a triangle and a\n * square are the same dot below four pixels\", which is what this said for months and is false; see\n * `SHAPE_ORDER` for the measurement that refutes it.\n *\n * **The values are strings because a contributed preference is a string**, in all three kinds, so an\n * unrecognised namespace rides through a write untouched. Parsing what a kind means is the reader's\n * job and it is two lines; `@kanzo-tech/theme` exports the same two, and importing them would add a\n * dependency to this package to carry no code — the same call `GRAPH_SECTION` already makes about the\n * manifest type.\n *\n * A key that is missing, or that carries a value the section never offered, takes the manifest's\n * default. Those defaults are what a graph drew before any of this existed.\n */\nexport function lookFrom(values: Readonly<Record<string, string | undefined>> = {}): Look {\n const on = (key: string, fallback: boolean) => {\n const value = values[key];\n return value === undefined ? fallback : value === \"true\";\n };\n const legible = values.marks === \"legible\";\n const labels = Number.parseFloat(values.labels ?? \"\");\n return {\n size: legible ? [4, 13] : [2, 8],\n link: {\n render: on(\"links\", true),\n opacity: legible ? 0.28 : 0.42,\n width: legible ? 0.5 : 0.6,\n // A hint, and `obligations.ts` says why: every link bows the same way, so cosmos.gl's default\n // of 0.5 reads as one pinwheel. A toggle rather than a range because a reader wants two\n // pictures — straight, and told apart — not a number to tune.\n curve: on(\"bowed-links\", true) ? 0.12 : 0,\n blend: on(\"additive-links\", false),\n // Shared by every form. It was three ranges within ±10% of each other, which is the\n // definition of a field nobody chose.\n fade: [200, 1400],\n },\n labels: Number.isFinite(labels) ? labels : 26,\n vignette: on(\"vignette\", false),\n grid: on(\"grid\", true),\n };\n}\n\n/**\n * What a canvas draws when nobody has chosen anything.\n *\n * **Not on the barrel, and it used to be.** It is literally `lookFrom()` — a second public name for\n * a value the package already hands out on request — and the reason it was exported is the one\n * `resolveLook` below removes: a host that wanted one field different had to start from the whole\n * object, because `look` took a whole `Look`. Spreading a default you were given is a copy of it,\n * and a copy is what stops tracking the original the next time a number here moves.\n */\nexport const DEFAULT_LOOK: Look = lookFrom();\n\n/**\n * A look in the pieces a caller wants different — everything else is this package's answer.\n *\n * Two levels, because a `Look` has exactly two: the fields, and `link`. Deep-merging arbitrarily\n * would be a guess about a shape that is right here in this file, and `size` and `fade` are tuples\n * that must be replaced whole rather than merged element-wise.\n */\nexport interface LookPatch extends Partial<Omit<Look, \"link\">> {\n link?: Partial<Look[\"link\"]>;\n}\n\n/**\n * A patch over the package's own default — the merge `DEFAULT_LOOK` existed so a host could do by\n * hand.\n *\n * **Nothing, and it is the shared constant rather than a copy of it.** That identity matters: the\n * buffers are rebuilt whenever the look's reference changes, so a fresh object per render would\n * mean a full colour/size/shape upload on every render of every canvas that never asked for one.\n */\nexport function resolveLook(patch?: LookPatch): Look {\n if (!patch) return DEFAULT_LOOK;\n return { ...DEFAULT_LOOK, ...patch, link: { ...DEFAULT_LOOK.link, ...patch.link } };\n}\n\n/**\n * The SVG path for a shape glyph inside a 12×12 box — the legend draws what the canvas draws.\n *\n * **Off the barrel, and `ShapeGlyph` is what replaced it.** One host imported this, to fill a\n * `<path>` in a legend key and a hover card. What that host actually wanted was *the glyph*, and\n * handing it the path data made it responsible for the viewBox, the fill and the fact that the box\n * is twelve units — three facts it had to keep in step with this file by reading the comment above.\n * A component carries all three and cannot fall out of step with itself.\n */\nexport const SHAPE_PATH: Record<Shape, string> = {\n circle: \"M6 1.6a4.4 4.4 0 1 0 0 8.8 4.4 4.4 0 0 0 0-8.8Z\",\n square: \"M2 2h8v8H2Z\",\n triangle: \"M6 1.6 10.6 10H1.4Z\",\n diamond: \"M6 1 11 6l-5 5-5-5Z\",\n // The proportions are cosmos.gl's own `crossDistance`: a plus with arms at 0.8 of the radius and\n // a bar 0.3 thick, so the legend's glyph is the shape the shader draws.\n cross: \"M4.2 1.2h3.6v3h3v3.6h-3v3H4.2v-3h-3V4.2h3Z\",\n};\n"],"names":["SHAPE_INDEX","SHAPE_ORDER","SHAPE_OTHER","lookFrom","values","on","key","fallback","value","legible","labels","DEFAULT_LOOK","resolveLook","patch","SHAPE_PATH"],"mappings":"AA6CO,MAAMA,IAAqC;AAAA,EAChD,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA,EACT,OAAO;AACT,GAuBaC,IAAuB,CAAC,UAAU,UAAU,YAAY,SAAS,GASjEC,IAAqB;AAuH3B,SAASC,EAASC,IAAuD,IAAU;AACxF,QAAMC,IAAK,CAACC,GAAaC,MAAsB;AAC7C,UAAMC,IAAQJ,EAAOE,CAAG;AACxB,WAAOE,MAAU,SAAYD,IAAWC,MAAU;AAAA,EACpD,GACMC,IAAUL,EAAO,UAAU,WAC3BM,IAAS,OAAO,WAAWN,EAAO,UAAU,EAAE;AACpD,SAAO;AAAA,IACL,MAAMK,IAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AAAA,IAC/B,MAAM;AAAA,MACJ,QAAQJ,EAAG,SAAS,EAAI;AAAA,MACxB,SAASI,IAAU,OAAO;AAAA,MAC1B,OAAOA,IAAU,MAAM;AAAA;AAAA;AAAA;AAAA,MAIvB,OAAOJ,EAAG,eAAe,EAAI,IAAI,OAAO;AAAA,MACxC,OAAOA,EAAG,kBAAkB,EAAK;AAAA;AAAA;AAAA,MAGjC,MAAM,CAAC,KAAK,IAAI;AAAA,IAAA;AAAA,IAElB,QAAQ,OAAO,SAASK,CAAM,IAAIA,IAAS;AAAA,IAC3C,UAAUL,EAAG,YAAY,EAAK;AAAA,IAC9B,MAAMA,EAAG,QAAQ,EAAI;AAAA,EAAA;AAEzB;AAWO,MAAMM,IAAqBR,EAAA;AAqB3B,SAASS,EAAYC,GAAyB;AACnD,SAAKA,IACE,EAAE,GAAGF,GAAc,GAAGE,GAAO,MAAM,EAAE,GAAGF,EAAa,MAAM,GAAGE,EAAM,OAAK,IAD7DF;AAErB;AAWO,MAAMG,IAAoC;AAAA,EAC/C,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,SAAS;AAAA;AAAA;AAAA,EAGT,OAAO;AACT;"}
|
package/dist/graph-model.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Graph, GraphConfig } from '@cosmos.gl/graph';
|
|
2
2
|
import { Slice } from './bounded';
|
|
3
|
-
import { Look,
|
|
3
|
+
import { Look, Shape } from './graph-looks';
|
|
4
4
|
import { Sim } from './graph-sim';
|
|
5
5
|
/**
|
|
6
6
|
* From a slice to the GPU, and nothing about where the slice came from.
|
|
@@ -75,7 +75,7 @@ export declare function isColour(value: string | undefined): value is string;
|
|
|
75
75
|
*/
|
|
76
76
|
export declare function scaleOf(channels: Channels, capacity?: number): {
|
|
77
77
|
color: (ordinal: number) => string;
|
|
78
|
-
shape: (ordinal: number) =>
|
|
78
|
+
shape: (ordinal: number) => Shape;
|
|
79
79
|
};
|
|
80
80
|
export interface Buffers {
|
|
81
81
|
colors: Float32Array;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-model.d.ts","sourceRoot":"","sources":["../src/graph-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,
|
|
1
|
+
{"version":3,"file":"graph-model.d.ts","sourceRoot":"","sources":["../src/graph-model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI3D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,EAAyC,KAAK,IAAI,EAAE,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAC7F,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAEvC;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;OASG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAEnE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,SAAc;qBAI7C,MAAM,KAAG,MAAM;qBAcf,MAAM,KAAG,KAAK;EAGlC;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,YAAY,CAAC;IACpB,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,YAAY,CAAC;CAC1B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,OAAO,CACrB,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,OAAO,EACb,QAAQ,GAAE,QAAa,GACtB,OAAO,CAgFT;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAMlE;AAED,qGAAqG;AACrG,wBAAgB,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,WAAW,CAS5C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,GAAG,WAAW,CA4BjE"}
|
package/dist/graph-model.js
CHANGED
|
@@ -1,21 +1,26 @@
|
|
|
1
|
-
import { CHART_SLOTS as A,
|
|
2
|
-
import {
|
|
3
|
-
import { SHAPE_ORDER as
|
|
4
|
-
function
|
|
1
|
+
import { CHART_SLOTS as A, categoricalColor as D, categoricalCapacity as E } from "@kanzo-tech/ui";
|
|
2
|
+
import { resolveToken as p, toHex as m } from "./css-color.js";
|
|
3
|
+
import { SHAPE_ORDER as F, SHAPE_OTHER as H, SHAPE_INDEX as S } from "./graph-looks.js";
|
|
4
|
+
function w(n) {
|
|
5
5
|
return n !== void 0 && /^(var\(|#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(n);
|
|
6
6
|
}
|
|
7
7
|
function L(n, i = A) {
|
|
8
|
-
const e =
|
|
8
|
+
const e = w(n.fill) ? n.fill : void 0, s = n.symbol !== void 0;
|
|
9
9
|
return {
|
|
10
|
-
color: (o) => e || (o >= i ? "var(--muted-foreground)" :
|
|
10
|
+
color: (o) => e || (o >= i ? "var(--muted-foreground)" : D(o, void 0, i)),
|
|
11
11
|
// The shape order runs out at four, so the fifth ordinal and anything past it land on
|
|
12
12
|
// `SHAPE_OTHER` — which is what makes the scale's claim true. Falling back to `circle` would
|
|
13
13
|
// hand category 5 the glyph category 0 already wears.
|
|
14
|
-
|
|
14
|
+
//
|
|
15
|
+
// A **name**, not cosmos.gl's enum index. This returned a `ShapeId` — the union of the numbers
|
|
16
|
+
// `setPointShapes` takes — so a legend drawing what this scale answered was holding the
|
|
17
|
+
// renderer's internal numbering. `buffers` does the translation below, at the one point where a
|
|
18
|
+
// number is what the GPU wants.
|
|
19
|
+
shape: (o) => s ? F[o] ?? H : "circle"
|
|
15
20
|
};
|
|
16
21
|
}
|
|
17
|
-
function
|
|
18
|
-
const o = L(s,
|
|
22
|
+
function _(n, i, e, s = {}) {
|
|
23
|
+
const o = L(s, E(e)), v = /* @__PURE__ */ new Map(), C = (t) => {
|
|
19
24
|
let r = v.get(t);
|
|
20
25
|
return r || (r = p(e, o.color(t)), v.set(t, r)), r;
|
|
21
26
|
}, k = n.positions.length / 2, f = new Float32Array(k * 4), y = new Float32Array(k), d = new Float32Array(k), a = n.sizes;
|
|
@@ -33,7 +38,7 @@ function T(n, i, e, s = {}) {
|
|
|
33
38
|
const r = n.categories[t] ?? 0;
|
|
34
39
|
f.set(C(r), t * 4);
|
|
35
40
|
const l = a ? (Math.sqrt(a[t]) - g) / b : 0;
|
|
36
|
-
y[t] = i.size[0] + l * (i.size[1] - i.size[0]), d[t] = o.shape(r);
|
|
41
|
+
y[t] = i.size[0] + l * (i.size[1] - i.size[0]), d[t] = S[o.shape(r)];
|
|
37
42
|
}
|
|
38
43
|
const h = n.links.length / 2, O = new Float32Array(h * 4), c = s.stroke ? p(e, s.stroke) : null;
|
|
39
44
|
for (let t = 0; t < h; t++) {
|
|
@@ -42,7 +47,7 @@ function T(n, i, e, s = {}) {
|
|
|
42
47
|
}
|
|
43
48
|
return { colors: f, sizes: y, shapes: d, linkColors: O };
|
|
44
49
|
}
|
|
45
|
-
function
|
|
50
|
+
function T(n, i) {
|
|
46
51
|
const { sourceIndexToTargetIndices: e, targetIndexToSourceIndices: s } = n.graph;
|
|
47
52
|
return [
|
|
48
53
|
...((e == null ? void 0 : e[i]) ?? []).map((o) => o[0]),
|
|
@@ -90,10 +95,10 @@ function G(n, i) {
|
|
|
90
95
|
}
|
|
91
96
|
export {
|
|
92
97
|
G as appearance,
|
|
93
|
-
|
|
98
|
+
_ as buffers,
|
|
94
99
|
q as forces,
|
|
95
|
-
|
|
96
|
-
|
|
100
|
+
w as isColour,
|
|
101
|
+
T as neighboursOf,
|
|
97
102
|
L as scaleOf
|
|
98
103
|
};
|
|
99
104
|
//# sourceMappingURL=graph-model.js.map
|
package/dist/graph-model.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-model.js","sources":["../src/graph-model.ts"],"sourcesContent":["import type { Graph, GraphConfig } from \"@cosmos.gl/graph\";\n// The categorical scheme is on the root barrel, not `/analytics`: a graph paints from it and\n// never opens a database, so the chart half is not what it needs.\nimport { CHART_SLOTS, categoricalCapacity, categoricalColor } from \"@kanzo-tech/ui\";\nimport type { Slice } from \"./bounded\";\nimport { resolveToken, toHex, type Rgba } from \"./css-color\";\nimport { SHAPE, SHAPE_ORDER, SHAPE_OTHER, type Look, type ShapeId } from \"./graph-looks\";\nimport type { Sim } from \"./graph-sim\";\n\n/**\n * From a slice to the GPU, and nothing about where the slice came from.\n *\n * `load()` used to live here — a relation in, every id, every row, an id→index map and a global\n * ranking out. ADR-0001 deleted it: the working set was N, so the ceiling was whatever N the machine\n * could hold, and 1,225 ms of first paint at 200,000 nodes was the measurement that ended the\n * argument. What replaces it is not a faster loader but a different question — `BoundedSource`\n * answers *what should I draw*, `useQueryLoop` asks it, and this turns the answer into buffers.\n *\n * The visible consequence is that **a category is an ordinal here, never a name.** A slice carries\n * `Uint16Array` category codes because carrying twenty thousand label strings to colour twenty\n * thousand dots is paying for a vocabulary the GPU cannot read. What each ordinal is *called* is a\n * question for a legend, and a legend asks the source.\n */\n\n/**\n * What each channel is bound to — Plot's names, and Plot's rule about what a value means.\n *\n * **A CSS colour is a constant; anything else is a column name.** `fill=\"kind\"` spends colour on a\n * category; `fill=\"var(--foreground)\"` paints every point one ink and leaves colour free to mean the\n * selection. That is not our invention: it is how Plot reads the same string, and it is what makes\n * \"monochrome\" expressible without a look that rebinds an encoding.\n *\n * The rule is spelled narrowly on purpose: a constant is `var(…)`, a hex, or a CSS colour function.\n * **A bare word is always a column**, so a corpus with a column called `red` is not a trap. The cost\n * is that the 148 CSS named colours are not accepted as constants, which is the trade a one-line\n * rule buys over a table nobody would keep current.\n */\nexport interface Channels {\n /** Which column colours a point, or a CSS colour every point wears. */\n fill?: string;\n /**\n * Which column a point's **shape** carries — Plot's `symbol`, and a peer of colour rather than a\n * decoration.\n *\n * Bound to the same column as `fill`, this is redundant encoding and costs nothing. Bound to a\n * *different* column it would need a second categorical array in the slice and in every source,\n * which is not paid for — and it is also the pairing the literature warns about, so the limit and\n * the advice point the same way. A slice carries one categorical column, and this spends shape on\n * it.\n */\n symbol?: string;\n /**\n * What tints a link. **Absent, each link takes the colour of the vertex it leaves**; a constant\n * makes links plain structure.\n *\n * No column form yet: a per-link datum — weight, confidence, recency — is a second array a slice\n * does not carry.\n */\n stroke?: string;\n}\n\n/**\n * Whether a channel's value is a **colour** — and therefore a constant rather than a column.\n *\n * Plot's test, narrowed to what a token-based system actually writes. Exported because the split it\n * decides happens in two places: the buffers paint the constant, and the query must not be asked to\n * fetch a column called `var(--foreground)`.\n */\nexport function isColour(value: string | undefined): value is string {\n return value !== undefined && /^(var\\(|#|rgb|hsl|oklch|oklab|lab|lch|color\\()/i.test(value);\n}\n\n/**\n * The categorical scale the bindings imply — what colour and what shape a category ordinal wears.\n *\n * One answer for the GPU buffers, the hover card and the legend, because three answers is how a\n * legend ends up disagreeing with the canvas it explains. Values are CSS strings: the DOM resolves\n * them itself, and the buffer path resolves them once on its way to the GPU.\n *\n * `capacity` is where Other begins, and it is the document's number rather than the token\n * vocabulary's: a set derived from a client's brand names 6 to 8 real categories, not always 8. The\n * colour past it would come out muted anyway — `compile()` writes `var(--muted-foreground)` into\n * those slots — but the graph has to *count* the same way, or a legend claims eight kinds it cannot\n * tell apart.\n */\nexport function scaleOf(channels: Channels, capacity = CHART_SLOTS) {\n const constant = isColour(channels.fill) ? channels.fill : undefined;\n const shaped = channels.symbol !== undefined;\n return {\n color: (ordinal: number): string => {\n if (constant) return constant;\n return ordinal >= capacity\n ? \"var(--muted-foreground)\"\n : categoricalColor(ordinal, undefined, capacity);\n },\n // The shape order runs out at four, so the fifth ordinal and anything past it land on\n // `SHAPE_OTHER` — which is what makes the scale's claim true. Falling back to `circle` would\n // hand category 5 the glyph category 0 already wears.\n shape: (ordinal: number): ShapeId =>\n shaped ? (SHAPE_ORDER[ordinal] ?? SHAPE_OTHER) : SHAPE.circle,\n };\n}\n\nexport interface Buffers {\n colors: Float32Array;\n sizes: Float32Array;\n shapes: Float32Array;\n linkColors: Float32Array;\n}\n\n/**\n * Every per-point and per-link attribute the GPU needs, from one slice and the live theme.\n *\n * `host` is the element the tokens are read against, which is what makes `var(--primary)` a legal\n * value in a look: the browser resolves it for the tree the canvas actually sits in, so the same\n * look answers differently in light and in dark.\n *\n * `display` is deliberately not an argument. Everything the reader's sliders control is a *global\n * scalar*, and a global scalar belongs in a uniform — see `appearance` — not multiplied into every\n * size and every RGBA quad that then have to be re-uploaded.\n *\n * The size ramp now spans **this slice**, not the corpus. That is the trade ADR-0001 names: a global\n * ordering is what a whole-corpus load gets for free and a bounded one cannot have. It is also\n * arguably the better question — the biggest node *here* is what a reader is looking at.\n */\nexport function buffers(\n slice: Slice,\n look: Look,\n host: Element,\n channels: Channels = {},\n): Buffers {\n const scale = scaleOf(channels, categoricalCapacity(host));\n\n /** Ordinal → resolved colour, memoised: a slice of 20,000 points wears at most a handful. */\n const rgba = new Map<number, Rgba>();\n const colourOf = (ordinal: number): Rgba => {\n let resolved = rgba.get(ordinal);\n if (!resolved) {\n resolved = resolveToken(host, scale.color(ordinal));\n rgba.set(ordinal, resolved);\n }\n return resolved;\n };\n\n const n = slice.positions.length / 2;\n const colors = new Float32Array(n * 4);\n const sizes = new Float32Array(n);\n const shapes = new Float32Array(n);\n\n // Whatever the source ranks by, square-rooted: a degree distribution is heavy-tailed and a linear\n // ramp leaves everything but the three biggest hubs on the floor. It used to read a second column\n // in aggregate mode — how many vertices a super-node stood for — and there are no super-nodes.\n const ramp = slice.sizes;\n let lo = 0;\n let span = 1;\n if (ramp && ramp.length > 0) {\n let min = Number.POSITIVE_INFINITY;\n let max = 0;\n for (let i = 0; i < ramp.length; i++) {\n const value = ramp[i] as number;\n if (value < min) min = value;\n if (value > max) max = value;\n }\n lo = Math.sqrt(Number.isFinite(min) ? min : 0);\n span = Math.sqrt(max) - lo || 1;\n }\n\n /**\n * Where the marks stop and the anchors begin.\n *\n * An anchor exists so an edge leaving the window has an end to be drawn to, and it is **not a\n * mark**: radius zero and alpha zero, so it cannot paint, cannot be picked and cannot be occluded\n * by. The zeroing is the loop bound and nothing else: the buffers are allocated zero-filled, so\n * stopping at `marks` leaves every anchor at radius zero and alpha zero. Writing it out again\n * afterwards would be a second statement of the same fact that no mutation can distinguish from\n * the first — which is how a guard goes green for the wrong reason.\n */\n const marks = Math.min(slice.marks, n);\n\n for (let i = 0; i < marks; i++) {\n const ordinal = slice.categories[i] ?? 0;\n // The slot colour is used as given. Nebula used to lighten it by degree, which is exactly the\n // kind of adjustment a validated palette cannot survive: every slot was measured for lightness\n // band, chroma floor and separation, and nudging one on the way to the GPU voids all three.\n colors.set(colourOf(ordinal), i * 4);\n const t = ramp ? (Math.sqrt(ramp[i] as number) - lo) / span : 0;\n sizes[i] = look.size[0] + t * (look.size[1] - look.size[0]);\n shapes[i] = scale.shape(ordinal);\n }\n\n const count = slice.links.length / 2;\n const linkColors = new Float32Array(count * 4);\n // Absent, a link takes the colour of the vertex it leaves; a constant makes links plain structure.\n const neutral = channels.stroke ? resolveToken(host, channels.stroke) : null;\n for (let e = 0; e < count; e++) {\n const src = slice.links[e * 2] ?? 0;\n const r = neutral ? neutral[0] : (colors[src * 4] ?? 0.7);\n const g = neutral ? neutral[1] : (colors[src * 4 + 1] ?? 0.7);\n const b = neutral ? neutral[2] : (colors[src * 4 + 2] ?? 0.7);\n // Alpha is 1, and it is *reserved* — for a datum that genuinely differs per link: edge weight,\n // confidence, recency. It used to carry `look.opacity × display.linkOpacity`, which is the same\n // number on every link, and paying for that cost a full re-upload of this array on every tick of\n // the Edge opacity slider. That product is a uniform now (`appearance`), and the shader\n // multiplies the two: `color.a * linkOpacity * …`. Do not spend this channel again.\n linkColors.set([r, g, b, 1], e * 4);\n }\n\n return { colors, sizes, shapes, linkColors };\n}\n\n/**\n * The points one hop from `index`, in both directions, **within the drawn slice**.\n *\n * This is the renderer's adjacency, not the graph's: it answers what is on screen, which is what a\n * hover highlight wants. The graph's own answer — what is adjacent whether or not it is drawn — is a\n * `neighbourhood` query, and a source that supports one answers it.\n *\n * Ours because 3.0 dropped `getAdjacentIndices` and the method that looks like its replacement is\n * not one: `getConnectedLinkIndices` filters on `n.has(d)`, so it answers only with links whose\n * *other* endpoint is also in the argument — an induced subgraph, which for a single point is its\n * self-loops. The adjacency lists themselves are still public on `graph.graph`, and each entry is a\n * `[otherPointIndex, linkIndex]` pair, so the neighbourhood is the first element of each.\n */\nexport function neighboursOf(graph: Graph, index: number): number[] {\n const { sourceIndexToTargetIndices, targetIndexToSourceIndices } = graph.graph;\n return [\n ...(sourceIndexToTargetIndices?.[index] ?? []).map((pair) => pair[0]),\n ...(targetIndexToSourceIndices?.[index] ?? []).map((pair) => pair[0]),\n ];\n}\n\n/** The simulation coefficients, in cosmos.gl's spelling. Shared by construction and every change. */\nexport function forces(sim: Sim): GraphConfig {\n return {\n simulationGravity: sim.gravity,\n simulationRepulsion: sim.repulsion,\n simulationLinkSpring: sim.linkSpring,\n simulationLinkDistance: sim.linkDistance,\n simulationFriction: sim.friction,\n simulationCluster: sim.cluster,\n };\n}\n\n/**\n * Everything the picture needs that is *one number for the whole canvas* — cosmos.gl's uniforms.\n *\n * That is the line between this and `buffers`, and it is the renderer's own: a uniform is read fresh\n * from the config on every draw, so changing one rebuilds no array and uploads nothing — which is\n * why a look change costs the GPU a `setConfigPartial` and no upload at all.\n *\n * It took a `Display` beside the look, and the two multipliers it carried are gone: each scaled a\n * number this same look already computes from the axis that owns it, so the panel offered two ways\n * to say one thing and the slider could always overrule the measurement.\n */\nexport function appearance(look: Look, host: Element): GraphConfig {\n return {\n // Always the theme's surface. Nebula used to pin a near-black of its own, which made it the one\n // look that ignored light mode — and put its fixed dark plane at odds with the light chrome\n // sitting on top of it.\n backgroundColor: toHex(resolveToken(host, \"var(--background)\")),\n // Points hold their screen size in every look. This was a field until all three settled on the\n // same value, at which point it was a field with one possible answer.\n scalePointsOnZoom: false,\n renderLinks: look.link.render,\n /** Edge opacity — the look's, multiplying each link's buffer alpha. */\n linkOpacity: look.link.opacity,\n linkDefaultWidth: look.link.width,\n linkBlending: look.link.blend,\n curvedLinks: look.link.curve > 0,\n curvedLinkControlPointDistance: look.link.curve,\n linkVisibilityDistanceRange: look.link.fade,\n linkVisibilityMinTransparency: 0.12,\n renderHoveredPointRing: true,\n hoveredPointRingColor: toHex(resolveToken(host, \"var(--primary)\")),\n focusedPointRingColor: toHex(resolveToken(host, \"var(--primary)\")),\n // The two greyouts are not the same kind of number, whatever the names suggest. A greyed link\n // multiplies (`opacity *= greyoutOpacity`), so it stays under the slider; a greyed point takes\n // this *instead of* `pointOpacity` — the point shader is an if/else. So a global point opacity,\n // if this canvas ever grows one, would not reach a dimmed node, and its floor would be 0.1 flat.\n pointGreyoutOpacity: 0.1,\n linkGreyoutOpacity: 0.025,\n };\n}\n"],"names":["isColour","value","scaleOf","channels","capacity","CHART_SLOTS","constant","shaped","ordinal","categoricalColor","SHAPE_ORDER","SHAPE_OTHER","SHAPE","buffers","slice","look","host","scale","categoricalCapacity","rgba","colourOf","resolved","resolveToken","n","colors","sizes","shapes","ramp","lo","span","min","max","i","marks","t","count","linkColors","neutral","e","src","r","g","b","neighboursOf","graph","index","sourceIndexToTargetIndices","targetIndexToSourceIndices","pair","forces","sim","appearance","toHex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"graph-model.js","sources":["../src/graph-model.ts"],"sourcesContent":["import type { Graph, GraphConfig } from \"@cosmos.gl/graph\";\n// The categorical scheme is on the root barrel, not `/analytics`: a graph paints from it and\n// never opens a database, so the chart half is not what it needs.\nimport { CHART_SLOTS, categoricalCapacity, categoricalColor } from \"@kanzo-tech/ui\";\nimport type { Slice } from \"./bounded\";\nimport { resolveToken, toHex, type Rgba } from \"./css-color\";\nimport { SHAPE_INDEX, SHAPE_ORDER, SHAPE_OTHER, type Look, type Shape } from \"./graph-looks\";\nimport type { Sim } from \"./graph-sim\";\n\n/**\n * From a slice to the GPU, and nothing about where the slice came from.\n *\n * `load()` used to live here — a relation in, every id, every row, an id→index map and a global\n * ranking out. ADR-0001 deleted it: the working set was N, so the ceiling was whatever N the machine\n * could hold, and 1,225 ms of first paint at 200,000 nodes was the measurement that ended the\n * argument. What replaces it is not a faster loader but a different question — `BoundedSource`\n * answers *what should I draw*, `useQueryLoop` asks it, and this turns the answer into buffers.\n *\n * The visible consequence is that **a category is an ordinal here, never a name.** A slice carries\n * `Uint16Array` category codes because carrying twenty thousand label strings to colour twenty\n * thousand dots is paying for a vocabulary the GPU cannot read. What each ordinal is *called* is a\n * question for a legend, and a legend asks the source.\n */\n\n/**\n * What each channel is bound to — Plot's names, and Plot's rule about what a value means.\n *\n * **A CSS colour is a constant; anything else is a column name.** `fill=\"kind\"` spends colour on a\n * category; `fill=\"var(--foreground)\"` paints every point one ink and leaves colour free to mean the\n * selection. That is not our invention: it is how Plot reads the same string, and it is what makes\n * \"monochrome\" expressible without a look that rebinds an encoding.\n *\n * The rule is spelled narrowly on purpose: a constant is `var(…)`, a hex, or a CSS colour function.\n * **A bare word is always a column**, so a corpus with a column called `red` is not a trap. The cost\n * is that the 148 CSS named colours are not accepted as constants, which is the trade a one-line\n * rule buys over a table nobody would keep current.\n */\nexport interface Channels {\n /** Which column colours a point, or a CSS colour every point wears. */\n fill?: string;\n /**\n * Which column a point's **shape** carries — Plot's `symbol`, and a peer of colour rather than a\n * decoration.\n *\n * Bound to the same column as `fill`, this is redundant encoding and costs nothing. Bound to a\n * *different* column it would need a second categorical array in the slice and in every source,\n * which is not paid for — and it is also the pairing the literature warns about, so the limit and\n * the advice point the same way. A slice carries one categorical column, and this spends shape on\n * it.\n */\n symbol?: string;\n /**\n * What tints a link. **Absent, each link takes the colour of the vertex it leaves**; a constant\n * makes links plain structure.\n *\n * No column form yet: a per-link datum — weight, confidence, recency — is a second array a slice\n * does not carry.\n */\n stroke?: string;\n}\n\n/**\n * Whether a channel's value is a **colour** — and therefore a constant rather than a column.\n *\n * Plot's test, narrowed to what a token-based system actually writes. Exported because the split it\n * decides happens in two places: the buffers paint the constant, and the query must not be asked to\n * fetch a column called `var(--foreground)`.\n */\nexport function isColour(value: string | undefined): value is string {\n return value !== undefined && /^(var\\(|#|rgb|hsl|oklch|oklab|lab|lch|color\\()/i.test(value);\n}\n\n/**\n * The categorical scale the bindings imply — what colour and what shape a category ordinal wears.\n *\n * One answer for the GPU buffers, the hover card and the legend, because three answers is how a\n * legend ends up disagreeing with the canvas it explains. Values are CSS strings: the DOM resolves\n * them itself, and the buffer path resolves them once on its way to the GPU.\n *\n * `capacity` is where Other begins, and it is the document's number rather than the token\n * vocabulary's: a set derived from a client's brand names 6 to 8 real categories, not always 8. The\n * colour past it would come out muted anyway — `compile()` writes `var(--muted-foreground)` into\n * those slots — but the graph has to *count* the same way, or a legend claims eight kinds it cannot\n * tell apart.\n */\nexport function scaleOf(channels: Channels, capacity = CHART_SLOTS) {\n const constant = isColour(channels.fill) ? channels.fill : undefined;\n const shaped = channels.symbol !== undefined;\n return {\n color: (ordinal: number): string => {\n if (constant) return constant;\n return ordinal >= capacity\n ? \"var(--muted-foreground)\"\n : categoricalColor(ordinal, undefined, capacity);\n },\n // The shape order runs out at four, so the fifth ordinal and anything past it land on\n // `SHAPE_OTHER` — which is what makes the scale's claim true. Falling back to `circle` would\n // hand category 5 the glyph category 0 already wears.\n //\n // A **name**, not cosmos.gl's enum index. This returned a `ShapeId` — the union of the numbers\n // `setPointShapes` takes — so a legend drawing what this scale answered was holding the\n // renderer's internal numbering. `buffers` does the translation below, at the one point where a\n // number is what the GPU wants.\n shape: (ordinal: number): Shape =>\n shaped ? (SHAPE_ORDER[ordinal] ?? SHAPE_OTHER) : \"circle\",\n };\n}\n\nexport interface Buffers {\n colors: Float32Array;\n sizes: Float32Array;\n shapes: Float32Array;\n linkColors: Float32Array;\n}\n\n/**\n * Every per-point and per-link attribute the GPU needs, from one slice and the live theme.\n *\n * `host` is the element the tokens are read against, which is what makes `var(--primary)` a legal\n * value in a look: the browser resolves it for the tree the canvas actually sits in, so the same\n * look answers differently in light and in dark.\n *\n * `display` is deliberately not an argument. Everything the reader's sliders control is a *global\n * scalar*, and a global scalar belongs in a uniform — see `appearance` — not multiplied into every\n * size and every RGBA quad that then have to be re-uploaded.\n *\n * The size ramp now spans **this slice**, not the corpus. That is the trade ADR-0001 names: a global\n * ordering is what a whole-corpus load gets for free and a bounded one cannot have. It is also\n * arguably the better question — the biggest node *here* is what a reader is looking at.\n */\nexport function buffers(\n slice: Slice,\n look: Look,\n host: Element,\n channels: Channels = {},\n): Buffers {\n const scale = scaleOf(channels, categoricalCapacity(host));\n\n /** Ordinal → resolved colour, memoised: a slice of 20,000 points wears at most a handful. */\n const rgba = new Map<number, Rgba>();\n const colourOf = (ordinal: number): Rgba => {\n let resolved = rgba.get(ordinal);\n if (!resolved) {\n resolved = resolveToken(host, scale.color(ordinal));\n rgba.set(ordinal, resolved);\n }\n return resolved;\n };\n\n const n = slice.positions.length / 2;\n const colors = new Float32Array(n * 4);\n const sizes = new Float32Array(n);\n const shapes = new Float32Array(n);\n\n // Whatever the source ranks by, square-rooted: a degree distribution is heavy-tailed and a linear\n // ramp leaves everything but the three biggest hubs on the floor. It used to read a second column\n // in aggregate mode — how many vertices a super-node stood for — and there are no super-nodes.\n const ramp = slice.sizes;\n let lo = 0;\n let span = 1;\n if (ramp && ramp.length > 0) {\n let min = Number.POSITIVE_INFINITY;\n let max = 0;\n for (let i = 0; i < ramp.length; i++) {\n const value = ramp[i] as number;\n if (value < min) min = value;\n if (value > max) max = value;\n }\n lo = Math.sqrt(Number.isFinite(min) ? min : 0);\n span = Math.sqrt(max) - lo || 1;\n }\n\n /**\n * Where the marks stop and the anchors begin.\n *\n * An anchor exists so an edge leaving the window has an end to be drawn to, and it is **not a\n * mark**: radius zero and alpha zero, so it cannot paint, cannot be picked and cannot be occluded\n * by. The zeroing is the loop bound and nothing else: the buffers are allocated zero-filled, so\n * stopping at `marks` leaves every anchor at radius zero and alpha zero. Writing it out again\n * afterwards would be a second statement of the same fact that no mutation can distinguish from\n * the first — which is how a guard goes green for the wrong reason.\n */\n const marks = Math.min(slice.marks, n);\n\n for (let i = 0; i < marks; i++) {\n const ordinal = slice.categories[i] ?? 0;\n // The slot colour is used as given. Nebula used to lighten it by degree, which is exactly the\n // kind of adjustment a validated palette cannot survive: every slot was measured for lightness\n // band, chroma floor and separation, and nudging one on the way to the GPU voids all three.\n colors.set(colourOf(ordinal), i * 4);\n const t = ramp ? (Math.sqrt(ramp[i] as number) - lo) / span : 0;\n sizes[i] = look.size[0] + t * (look.size[1] - look.size[0]);\n // The one place a glyph becomes a number: `setPointShapes` takes cosmos.gl's enum, and this is\n // the only consumer of it. Everything above and outside says `\"cross\"`.\n shapes[i] = SHAPE_INDEX[scale.shape(ordinal)] as number;\n }\n\n const count = slice.links.length / 2;\n const linkColors = new Float32Array(count * 4);\n // Absent, a link takes the colour of the vertex it leaves; a constant makes links plain structure.\n const neutral = channels.stroke ? resolveToken(host, channels.stroke) : null;\n for (let e = 0; e < count; e++) {\n const src = slice.links[e * 2] ?? 0;\n const r = neutral ? neutral[0] : (colors[src * 4] ?? 0.7);\n const g = neutral ? neutral[1] : (colors[src * 4 + 1] ?? 0.7);\n const b = neutral ? neutral[2] : (colors[src * 4 + 2] ?? 0.7);\n // Alpha is 1, and it is *reserved* — for a datum that genuinely differs per link: edge weight,\n // confidence, recency. It used to carry `look.opacity × display.linkOpacity`, which is the same\n // number on every link, and paying for that cost a full re-upload of this array on every tick of\n // the Edge opacity slider. That product is a uniform now (`appearance`), and the shader\n // multiplies the two: `color.a * linkOpacity * …`. Do not spend this channel again.\n linkColors.set([r, g, b, 1], e * 4);\n }\n\n return { colors, sizes, shapes, linkColors };\n}\n\n/**\n * The points one hop from `index`, in both directions, **within the drawn slice**.\n *\n * This is the renderer's adjacency, not the graph's: it answers what is on screen, which is what a\n * hover highlight wants. The graph's own answer — what is adjacent whether or not it is drawn — is a\n * `neighbourhood` query, and a source that supports one answers it.\n *\n * Ours because 3.0 dropped `getAdjacentIndices` and the method that looks like its replacement is\n * not one: `getConnectedLinkIndices` filters on `n.has(d)`, so it answers only with links whose\n * *other* endpoint is also in the argument — an induced subgraph, which for a single point is its\n * self-loops. The adjacency lists themselves are still public on `graph.graph`, and each entry is a\n * `[otherPointIndex, linkIndex]` pair, so the neighbourhood is the first element of each.\n */\nexport function neighboursOf(graph: Graph, index: number): number[] {\n const { sourceIndexToTargetIndices, targetIndexToSourceIndices } = graph.graph;\n return [\n ...(sourceIndexToTargetIndices?.[index] ?? []).map((pair) => pair[0]),\n ...(targetIndexToSourceIndices?.[index] ?? []).map((pair) => pair[0]),\n ];\n}\n\n/** The simulation coefficients, in cosmos.gl's spelling. Shared by construction and every change. */\nexport function forces(sim: Sim): GraphConfig {\n return {\n simulationGravity: sim.gravity,\n simulationRepulsion: sim.repulsion,\n simulationLinkSpring: sim.linkSpring,\n simulationLinkDistance: sim.linkDistance,\n simulationFriction: sim.friction,\n simulationCluster: sim.cluster,\n };\n}\n\n/**\n * Everything the picture needs that is *one number for the whole canvas* — cosmos.gl's uniforms.\n *\n * That is the line between this and `buffers`, and it is the renderer's own: a uniform is read fresh\n * from the config on every draw, so changing one rebuilds no array and uploads nothing — which is\n * why a look change costs the GPU a `setConfigPartial` and no upload at all.\n *\n * It took a `Display` beside the look, and the two multipliers it carried are gone: each scaled a\n * number this same look already computes from the axis that owns it, so the panel offered two ways\n * to say one thing and the slider could always overrule the measurement.\n */\nexport function appearance(look: Look, host: Element): GraphConfig {\n return {\n // Always the theme's surface. Nebula used to pin a near-black of its own, which made it the one\n // look that ignored light mode — and put its fixed dark plane at odds with the light chrome\n // sitting on top of it.\n backgroundColor: toHex(resolveToken(host, \"var(--background)\")),\n // Points hold their screen size in every look. This was a field until all three settled on the\n // same value, at which point it was a field with one possible answer.\n scalePointsOnZoom: false,\n renderLinks: look.link.render,\n /** Edge opacity — the look's, multiplying each link's buffer alpha. */\n linkOpacity: look.link.opacity,\n linkDefaultWidth: look.link.width,\n linkBlending: look.link.blend,\n curvedLinks: look.link.curve > 0,\n curvedLinkControlPointDistance: look.link.curve,\n linkVisibilityDistanceRange: look.link.fade,\n linkVisibilityMinTransparency: 0.12,\n renderHoveredPointRing: true,\n hoveredPointRingColor: toHex(resolveToken(host, \"var(--primary)\")),\n focusedPointRingColor: toHex(resolveToken(host, \"var(--primary)\")),\n // The two greyouts are not the same kind of number, whatever the names suggest. A greyed link\n // multiplies (`opacity *= greyoutOpacity`), so it stays under the slider; a greyed point takes\n // this *instead of* `pointOpacity` — the point shader is an if/else. So a global point opacity,\n // if this canvas ever grows one, would not reach a dimmed node, and its floor would be 0.1 flat.\n pointGreyoutOpacity: 0.1,\n linkGreyoutOpacity: 0.025,\n };\n}\n"],"names":["isColour","value","scaleOf","channels","capacity","CHART_SLOTS","constant","shaped","ordinal","categoricalColor","SHAPE_ORDER","SHAPE_OTHER","buffers","slice","look","host","scale","categoricalCapacity","rgba","colourOf","resolved","resolveToken","n","colors","sizes","shapes","ramp","lo","span","min","max","i","marks","t","SHAPE_INDEX","count","linkColors","neutral","e","src","r","g","b","neighboursOf","graph","index","sourceIndexToTargetIndices","targetIndexToSourceIndices","pair","forces","sim","appearance","toHex"],"mappings":"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"}
|
package/dist/graph-sim.d.ts
CHANGED
|
@@ -35,6 +35,20 @@ export interface Sim {
|
|
|
35
35
|
* what a graph simulated before any of this existed.
|
|
36
36
|
*/
|
|
37
37
|
export declare function simFrom(values?: Readonly<Record<string, string | undefined>>): Sim;
|
|
38
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* What a canvas simulates with when nobody has chosen anything.
|
|
40
|
+
*
|
|
41
|
+
* **Not on the barrel, and it used to be** — for the reason its twin was: it is `simFrom()`, a
|
|
42
|
+
* second public name for a value already available on request, exported only because `sim` took a
|
|
43
|
+
* whole `Sim` and a host changing `gravity` had to supply the other five.
|
|
44
|
+
*/
|
|
39
45
|
export declare const DEFAULT_SIM: Sim;
|
|
46
|
+
/**
|
|
47
|
+
* The coefficients a caller wants different, over the ones this package chose.
|
|
48
|
+
*
|
|
49
|
+
* Flat, so a spread is the whole merge. `undefined` returns the shared constant rather than a copy:
|
|
50
|
+
* `useRenderer` re-heats when the forces change and tells them apart by reference, so a fresh object
|
|
51
|
+
* per render would put energy back into a settled layout on every render.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveSim(patch?: Partial<Sim>): Sim;
|
|
40
54
|
//# sourceMappingURL=graph-sim.d.ts.map
|
package/dist/graph-sim.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-sim.d.ts","sourceRoot":"","sources":["../src/graph-sim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iEAAiE;AACjE,MAAM,WAAW,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,mGAAmG;IACnG,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAM,GAAG,GAAG,CAatF;AAED
|
|
1
|
+
{"version":3,"file":"graph-sim.d.ts","sourceRoot":"","sources":["../src/graph-sim.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,iEAAiE;AACjE,MAAM,WAAW,GAAG;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,mGAAmG;IACnG,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,OAAO,CAAC,MAAM,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAM,GAAG,GAAG,CAatF;AAED;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,EAAE,GAAe,CAAC;AAE1C;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAGpD"}
|
package/dist/graph-sim.js
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
-
function
|
|
2
|
-
const
|
|
3
|
-
const
|
|
4
|
-
return Number.isFinite(
|
|
1
|
+
function u(i = {}) {
|
|
2
|
+
const n = (e, s) => {
|
|
3
|
+
const r = Number.parseFloat(i[e] ?? "");
|
|
4
|
+
return Number.isFinite(r) ? r : s;
|
|
5
5
|
};
|
|
6
6
|
return {
|
|
7
|
-
gravity:
|
|
8
|
-
repulsion:
|
|
9
|
-
linkSpring:
|
|
10
|
-
linkDistance:
|
|
11
|
-
friction:
|
|
12
|
-
cluster:
|
|
7
|
+
gravity: n("gravity", 0.14),
|
|
8
|
+
repulsion: n("repulsion", 1.1),
|
|
9
|
+
linkSpring: n("link-spring", 0.6),
|
|
10
|
+
linkDistance: n("link-distance", 18),
|
|
11
|
+
friction: n("friction", 0.86),
|
|
12
|
+
cluster: n("cluster", 0.1)
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
|
-
const
|
|
15
|
+
const t = u();
|
|
16
|
+
function o(i) {
|
|
17
|
+
return i ? { ...t, ...i } : t;
|
|
18
|
+
}
|
|
16
19
|
export {
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
t as DEFAULT_SIM,
|
|
21
|
+
o as resolveSim,
|
|
22
|
+
u as simFrom
|
|
19
23
|
};
|
|
20
24
|
//# sourceMappingURL=graph-sim.js.map
|
package/dist/graph-sim.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-sim.js","sources":["../src/graph-sim.ts"],"sourcesContent":["/**\n * The force coefficients, and the one function that builds them from the axes a person chose.\n *\n * `graph-looks.ts`'s sibling, and deliberately its twin: a type the renderer consumes, one builder\n * that reads declared string values, and a default that is the builder called with nothing. What was\n * here before is what was there before — an interface, a `DEFAULT_SIM` table beside it, and a dock\n * that held six of them in React state and drew six sliders by hand.\n *\n * **A coefficient is not appearance, and it is still a preference.** `section.ts` says why it shares\n * the manifest: `tokens` are the colours a document may move, `prefs` are what the person on the\n * screen decides, and somebody tuning a layout until it settles is deciding.\n */\n\n/** Force coefficients, handed straight to the GPU simulation. */\nexport interface Sim {\n gravity: number;\n repulsion: number;\n linkSpring: number;\n linkDistance: number;\n friction: number;\n /** Pull toward the node's group position on the cluster ring. Zero lets the links decide alone. */\n cluster: number;\n}\n\n/**\n * Coefficients that settle a few-hundred-node graph into something readable.\n *\n * Chosen against a corpus of that size, and they are a starting point rather than a law: a graph\n * two orders of magnitude larger wants less repulsion and more friction, and the measurements in\n * `BENCHMARKS.md` say a live simulation is finished by around 200,000 points regardless. What a\n * corpus of a given size wants is computed rather than chosen — see `adaptive` — and a host that\n * knows its corpus should start its users at that answer through the tenant policy.\n *\n * The values are strings for the reason `lookFrom`'s are: a contributed preference is a string in\n * all three kinds, so an unrecognised namespace rides through a write untouched. A key that is\n * missing, or that carries a value the section never offered, takes the default below — which is\n * what a graph simulated before any of this existed.\n */\nexport function simFrom(values: Readonly<Record<string, string | undefined>> = {}): Sim {\n const num = (key: string, fallback: number) => {\n const value = Number.parseFloat(values[key] ?? \"\");\n return Number.isFinite(value) ? value : fallback;\n };\n return {\n gravity: num(\"gravity\", 0.14),\n repulsion: num(\"repulsion\", 1.1),\n linkSpring: num(\"link-spring\", 0.6),\n linkDistance: num(\"link-distance\", 18),\n friction: num(\"friction\", 0.86),\n cluster: num(\"cluster\", 0.1),\n };\n}\n\n
|
|
1
|
+
{"version":3,"file":"graph-sim.js","sources":["../src/graph-sim.ts"],"sourcesContent":["/**\n * The force coefficients, and the one function that builds them from the axes a person chose.\n *\n * `graph-looks.ts`'s sibling, and deliberately its twin: a type the renderer consumes, one builder\n * that reads declared string values, and a default that is the builder called with nothing. What was\n * here before is what was there before — an interface, a `DEFAULT_SIM` table beside it, and a dock\n * that held six of them in React state and drew six sliders by hand.\n *\n * **A coefficient is not appearance, and it is still a preference.** `section.ts` says why it shares\n * the manifest: `tokens` are the colours a document may move, `prefs` are what the person on the\n * screen decides, and somebody tuning a layout until it settles is deciding.\n */\n\n/** Force coefficients, handed straight to the GPU simulation. */\nexport interface Sim {\n gravity: number;\n repulsion: number;\n linkSpring: number;\n linkDistance: number;\n friction: number;\n /** Pull toward the node's group position on the cluster ring. Zero lets the links decide alone. */\n cluster: number;\n}\n\n/**\n * Coefficients that settle a few-hundred-node graph into something readable.\n *\n * Chosen against a corpus of that size, and they are a starting point rather than a law: a graph\n * two orders of magnitude larger wants less repulsion and more friction, and the measurements in\n * `BENCHMARKS.md` say a live simulation is finished by around 200,000 points regardless. What a\n * corpus of a given size wants is computed rather than chosen — see `adaptive` — and a host that\n * knows its corpus should start its users at that answer through the tenant policy.\n *\n * The values are strings for the reason `lookFrom`'s are: a contributed preference is a string in\n * all three kinds, so an unrecognised namespace rides through a write untouched. A key that is\n * missing, or that carries a value the section never offered, takes the default below — which is\n * what a graph simulated before any of this existed.\n */\nexport function simFrom(values: Readonly<Record<string, string | undefined>> = {}): Sim {\n const num = (key: string, fallback: number) => {\n const value = Number.parseFloat(values[key] ?? \"\");\n return Number.isFinite(value) ? value : fallback;\n };\n return {\n gravity: num(\"gravity\", 0.14),\n repulsion: num(\"repulsion\", 1.1),\n linkSpring: num(\"link-spring\", 0.6),\n linkDistance: num(\"link-distance\", 18),\n friction: num(\"friction\", 0.86),\n cluster: num(\"cluster\", 0.1),\n };\n}\n\n/**\n * What a canvas simulates with when nobody has chosen anything.\n *\n * **Not on the barrel, and it used to be** — for the reason its twin was: it is `simFrom()`, a\n * second public name for a value already available on request, exported only because `sim` took a\n * whole `Sim` and a host changing `gravity` had to supply the other five.\n */\nexport const DEFAULT_SIM: Sim = simFrom();\n\n/**\n * The coefficients a caller wants different, over the ones this package chose.\n *\n * Flat, so a spread is the whole merge. `undefined` returns the shared constant rather than a copy:\n * `useRenderer` re-heats when the forces change and tells them apart by reference, so a fresh object\n * per render would put energy back into a settled layout on every render.\n */\nexport function resolveSim(patch?: Partial<Sim>): Sim {\n if (!patch) return DEFAULT_SIM;\n return { ...DEFAULT_SIM, ...patch };\n}\n"],"names":["simFrom","values","num","key","fallback","value","DEFAULT_SIM","resolveSim","patch"],"mappings":"AAsCO,SAASA,EAAQC,IAAuD,IAAS;AACtF,QAAMC,IAAM,CAACC,GAAaC,MAAqB;AAC7C,UAAMC,IAAQ,OAAO,WAAWJ,EAAOE,CAAG,KAAK,EAAE;AACjD,WAAO,OAAO,SAASE,CAAK,IAAIA,IAAQD;AAAA,EAC1C;AACA,SAAO;AAAA,IACL,SAASF,EAAI,WAAW,IAAI;AAAA,IAC5B,WAAWA,EAAI,aAAa,GAAG;AAAA,IAC/B,YAAYA,EAAI,eAAe,GAAG;AAAA,IAClC,cAAcA,EAAI,iBAAiB,EAAE;AAAA,IACrC,UAAUA,EAAI,YAAY,IAAI;AAAA,IAC9B,SAASA,EAAI,WAAW,GAAG;AAAA,EAAA;AAE/B;AASO,MAAMI,IAAmBN,EAAA;AASzB,SAASO,EAAWC,GAA2B;AACpD,SAAKA,IACE,EAAE,GAAGF,GAAa,GAAGE,EAAA,IADTF;AAErB;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -19,24 +19,25 @@
|
|
|
19
19
|
* precomputed once and stored as a column — which is why a simulation is opt-in here and off by
|
|
20
20
|
* default, and why the render path is bounded rather than fast.
|
|
21
21
|
*/
|
|
22
|
-
export {
|
|
23
|
-
export {
|
|
22
|
+
export { scaleOf, neighboursOf, type Channels } from './graph-model';
|
|
23
|
+
export { lookFrom, type Look, type LookPatch, type Shape, } from './graph-looks';
|
|
24
|
+
export { ShapeGlyph, type ShapeGlyphProps } from './shape-glyph';
|
|
24
25
|
/**
|
|
25
26
|
* The graph, in Ark's four pieces.
|
|
26
27
|
*
|
|
27
28
|
* `useGraph(props)` **creates** the api and `useGraphContext()` **reads** it, which is Ark's
|
|
28
29
|
* convention and was inverted here: the reader was `useGraphCanvas` and there was no creator.
|
|
29
30
|
* `GraphCanvas` is the shortcut that does both, and `GraphRootProvider` is what a host reaches for
|
|
30
|
-
* when it has to call a hook *beside* the canvas — `useGraphOverlays` and the `events`
|
|
31
|
-
*
|
|
31
|
+
* when it has to call a hook *beside* the canvas — `useGraphOverlays` takes the api and the `events`
|
|
32
|
+
* block reads `getGraph`/`getResident` off it, both from above the element where no context is
|
|
33
|
+
* readable.
|
|
32
34
|
*
|
|
33
35
|
* That was not a symmetry we wanted for its own sake: it is what the workspace could not adopt
|
|
34
36
|
* `GraphCanvas` without, and the `graphRef`/`residentRef` props that stood in for it are gone.
|
|
35
37
|
*/
|
|
36
38
|
export { GraphCanvas, GraphRootProvider, useGraphContext, type GraphCanvasProps, type GraphRootProviderProps, } from './graph-canvas';
|
|
37
39
|
export { useGraph, type GraphApi, type GraphEvents, type UseGraphProps } from './use-graph';
|
|
38
|
-
export {
|
|
39
|
-
export { useGraphOverlays, GRID, type GraphOverlayOptions, type GraphOverlays, } from './use-graph-overlays';
|
|
40
|
+
export { useGraphOverlays, type GraphOverlays } from './use-graph-overlays';
|
|
40
41
|
export { useGraphSelection, cursorChip } from './use-graph-selection';
|
|
41
42
|
/**
|
|
42
43
|
* Identity, and the map from it to the buffer index cosmos.gl draws at.
|
|
@@ -57,16 +58,15 @@ export { residentOf, vertexId, typeOf, denseOf, type Resident, type VertexId, }
|
|
|
57
58
|
* which is what removed the ceiling rather than raising it.
|
|
58
59
|
*
|
|
59
60
|
* `useQueryLoop` is the loop that asks — it observes the camera, debounces, cancels what the
|
|
60
|
-
* camera has already superseded, and pushes each answer into the renderer.
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
61
|
+
* camera has already superseded, and pushes each answer into the renderer. **The source itself is
|
|
62
|
+
* not here and there is one of it**: `openCorpus`, on `@kanzo-tech/graph/duckdb`, because a corpus
|
|
63
|
+
* is read through a database and a database is an optional peer. What is left on this barrel is the
|
|
64
|
+
* rendering surface — the hooks, the look, identity and the buffers a slice implies — and it draws
|
|
65
|
+
* nothing on its own.
|
|
64
66
|
*/
|
|
65
|
-
export {
|
|
66
|
-
export { memorySource, type MemoryGraph } from './memory-source';
|
|
67
|
-
export { clusterRing } from './cluster-ring';
|
|
67
|
+
export { shouldSlice, type BoundedSource, type Slice, type SliceRequest, type Viewport, } from './bounded';
|
|
68
68
|
export { adaptive } from './adaptive';
|
|
69
69
|
export { resolveToken, toHex, type Rgba } from './css-color';
|
|
70
70
|
export { type GraphCommands, type Motion, type Selection, type SelectionSource, type Tool, } from './types';
|
|
71
|
-
export {
|
|
71
|
+
export { simFrom, type Sim } from './graph-sim';
|
|
72
72
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAeH,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAC;AAqBrE,OAAO,EAIL,QAAQ,EACR,KAAK,IAAI,EACT,KAAK,SAAS,EACd,KAAK,KAAK,GACX,MAAM,eAAe,CAAC;AAQvB,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,KAAK,QAAQ,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAgC5F,OAAO,EAAE,gBAAgB,EAAE,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC5E,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAEtE;;;;;;;;GAQG;AACH,OAAO,EACL,UAAU,EACV,QAAQ,EACR,MAAM,EACN,OAAO,EACP,KAAK,QAAQ,EACb,KAAK,QAAQ,GACd,MAAM,YAAY,CAAC;AAwBpB;;;;;;;;;;;;;;GAcG;AAoBH,OAAO,EACL,WAAW,EACX,KAAK,aAAa,EAClB,KAAK,KAAK,EACV,KAAK,YAAY,EACjB,KAAK,QAAQ,GACd,MAAM,WAAW,CAAC;AAsBnB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAKtC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAE7D,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,SAAS,EACd,KAAK,eAAe,EACpB,KAAK,IAAI,GACV,MAAM,SAAS,CAAC;AASjB,OAAO,EAAE,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,53 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { cursorChip as v, useGraphSelection as
|
|
8
|
-
import { denseOf as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import { resolveToken as J, toHex as Q } from "./css-color.js";
|
|
14
|
-
import { DEFAULT_SIM as W, simFrom as X } from "./graph-sim.js";
|
|
1
|
+
import { neighboursOf as e, scaleOf as p } from "./graph-model.js";
|
|
2
|
+
import { lookFrom as f } from "./graph-looks.js";
|
|
3
|
+
import { ShapeGlyph as x } from "./shape-glyph.js";
|
|
4
|
+
import { GraphCanvas as a, GraphRootProvider as h, useGraphContext as i } from "./graph-canvas.js";
|
|
5
|
+
import { useGraph as n } from "./use-graph.js";
|
|
6
|
+
import { useGraphOverlays as G } from "./use-graph-overlays.js";
|
|
7
|
+
import { cursorChip as v, useGraphSelection as O } from "./use-graph-selection.js";
|
|
8
|
+
import { denseOf as y, residentOf as C, typeOf as S, vertexId as k } from "./resident.js";
|
|
9
|
+
import { shouldSlice as b } from "./bounded.js";
|
|
10
|
+
import { adaptive as H } from "./adaptive.js";
|
|
11
|
+
import { resolveToken as P, toHex as R } from "./css-color.js";
|
|
12
|
+
import { simFrom as j } from "./graph-sim.js";
|
|
15
13
|
export {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
l as GraphCanvas,
|
|
21
|
-
n as GraphRootProvider,
|
|
22
|
-
H as REHEAT,
|
|
23
|
-
E as SHAPE,
|
|
24
|
-
u as SHAPE_ORDER,
|
|
25
|
-
S as SHAPE_OTHER,
|
|
26
|
-
i as SHAPE_PATH,
|
|
27
|
-
g as SUPERSEDED,
|
|
28
|
-
w as adaptive,
|
|
29
|
-
o as appearance,
|
|
30
|
-
p as buffers,
|
|
31
|
-
j as clusterRing,
|
|
14
|
+
a as GraphCanvas,
|
|
15
|
+
h as GraphRootProvider,
|
|
16
|
+
x as ShapeGlyph,
|
|
17
|
+
H as adaptive,
|
|
32
18
|
v as cursorChip,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
k as isSuperseded,
|
|
37
|
-
O as lookFrom,
|
|
38
|
-
M as memorySource,
|
|
39
|
-
s as neighboursOf,
|
|
19
|
+
y as denseOf,
|
|
20
|
+
f as lookFrom,
|
|
21
|
+
e as neighboursOf,
|
|
40
22
|
C as residentOf,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
23
|
+
P as resolveToken,
|
|
24
|
+
p as scaleOf,
|
|
25
|
+
b as shouldSlice,
|
|
26
|
+
j as simFrom,
|
|
27
|
+
R as toHex,
|
|
28
|
+
S as typeOf,
|
|
29
|
+
n as useGraph,
|
|
30
|
+
i as useGraphContext,
|
|
31
|
+
G as useGraphOverlays,
|
|
32
|
+
O as useGraphSelection,
|
|
33
|
+
k as vertexId
|
|
52
34
|
};
|
|
53
35
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
|
package/dist/obligations.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Channels } from './graph-model';
|
|
2
|
-
import {
|
|
2
|
+
import { Look } from './graph-looks';
|
|
3
3
|
/**
|
|
4
4
|
* What the graph's geometry owes, as a report rather than as prose.
|
|
5
5
|
*
|
|
@@ -57,6 +57,4 @@ export interface Check extends Obligation {
|
|
|
57
57
|
* `OBLIGATIONS.length - check().length` is the number of open questions this section has.
|
|
58
58
|
*/
|
|
59
59
|
export declare function check(): Check[];
|
|
60
|
-
/** `SHAPE.cross` is the past-capacity glyph and `SHAPE` is re-exported so a caller can name it. */
|
|
61
|
-
export { SHAPE };
|
|
62
60
|
//# sourceMappingURL=obligations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obligations.d.ts","sourceRoot":"","sources":["../src/obligations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,
|
|
1
|
+
{"version":3,"file":"obligations.d.ts","sourceRoot":"","sources":["../src/obligations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAsC,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AAE9E;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,UAAU;IACzB,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,gGAAgG;IAChG,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gDAAgD;IAChD,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;CAChB;AAgDD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,GAAG,KAAK,GAAG,IAAI,CAK7E;AAED,eAAO,MAAM,WAAW,EAAE,SAAS,UAAU,EAiE5C,CAAC;AAEF,8DAA8D;AAC9D,MAAM,WAAW,KAAM,SAAQ,UAAU;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,OAAO,CAAC;CACb;AAED;;;;;;GAMG;AACH,wBAAgB,KAAK,IAAI,KAAK,EAAE,CAa/B"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Shape } from './graph-looks';
|
|
2
|
+
/**
|
|
3
|
+
* The glyph the canvas draws for a category, in the DOM — a legend key, a hover card, a preview.
|
|
4
|
+
*
|
|
5
|
+
* **This replaced `SHAPE_PATH` on the barrel, and the difference is what a host is made responsible
|
|
6
|
+
* for.** The path table was exported for one reason: a host drawing a legend wanted the same glyph
|
|
7
|
+
* the point shader fills, because a legend drawn from a second set of shapes is a legend that
|
|
8
|
+
* explains a picture nobody is looking at. What the host got was path *data*, and with it three
|
|
9
|
+
* facts it had to keep in step with `graph-looks.ts` by reading a comment — that the box is twelve
|
|
10
|
+
* units, that the path wants a `fill` rather than a `stroke`, and which enum index each glyph is
|
|
11
|
+
* keyed by. Every one of those was silent when it drifted.
|
|
12
|
+
*
|
|
13
|
+
* A component carries all three and cannot disagree with itself. What is left at the call site is
|
|
14
|
+
* the only thing the host actually decides: how big, and what colour.
|
|
15
|
+
*
|
|
16
|
+
* **No `"use client"`, deliberately.** It is a function of its props with no state, no effect and no
|
|
17
|
+
* event handler, so it renders on a server the way any other markup does. The rest of this package
|
|
18
|
+
* is client-only because a WebGL context is; a `<path>` is not.
|
|
19
|
+
*/
|
|
20
|
+
export interface ShapeGlyphProps extends React.SVGProps<SVGSVGElement> {
|
|
21
|
+
/** Which glyph — the name `scaleOf(...).shape(ordinal)` answers with. */
|
|
22
|
+
shape: Shape;
|
|
23
|
+
/**
|
|
24
|
+
* What to fill it with. Defaults to `currentColor`, so a glyph inside a legend row inherits the
|
|
25
|
+
* row's colour and a host that is colouring by category passes `scaleOf(...).color(ordinal)`.
|
|
26
|
+
*/
|
|
27
|
+
color?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function ShapeGlyph({ color, shape, ...rest }: ShapeGlyphProps): import("react").JSX.Element;
|
|
30
|
+
//# sourceMappingURL=shape-glyph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape-glyph.d.ts","sourceRoot":"","sources":["../src/shape-glyph.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,KAAK,EAAE,MAAM,eAAe,CAAC;AAEvD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,WAAW,eAAgB,SAAQ,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC;IACpE,yEAAyE;IACzE,KAAK,EAAE,KAAK,CAAC;IACb;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,UAAU,CAAC,EAAE,KAAsB,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,eAAe,+BAUrF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as r } from "react/jsx-runtime";
|
|
2
|
+
import { SHAPE_PATH as i } from "./graph-looks.js";
|
|
3
|
+
function n({ color: o = "currentColor", shape: t, ...e }) {
|
|
4
|
+
return (
|
|
5
|
+
// The `viewBox` is the glyph's own box and is not a prop: the paths are authored inside a 12×12
|
|
6
|
+
// square, which is the fact the host used to have to know. Size it from outside — a `className`,
|
|
7
|
+
// a `width`/`height`, or `x`/`y`/`width`/`height` when this is nested inside another `<svg>`,
|
|
8
|
+
// which is how a preview places a glyph at a vertex.
|
|
9
|
+
/* @__PURE__ */ r("svg", { viewBox: "0 0 12 12", ...e, children: /* @__PURE__ */ r("path", { d: i[t], fill: o }) })
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
n as ShapeGlyph
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=shape-glyph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shape-glyph.js","sources":["../src/shape-glyph.tsx"],"sourcesContent":["import { SHAPE_PATH, type Shape } from \"./graph-looks\";\n\n/**\n * The glyph the canvas draws for a category, in the DOM — a legend key, a hover card, a preview.\n *\n * **This replaced `SHAPE_PATH` on the barrel, and the difference is what a host is made responsible\n * for.** The path table was exported for one reason: a host drawing a legend wanted the same glyph\n * the point shader fills, because a legend drawn from a second set of shapes is a legend that\n * explains a picture nobody is looking at. What the host got was path *data*, and with it three\n * facts it had to keep in step with `graph-looks.ts` by reading a comment — that the box is twelve\n * units, that the path wants a `fill` rather than a `stroke`, and which enum index each glyph is\n * keyed by. Every one of those was silent when it drifted.\n *\n * A component carries all three and cannot disagree with itself. What is left at the call site is\n * the only thing the host actually decides: how big, and what colour.\n *\n * **No `\"use client\"`, deliberately.** It is a function of its props with no state, no effect and no\n * event handler, so it renders on a server the way any other markup does. The rest of this package\n * is client-only because a WebGL context is; a `<path>` is not.\n */\nexport interface ShapeGlyphProps extends React.SVGProps<SVGSVGElement> {\n /** Which glyph — the name `scaleOf(...).shape(ordinal)` answers with. */\n shape: Shape;\n /**\n * What to fill it with. Defaults to `currentColor`, so a glyph inside a legend row inherits the\n * row's colour and a host that is colouring by category passes `scaleOf(...).color(ordinal)`.\n */\n color?: string;\n}\n\nexport function ShapeGlyph({ color = \"currentColor\", shape, ...rest }: ShapeGlyphProps) {\n return (\n // The `viewBox` is the glyph's own box and is not a prop: the paths are authored inside a 12×12\n // square, which is the fact the host used to have to know. Size it from outside — a `className`,\n // a `width`/`height`, or `x`/`y`/`width`/`height` when this is nested inside another `<svg>`,\n // which is how a preview places a glyph at a vertex.\n <svg viewBox=\"0 0 12 12\" {...rest}>\n <path d={SHAPE_PATH[shape]} fill={color} />\n </svg>\n );\n}\n"],"names":["ShapeGlyph","color","shape","rest","jsx","SHAPE_PATH"],"mappings":";;AA8BO,SAASA,EAAW,EAAE,OAAAC,IAAQ,gBAAgB,OAAAC,GAAO,GAAGC,KAAyB;AACtF;AAAA;AAAA;AAAA;AAAA;AAAA,IAKE,gBAAAC,EAAC,OAAA,EAAI,SAAQ,aAAa,GAAGD,GAC3B,UAAA,gBAAAC,EAAC,QAAA,EAAK,GAAGC,EAAWH,CAAK,GAAG,MAAMD,GAAO,EAAA,CAC3C;AAAA;AAEJ;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slice-client.d.ts","sourceRoot":"","sources":["../src/slice-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG7E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,SAAU,SAAQ,YAAY;;IAOzC;;;;;OAKG;gBACS,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS;IAK1D;;;;;;;;OAQG;IACH,IAAa,YAAY,IAAI,OAAO,CAEnC;IAED;;;;;;;OAOG;IACH,IAAI,SAAS,IAAI,UAAU,CAE1B;IAED;;;;;;OAMG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"slice-client.d.ts","sourceRoot":"","sources":["../src/slice-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAG7E;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,SAAU,SAAQ,YAAY;;IAOzC;;;;;OAKG;gBACS,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,SAAS;IAK1D;;;;;;;;OAQG;IACH,IAAa,YAAY,IAAI,OAAO,CAEnC;IAED;;;;;;;OAOG;IACH,IAAI,SAAS,IAAI,UAAU,CAE1B;IAED;;;;;;OAMG;IACH,GAAG,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IA4B5D;;;;;;OAMG;IACH,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC,GAAG,IAAI,EAEpD;IAED,+FAA+F;IAC/F,OAAO,IAAI,IAAI;IAWN,KAAK,CAAC,MAAM,GAAE,UAAe,GAAG,MAAM,GAAG,IAAI;IAI7C,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI;IAQhC,UAAU,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;CAMxC"}
|