@kanzo-tech/graph 0.9.0 → 0.11.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 +60 -95
- package/dist/core/categories.d.ts +12 -0
- package/dist/core/categories.d.ts.map +1 -0
- package/dist/core/categories.js +14 -0
- package/dist/core/categories.js.map +1 -0
- package/dist/core/channels.d.ts +34 -0
- package/dist/core/channels.d.ts.map +1 -0
- package/dist/core/channels.js +19 -0
- package/dist/core/channels.js.map +1 -0
- package/dist/core/detail.d.ts +18 -0
- package/dist/core/detail.d.ts.map +1 -0
- package/dist/core/detail.js +20 -0
- package/dist/core/detail.js.map +1 -0
- package/dist/core/filter.d.ts +34 -0
- package/dist/core/filter.d.ts.map +1 -0
- package/dist/core/filter.js +99 -0
- package/dist/core/filter.js.map +1 -0
- package/dist/core/refine.d.ts +14 -0
- package/dist/core/refine.d.ts.map +1 -0
- package/dist/core/refine.js +20 -0
- package/dist/core/refine.js.map +1 -0
- package/dist/{resident.d.ts → core/resident.d.ts} +8 -8
- package/dist/core/resident.d.ts.map +1 -0
- package/dist/core/resident.js +44 -0
- package/dist/core/resident.js.map +1 -0
- package/dist/core/scheduler.d.ts +42 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js +77 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/state.d.ts +132 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/store.d.ts +6 -0
- package/dist/core/store.d.ts.map +1 -0
- package/dist/core/store.js +235 -0
- package/dist/core/store.js.map +1 -0
- package/dist/core/tile-matrix.d.ts +37 -0
- package/dist/core/tile-matrix.d.ts.map +1 -0
- package/dist/core/tile-matrix.js +49 -0
- package/dist/core/tile-matrix.js.map +1 -0
- package/dist/core/tile.d.ts +54 -0
- package/dist/core/tile.d.ts.map +1 -0
- package/dist/core/tile.js +76 -0
- package/dist/core/tile.js.map +1 -0
- package/dist/core/tileset.d.ts +59 -0
- package/dist/core/tileset.d.ts.map +1 -0
- package/dist/core/tileset.js +177 -0
- package/dist/core/tileset.js.map +1 -0
- package/dist/{types.d.ts → core/types.d.ts} +9 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/index.d.ts +37 -70
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +32 -34
- package/dist/index.js.map +1 -1
- package/dist/{use-graph-selection.d.ts → parts/gesture.d.ts} +4 -4
- package/dist/parts/gesture.d.ts.map +1 -0
- package/dist/{use-graph-selection.js → parts/gesture.js} +17 -17
- package/dist/parts/gesture.js.map +1 -0
- package/dist/parts/graph-canvas.d.ts +17 -0
- package/dist/parts/graph-canvas.d.ts.map +1 -0
- package/dist/parts/graph-canvas.js +174 -0
- package/dist/parts/graph-canvas.js.map +1 -0
- package/dist/parts/graph-inspector.d.ts +18 -0
- package/dist/parts/graph-inspector.d.ts.map +1 -0
- package/dist/parts/graph-inspector.js +84 -0
- package/dist/parts/graph-inspector.js.map +1 -0
- package/dist/parts/graph-legend.d.ts +12 -0
- package/dist/parts/graph-legend.d.ts.map +1 -0
- package/dist/parts/graph-legend.js +61 -0
- package/dist/parts/graph-legend.js.map +1 -0
- package/dist/parts/graph-toolbar.d.ts +15 -0
- package/dist/parts/graph-toolbar.d.ts.map +1 -0
- package/dist/parts/graph-toolbar.js +94 -0
- package/dist/parts/graph-toolbar.js.map +1 -0
- package/dist/parts/overlays.d.ts +33 -0
- package/dist/parts/overlays.d.ts.map +1 -0
- package/dist/{use-graph-overlays.js → parts/overlays.js} +8 -8
- package/dist/parts/overlays.js.map +1 -0
- package/dist/{shape-glyph.d.ts → parts/shape-glyph.d.ts} +1 -1
- package/dist/parts/shape-glyph.d.ts.map +1 -0
- package/dist/{shape-glyph.js → parts/shape-glyph.js} +1 -1
- package/dist/parts/shape-glyph.js.map +1 -0
- package/dist/react/graph-root.d.ts +15 -0
- package/dist/react/graph-root.d.ts.map +1 -0
- package/dist/react/graph-root.js +23 -0
- package/dist/react/graph-root.js.map +1 -0
- package/dist/{use-graph-prefs.d.ts → react/use-graph-prefs.d.ts} +2 -2
- package/dist/react/use-graph-prefs.d.ts.map +1 -0
- package/dist/{use-graph-prefs.js → react/use-graph-prefs.js} +3 -3
- package/dist/react/use-graph-prefs.js.map +1 -0
- package/dist/react/use-graph-state.d.ts +11 -0
- package/dist/react/use-graph-state.d.ts.map +1 -0
- package/dist/react/use-graph-state.js +16 -0
- package/dist/react/use-graph-state.js.map +1 -0
- package/dist/react/use-graph.d.ts +38 -0
- package/dist/react/use-graph.d.ts.map +1 -0
- package/dist/react/use-graph.js +87 -0
- package/dist/react/use-graph.js.map +1 -0
- package/dist/{adaptive.d.ts → render/adaptive.d.ts} +1 -1
- package/dist/render/adaptive.d.ts.map +1 -0
- package/dist/render/adaptive.js.map +1 -0
- package/dist/render/compose.d.ts +51 -0
- package/dist/render/compose.d.ts.map +1 -0
- package/dist/render/compose.js +107 -0
- package/dist/render/compose.js.map +1 -0
- package/dist/render/css-color.d.ts.map +1 -0
- package/dist/render/css-color.js.map +1 -0
- package/dist/render/encode.d.ts +42 -0
- package/dist/render/encode.d.ts.map +1 -0
- package/dist/render/encode.js +68 -0
- package/dist/render/encode.js.map +1 -0
- package/dist/render/graph-looks.d.ts.map +1 -0
- package/dist/render/graph-looks.js.map +1 -0
- package/dist/render/graph-model.d.ts +44 -0
- package/dist/render/graph-model.d.ts.map +1 -0
- package/dist/render/graph-model.js +80 -0
- package/dist/render/graph-model.js.map +1 -0
- package/dist/{graph-sim.d.ts → render/graph-sim.d.ts} +2 -2
- package/dist/render/graph-sim.d.ts.map +1 -0
- package/dist/render/graph-sim.js.map +1 -0
- package/dist/{obligations.d.ts → render/obligations.d.ts} +1 -1
- package/dist/render/obligations.d.ts.map +1 -0
- package/dist/render/renderer.d.ts +38 -0
- package/dist/render/renderer.d.ts.map +1 -0
- package/dist/render/renderer.js +235 -0
- package/dist/render/renderer.js.map +1 -0
- package/dist/render/webgl.d.ts +14 -0
- package/dist/render/webgl.d.ts.map +1 -0
- package/dist/render/webgl.js +19 -0
- package/dist/render/webgl.js.map +1 -0
- package/dist/render/when-ready.d.ts.map +1 -0
- package/dist/render/when-ready.js.map +1 -0
- package/package.json +11 -21
- package/dist/adaptive.d.ts.map +0 -1
- package/dist/adaptive.js.map +0 -1
- package/dist/bounded.d.ts +0 -364
- package/dist/bounded.d.ts.map +0 -1
- package/dist/bounded.js +0 -18
- package/dist/bounded.js.map +0 -1
- package/dist/cluster-ring.d.ts +0 -25
- package/dist/cluster-ring.d.ts.map +0 -1
- package/dist/cluster-ring.js +0 -16
- package/dist/cluster-ring.js.map +0 -1
- package/dist/css-color.d.ts.map +0 -1
- package/dist/css-color.js.map +0 -1
- package/dist/duck-source.d.ts +0 -198
- package/dist/duck-source.d.ts.map +0 -1
- package/dist/duck-source.js +0 -320
- package/dist/duck-source.js.map +0 -1
- package/dist/graph-canvas.d.ts +0 -50
- package/dist/graph-canvas.d.ts.map +0 -1
- package/dist/graph-canvas.js +0 -35
- package/dist/graph-canvas.js.map +0 -1
- package/dist/graph-looks.d.ts.map +0 -1
- package/dist/graph-looks.js.map +0 -1
- package/dist/graph-model.d.ts +0 -130
- package/dist/graph-model.d.ts.map +0 -1
- package/dist/graph-model.js +0 -104
- package/dist/graph-model.js.map +0 -1
- package/dist/graph-sim.d.ts.map +0 -1
- package/dist/graph-sim.js.map +0 -1
- package/dist/obligations.d.ts.map +0 -1
- package/dist/resident.d.ts.map +0 -1
- package/dist/resident.js +0 -44
- package/dist/resident.js.map +0 -1
- package/dist/shape-glyph.d.ts.map +0 -1
- package/dist/shape-glyph.js.map +0 -1
- package/dist/slice-client.d.ts +0 -78
- package/dist/slice-client.d.ts.map +0 -1
- package/dist/slice-client.js +0 -98
- package/dist/slice-client.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/use-graph-look.d.ts +0 -28
- package/dist/use-graph-look.d.ts.map +0 -1
- package/dist/use-graph-look.js +0 -28
- package/dist/use-graph-look.js.map +0 -1
- package/dist/use-graph-overlays.d.ts +0 -44
- package/dist/use-graph-overlays.d.ts.map +0 -1
- package/dist/use-graph-overlays.js.map +0 -1
- package/dist/use-graph-prefs.d.ts.map +0 -1
- package/dist/use-graph-prefs.js.map +0 -1
- package/dist/use-graph-selection.d.ts.map +0 -1
- package/dist/use-graph-selection.js.map +0 -1
- package/dist/use-graph.d.ts +0 -203
- package/dist/use-graph.d.ts.map +0 -1
- package/dist/use-graph.js +0 -102
- package/dist/use-graph.js.map +0 -1
- package/dist/use-query-loop.d.ts +0 -88
- package/dist/use-query-loop.d.ts.map +0 -1
- package/dist/use-query-loop.js +0 -148
- package/dist/use-query-loop.js.map +0 -1
- package/dist/use-renderer.d.ts +0 -86
- package/dist/use-renderer.d.ts.map +0 -1
- package/dist/use-renderer.js +0 -188
- package/dist/use-renderer.js.map +0 -1
- package/dist/when-ready.d.ts.map +0 -1
- package/dist/when-ready.js.map +0 -1
- /package/dist/{adaptive.js → render/adaptive.js} +0 -0
- /package/dist/{css-color.d.ts → render/css-color.d.ts} +0 -0
- /package/dist/{css-color.js → render/css-color.js} +0 -0
- /package/dist/{graph-looks.d.ts → render/graph-looks.d.ts} +0 -0
- /package/dist/{graph-looks.js → render/graph-looks.js} +0 -0
- /package/dist/{graph-sim.js → render/graph-sim.js} +0 -0
- /package/dist/{when-ready.d.ts → render/when-ready.d.ts} +0 -0
- /package/dist/{when-ready.js → render/when-ready.js} +0 -0
package/README.md
CHANGED
|
@@ -1,116 +1,81 @@
|
|
|
1
1
|
# @kanzo-tech/graph
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## What it is not
|
|
8
|
-
|
|
9
|
-
**There is no `<GraphCanvas>`.** That is the shape of the package rather than a gap in it. A graph
|
|
10
|
-
canvas is a toolbar, a legend, an inspector, a hover card and a search box wired to one renderer,
|
|
11
|
-
and every one of those answers differently per product. What is genuinely shared sits underneath —
|
|
12
|
-
reading a relation into typed arrays, turning a look and the live theme into GPU buffers, owning the
|
|
13
|
-
renderer across React's lifecycle, and keeping a lasso inside a Mosaic crossfilter. Those are here.
|
|
14
|
-
The arrangement belongs at the call site; `docs/showcases/workspace/graph-canvas.tsx` is one, and it
|
|
15
|
-
is not the only possible one.
|
|
16
|
-
|
|
17
|
-
## Why a package, and not part of `@kanzo-tech/ui`
|
|
18
|
-
|
|
19
|
-
The [first admission rule](/docs/philosophy#admission) is *domain-free — nothing about RDF / SHACL / fossil / **graphs**
|
|
20
|
-
/ auth*. Graphs are excluded by name, deliberately: `ui` is the generic vocabulary every product
|
|
21
|
-
shares. A sibling package is also the only honest home for a **required** WebGL peer — as an
|
|
22
|
-
optional peer of `ui` it would have been a lie about what the package is.
|
|
3
|
+
The graph view over a [fossil](https://github.com/kanzo-tech/fossil) corpus, drawn with
|
|
4
|
+
[cosmos.gl](https://cosmosgl.github.io/graph). fossil is the backend and this package is the view:
|
|
5
|
+
the host opens the corpus, and `GraphRoot` draws it by tile — no SQL is written here.
|
|
23
6
|
|
|
24
7
|
## Install
|
|
25
8
|
|
|
26
9
|
```sh
|
|
27
|
-
pnpm add @kanzo-tech/graph @cosmos.gl/graph
|
|
10
|
+
pnpm add @kanzo-tech/graph @cosmos.gl/graph @fossil-lang/corpus @kanzo-tech/mosaic @kanzo-tech/ui lucide-react @uwdata/mosaic-core @uwdata/mosaic-sql
|
|
28
11
|
```
|
|
29
12
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
**So the root barrel draws nothing, and that is the shape rather than an oversight.** The reason for
|
|
35
|
-
the split used to be *a host drawing arrays it already has should not pay for a database*, and that
|
|
36
|
-
host no longer exists here: `memorySource` is deleted and this package sends **one** source, the
|
|
37
|
-
corpus'. What the split protects now is a barrel that is a rendering surface — hooks, looks,
|
|
38
|
-
identity, the buffers a slice implies — for a host whose slices arrive from somewhere else, its own
|
|
39
|
-
`BoundedSource` included. A picture costs `@kanzo-tech/graph/duckdb`.
|
|
13
|
+
Every peer is required. `@fossil-lang/corpus` reads the corpus, `@kanzo-tech/mosaic` is the page's one
|
|
14
|
+
DuckDB-WASM engine and its crossfilter, cosmos.gl draws, and the parts are built from
|
|
15
|
+
`@kanzo-tech/ui` and its icons.
|
|
40
16
|
|
|
41
|
-
## The
|
|
17
|
+
## The one path
|
|
42
18
|
|
|
43
|
-
|
|
44
|
-
The answer is a `Slice`: at most `limit` points as parallel typed arrays, whose size follows the
|
|
45
|
-
question rather than the corpus. Moving the camera re-asks, and a window holding more than `limit`
|
|
46
|
-
is **sampled** rather than truncated — one row every `ceil(matched / limit)` over the corpus'
|
|
47
|
-
Morton-ordered `dense_id`, which spreads the marks over the window instead of drawing a corner of
|
|
48
|
-
it. So a view of everything is still a few thousand marks, and they are still everywhere.
|
|
49
|
-
|
|
50
|
-
`openCorpus` — on `@kanzo-tech/graph/duckdb`, because that is the half that needs Mosaic and
|
|
51
|
-
fossil's reader — takes the corpus the host opened with fossil's `open` and the page's `engine()`,
|
|
52
|
-
and hands back both halves: the source the canvas draws from, and the names fossil's verbs query
|
|
53
|
-
the relations by, for the charts and the crossfilter.
|
|
54
|
-
|
|
55
|
-
```ts
|
|
19
|
+
```tsx
|
|
56
20
|
import { open } from "@fossil-lang/corpus";
|
|
57
21
|
import { engine } from "@kanzo-tech/mosaic";
|
|
58
|
-
import {
|
|
22
|
+
import { GraphCanvas, GraphInspector, GraphLegend, GraphRoot, GraphToolbar } from "@kanzo-tech/graph";
|
|
23
|
+
|
|
24
|
+
const corpus = engine().then((e) => open(url, { engine: e }));
|
|
59
25
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
26
|
+
<GraphRoot corpus={corpus} fill="kind" r="degree" title="label" filterBy={crossfilter} onFailure={setFailure}>
|
|
27
|
+
<GraphCanvas>
|
|
28
|
+
<GraphToolbar />
|
|
29
|
+
<GraphLegend />
|
|
30
|
+
</GraphCanvas>
|
|
31
|
+
<GraphInspector />
|
|
32
|
+
</GraphRoot>;
|
|
63
33
|
```
|
|
64
34
|
|
|
65
|
-
Opening is the host's
|
|
66
|
-
`` open(`jobs/${id}`, { engine
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
`
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
used to cost to hold two hundred thousand. What is drawn and transferred follows the window — the
|
|
104
|
-
upload is flat at 23–30 ms and the redraw ceiling stays in the thousands of frames per second. What
|
|
105
|
-
is *scanned* does not: the pan grows from 77 ms at a million to 256 ms at five, and the term that
|
|
106
|
-
grows is the edge join, over one file on a DuckDB-WASM that gets a single thread. That is the next
|
|
107
|
-
thing to fix, and it is the corpus layout, not the renderer.
|
|
35
|
+
**Opening is the host's.** Where the corpus is and what signs it are the host's to say — a private
|
|
36
|
+
corpus opens as `` open(`jobs/${id}`, { engine, host }) `` — and `GraphRoot` takes what came back,
|
|
37
|
+
or the promise of it, which is what lets it say it is opening. Closing it is the host's too.
|
|
38
|
+
|
|
39
|
+
**The channels are Plot's**: `fill`, `symbol`, `r`, `stroke` and `title`, where a CSS colour is a
|
|
40
|
+
constant and anything else is a column. A column binding is a projection: changing one builds a new
|
|
41
|
+
scan and reloads the tiles while keeping the picture.
|
|
42
|
+
|
|
43
|
+
**The camera is addressed.** A tileset in deck.gl's `Tileset2D` shape culls the tile matrix fossil
|
|
44
|
+
published, picks the finest zoom whose tiles in view hold at most `limit` rows (20,000 by default),
|
|
45
|
+
reads one tile at a time nearest the centre first, cancels what the camera has left, and keeps five
|
|
46
|
+
times what it selected. A far view is a coarser rung of fossil's cell pyramid; an edge is drawn when
|
|
47
|
+
both of its ends are in tiles already read.
|
|
48
|
+
|
|
49
|
+
**`filterBy` is the page's crossfilter.** Its clauses are translated into scan's filter, so the
|
|
50
|
+
canvas draws what survives; a clause that cannot be translated reaches `onFailure` rather than being
|
|
51
|
+
dropped. A lasso or a click publishes the reader's pick back into it, exempting the graph itself.
|
|
52
|
+
|
|
53
|
+
## The pieces
|
|
54
|
+
|
|
55
|
+
- `GraphRoot` — `useGraph` plus the context. `GraphRootProvider` takes an api a host built with
|
|
56
|
+
`useGraph`; `useGraphContext` reads it — Ark's four, one for one. The api is the commands and
|
|
57
|
+
never changes; `useGraphState(selector)` reads a slice of the state.
|
|
58
|
+
- `GraphCanvas` — the element, the grid, the vignette, the labels, the hover card and the marquee
|
|
59
|
+
and lasso gesture. Children are chrome positioned over it.
|
|
60
|
+
- `GraphLegend`, `GraphToolbar`, `GraphInspector` — the categorical scale with its tally, the
|
|
61
|
+
commands drawn, and the focused vertex's row with a render prop for a product's own fields. No
|
|
62
|
+
part takes a callback: what a click means is `onSelect`, `onFocus` and `onFailure` on the root.
|
|
63
|
+
- `lookFrom`, `simFrom`, `useGraphPrefs` — the form and the forces from a preferences panel's
|
|
64
|
+
answers; `scaleOf` — what colour and shape a category wears; `adaptive` — simulation tuning by size.
|
|
65
|
+
- `vertexId`, `typeOf`, `denseOf` — a vertex is `(type_idx, dense_id)` packed into a `bigint`, and
|
|
66
|
+
everything that outlives one composition is held as one.
|
|
67
|
+
|
|
68
|
+
## Why a package, and not part of `@kanzo-tech/ui`
|
|
69
|
+
|
|
70
|
+
The [first admission rule](https://kanzo-tech.github.io/ui/docs/philosophy#admission) is
|
|
71
|
+
*domain-free — nothing about RDF / SHACL / fossil / **graphs** / auth*. Graphs are excluded by name,
|
|
72
|
+
and a sibling package is the only honest home for a required WebGL peer.
|
|
108
73
|
|
|
109
74
|
## Gotchas the source will not tell you twice
|
|
110
75
|
|
|
111
76
|
- **`setConfig` resets everything.** cosmos.gl 3.x resets the whole configuration to defaults and
|
|
112
77
|
then applies the argument. Use `setConfigPartial`. This typechecks either way.
|
|
113
78
|
- **`getConnectedLinkIndices` is not a neighbourhood.** It returns only links whose *other* endpoint
|
|
114
|
-
is also in the argument
|
|
115
|
-
- **`requestAnimationFrame` never fires in a hidden tab**, and
|
|
116
|
-
|
|
79
|
+
is also in the argument. `getNeighboringPointIndices` is the neighbourhood.
|
|
80
|
+
- **`requestAnimationFrame` never fires in a hidden tab**, and the renderer draws on animation
|
|
81
|
+
frames. A backgrounded graph is stopped, not slow.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Corpus } from '@fossil-lang/corpus';
|
|
2
|
+
import { Binding } from './channels';
|
|
3
|
+
/**
|
|
4
|
+
* **The categorical domain, fixed before a tile arrives.** A column the manifest's `channels:`
|
|
5
|
+
* declares as categorical ranks by its own ordinal, `0` to `domain − 1`; otherwise the host's
|
|
6
|
+
* `categories` keys are the order. Only a value neither names is ranked as it is seen, after them —
|
|
7
|
+
* which is what a legend whose colours moved as tiles arrived was doing for every value.
|
|
8
|
+
*/
|
|
9
|
+
export declare function domainOf(corpus: Corpus | null, typeIndex: number, binding: Binding, categories: Readonly<Record<string, string>> | undefined): readonly unknown[];
|
|
10
|
+
/** What a legend, a card or an inspector calls a category value. */
|
|
11
|
+
export declare const nameOf: (value: unknown, categories: Readonly<Record<string, string>> | undefined) => string;
|
|
12
|
+
//# sourceMappingURL=categories.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.d.ts","sourceRoot":"","sources":["../../src/core/categories.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,OAAO,EAChB,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GACvD,SAAS,OAAO,EAAE,CAOpB;AAED,oEAAoE;AACpE,eAAO,MAAM,MAAM,GAAI,OAAO,OAAO,EAAE,YAAY,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,KAAG,MAC7C,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function a(n, t, i, r) {
|
|
2
|
+
var o;
|
|
3
|
+
if (i.category === void 0) return [];
|
|
4
|
+
const f = (o = n == null ? void 0 : n.types.vertices[t]) == null ? void 0 : o.channels.find(
|
|
5
|
+
(m) => m.column === i.category && m.scale === "categorical" && m.domain !== null
|
|
6
|
+
);
|
|
7
|
+
return f != null && f.domain ? Array.from({ length: f.domain }, (m, y) => y) : r ? Object.keys(r) : [];
|
|
8
|
+
}
|
|
9
|
+
const d = (n, t) => (t == null ? void 0 : t[String(n)]) ?? String(n ?? "—");
|
|
10
|
+
export {
|
|
11
|
+
a as domainOf,
|
|
12
|
+
d as nameOf
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=categories.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"categories.js","sources":["../../src/core/categories.ts"],"sourcesContent":["import type { Corpus } from \"@fossil-lang/corpus\";\nimport type { Binding } from \"./channels\";\n\n/**\n * **The categorical domain, fixed before a tile arrives.** A column the manifest's `channels:`\n * declares as categorical ranks by its own ordinal, `0` to `domain − 1`; otherwise the host's\n * `categories` keys are the order. Only a value neither names is ranked as it is seen, after them —\n * which is what a legend whose colours moved as tiles arrived was doing for every value.\n */\nexport function domainOf(\n corpus: Corpus | null,\n typeIndex: number,\n binding: Binding,\n categories: Readonly<Record<string, string>> | undefined,\n): readonly unknown[] {\n if (binding.category === undefined) return [];\n const declared = corpus?.types.vertices[typeIndex]?.channels.find(\n (channel) => channel.column === binding.category && channel.scale === \"categorical\" && channel.domain !== null,\n );\n if (declared?.domain) return Array.from({ length: declared.domain }, (_, ordinal) => ordinal);\n return categories ? Object.keys(categories) : [];\n}\n\n/** What a legend, a card or an inspector calls a category value. */\nexport const nameOf = (value: unknown, categories: Readonly<Record<string, string>> | undefined): string =>\n categories?.[String(value)] ?? String(value ?? \"—\");\n"],"names":["domainOf","corpus","typeIndex","binding","categories","_a","declared","channel","_","ordinal","nameOf","value"],"mappings":"AASO,SAASA,EACdC,GACAC,GACAC,GACAC,GACoB;AALf,MAAAC;AAML,MAAIF,EAAQ,aAAa,OAAW,QAAO,CAAA;AAC3C,QAAMG,KAAWD,IAAAJ,KAAA,gBAAAA,EAAQ,MAAM,SAASC,OAAvB,gBAAAG,EAAmC,SAAS;AAAA,IAC3D,CAACE,MAAYA,EAAQ,WAAWJ,EAAQ,YAAYI,EAAQ,UAAU,iBAAiBA,EAAQ,WAAW;AAAA;AAE5G,SAAID,KAAA,QAAAA,EAAU,SAAe,MAAM,KAAK,EAAE,QAAQA,EAAS,OAAA,GAAU,CAACE,GAAGC,MAAYA,CAAO,IACrFL,IAAa,OAAO,KAAKA,CAAU,IAAI,CAAA;AAChD;AAGO,MAAMM,IAAS,CAACC,GAAgBP,OACrCA,KAAA,gBAAAA,EAAa,OAAOO,CAAK,OAAM,OAAOA,KAAS,GAAG;"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What each channel is bound to — Plot's names, and Plot's rule that **a CSS colour is a constant
|
|
3
|
+
* and anything else is a column.** `fill="kind"` spends colour on a category; `fill="var(--foreground)"`
|
|
4
|
+
* paints every point one ink and leaves colour free to mean the selection.
|
|
5
|
+
*/
|
|
6
|
+
export interface Channels {
|
|
7
|
+
/** Which column colours a point, or a CSS colour every point wears. */
|
|
8
|
+
fill?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Which column a point's shape carries. A tile carries one categorical column, so bound beside a
|
|
11
|
+
* `fill` column this reads the same one; a second would need a second array everywhere.
|
|
12
|
+
*/
|
|
13
|
+
symbol?: string;
|
|
14
|
+
/** What tints a link. Absent, a link takes the colour of the vertex it leaves. */
|
|
15
|
+
stroke?: string;
|
|
16
|
+
}
|
|
17
|
+
/** Narrow on purpose — `var(…)`, a hex, a colour function — so a bare word is always a column. */
|
|
18
|
+
export declare function isColour(value: string | undefined): value is string;
|
|
19
|
+
/** The columns a binding reads, which is what a scan projects. */
|
|
20
|
+
export interface Binding {
|
|
21
|
+
/** The one categorical column: `fill` when it names one, `symbol` when `fill` is a constant. */
|
|
22
|
+
readonly category: string | undefined;
|
|
23
|
+
/** What the size ramp is spent on — Plot's `r`. */
|
|
24
|
+
readonly size: string | undefined;
|
|
25
|
+
/** The text a label and the hover card show — Plot's `title`. */
|
|
26
|
+
readonly title: string | undefined;
|
|
27
|
+
}
|
|
28
|
+
export declare function bindingOf(options: Channels & {
|
|
29
|
+
r?: string;
|
|
30
|
+
title?: string;
|
|
31
|
+
}): Binding;
|
|
32
|
+
/** A binding is a projection: `fill`, `r` and `title` as columns become the scan's `select`. */
|
|
33
|
+
export declare function projectionOf(binding: Binding, fixed: readonly string[]): string[];
|
|
34
|
+
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/core/channels.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,IAAI,MAAM,CAEnE;AAED,kEAAkE;AAClE,MAAM,WAAW,OAAO;IACtB,gGAAgG;IAChG,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,QAAQ,GAAG;IAAE,CAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAMrF;AAED,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAEjF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
function l(r) {
|
|
2
|
+
return r !== void 0 && /^(var\(|#|rgb|hsl|oklch|oklab|lab|lch|color\()/i.test(r);
|
|
3
|
+
}
|
|
4
|
+
function i(r) {
|
|
5
|
+
return {
|
|
6
|
+
category: l(r.fill) ? r.symbol : r.fill,
|
|
7
|
+
size: r.r,
|
|
8
|
+
title: r.title
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
function c(r, t) {
|
|
12
|
+
return [...new Set([...t, r.category, r.size, r.title].filter((e) => e !== void 0))];
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
i as bindingOf,
|
|
16
|
+
l as isColour,
|
|
17
|
+
c as projectionOf
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=channels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels.js","sources":["../../src/core/channels.ts"],"sourcesContent":["/**\n * What each channel is bound to — Plot's names, and Plot's rule that **a CSS colour is a constant\n * and anything else is a column.** `fill=\"kind\"` spends colour on a category; `fill=\"var(--foreground)\"`\n * paints every point one ink and leaves colour free to mean the selection.\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. A tile carries one categorical column, so bound beside a\n * `fill` column this reads the same one; a second would need a second array everywhere.\n */\n symbol?: string;\n /** What tints a link. Absent, a link takes the colour of the vertex it leaves. */\n stroke?: string;\n}\n\n/** Narrow on purpose — `var(…)`, a hex, a colour function — so a bare word is always a column. */\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/** The columns a binding reads, which is what a scan projects. */\nexport interface Binding {\n /** The one categorical column: `fill` when it names one, `symbol` when `fill` is a constant. */\n readonly category: string | undefined;\n /** What the size ramp is spent on — Plot's `r`. */\n readonly size: string | undefined;\n /** The text a label and the hover card show — Plot's `title`. */\n readonly title: string | undefined;\n}\n\nexport function bindingOf(options: Channels & { r?: string; title?: string }): Binding {\n return {\n category: isColour(options.fill) ? options.symbol : options.fill,\n size: options.r,\n title: options.title,\n };\n}\n\n/** A binding is a projection: `fill`, `r` and `title` as columns become the scan's `select`. */\nexport function projectionOf(binding: Binding, fixed: readonly string[]): string[] {\n return [...new Set([...fixed, binding.category, binding.size, binding.title].filter((c) => c !== undefined))];\n}\n"],"names":["isColour","value","bindingOf","options","projectionOf","binding","fixed","c"],"mappings":"AAkBO,SAASA,EAASC,GAA4C;AACnE,SAAOA,MAAU,UAAa,kDAAkD,KAAKA,CAAK;AAC5F;AAYO,SAASC,EAAUC,GAA6D;AACrF,SAAO;AAAA,IACL,UAAUH,EAASG,EAAQ,IAAI,IAAIA,EAAQ,SAASA,EAAQ;AAAA,IAC5D,MAAMA,EAAQ;AAAA,IACd,OAAOA,EAAQ;AAAA,EAAA;AAEnB;AAGO,SAASC,EAAaC,GAAkBC,GAAoC;AACjF,SAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAGA,GAAOD,EAAQ,UAAUA,EAAQ,MAAMA,EAAQ,KAAK,EAAE,OAAO,CAACE,MAAMA,MAAM,MAAS,CAAC,CAAC;AAC9G;"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Corpus, TileMatrixSet } from '@fossil-lang/corpus';
|
|
2
|
+
import { VertexId } from './resident';
|
|
3
|
+
/** One vertex's row, as its type's fields order it — every column but the address and the position. */
|
|
4
|
+
export interface VertexDetail {
|
|
5
|
+
readonly vertex: VertexId;
|
|
6
|
+
readonly fields: readonly {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly value: unknown;
|
|
9
|
+
}[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* **Detail is fetched, not carried** — ADR 0001. A tile holds what the channels project; the rest of a
|
|
13
|
+
* row is asked for when a reader focuses the vertex, as a scan of the one payload tile its `dense_id`
|
|
14
|
+
* falls in, filtered to it. `corpus.node` takes an identity, and a tile carries an address, so the
|
|
15
|
+
* address is what asks.
|
|
16
|
+
*/
|
|
17
|
+
export declare function readVertex(corpus: Corpus, matrix: TileMatrixSet, vertex: VertexId, signal?: AbortSignal): Promise<VertexDetail | null>;
|
|
18
|
+
//# sourceMappingURL=detail.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detail.d.ts","sourceRoot":"","sources":["../../src/core/detail.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,MAAM,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC5G,OAAO,EAAW,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGpD,uGAAuG;AACvG,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;CAChF;AAKD;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,QAAQ,EAChB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAa9B"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { PAYLOAD_ADDRESS as u, PAYLOAD_COORDINATES as m } from "@fossil-lang/corpus";
|
|
2
|
+
import { denseOf as y } from "./resident.js";
|
|
3
|
+
import { tileOfDense as D } from "./tile-matrix.js";
|
|
4
|
+
const s = u[0], A = /* @__PURE__ */ new Set([s, ...m]);
|
|
5
|
+
async function S(o, t, r, p) {
|
|
6
|
+
const l = y(r), c = D(t, l), a = o.types.vertices.find((e) => e.type === t.type);
|
|
7
|
+
if (!c || !a) return null;
|
|
8
|
+
const f = a.fields.map((e) => e.name).filter((e) => !A.has(e)), d = o.scan({ type: t.type, filter: { column: s, op: "=", value: l }, select: [s, ...f] }), [n] = await d.read([c], { signal: p });
|
|
9
|
+
return !n || n.numRows === 0 ? null : {
|
|
10
|
+
vertex: r,
|
|
11
|
+
fields: f.map((e) => {
|
|
12
|
+
var i;
|
|
13
|
+
return { name: e, value: ((i = n.getChild(e)) == null ? void 0 : i.toArray()[0]) ?? null };
|
|
14
|
+
})
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
S as readVertex
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=detail.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detail.js","sources":["../../src/core/detail.ts"],"sourcesContent":["import { PAYLOAD_ADDRESS, PAYLOAD_COORDINATES, type Corpus, type TileMatrixSet } from \"@fossil-lang/corpus\";\nimport { denseOf, type VertexId } from \"./resident\";\nimport { tileOfDense } from \"./tile-matrix\";\n\n/** One vertex's row, as its type's fields order it — every column but the address and the position. */\nexport interface VertexDetail {\n readonly vertex: VertexId;\n readonly fields: readonly { readonly name: string; readonly value: unknown }[];\n}\n\nconst KEY = PAYLOAD_ADDRESS[0] as string;\nconst HIDDEN = new Set<string>([KEY, ...PAYLOAD_COORDINATES]);\n\n/**\n * **Detail is fetched, not carried** — ADR 0001. A tile holds what the channels project; the rest of a\n * row is asked for when a reader focuses the vertex, as a scan of the one payload tile its `dense_id`\n * falls in, filtered to it. `corpus.node` takes an identity, and a tile carries an address, so the\n * address is what asks.\n */\nexport async function readVertex(\n corpus: Corpus,\n matrix: TileMatrixSet,\n vertex: VertexId,\n signal?: AbortSignal,\n): Promise<VertexDetail | null> {\n const dense = denseOf(vertex);\n const address = tileOfDense(matrix, dense);\n const type = corpus.types.vertices.find((t) => t.type === matrix.type);\n if (!address || !type) return null;\n const names = type.fields.map((field) => field.name).filter((name) => !HIDDEN.has(name));\n const scan = corpus.scan({ type: matrix.type, filter: { column: KEY, op: \"=\", value: dense }, select: [KEY, ...names] });\n const [rows] = await scan.read([address], { signal });\n if (!rows || rows.numRows === 0) return null;\n return {\n vertex,\n fields: names.map((name) => ({ name, value: rows.getChild(name)?.toArray()[0] ?? null })),\n };\n}\n"],"names":["KEY","PAYLOAD_ADDRESS","HIDDEN","PAYLOAD_COORDINATES","readVertex","corpus","matrix","vertex","signal","dense","denseOf","address","tileOfDense","type","t","names","field","name","scan","rows","_a"],"mappings":";;;AAUA,MAAMA,IAAMC,EAAgB,CAAC,GACvBC,IAAS,oBAAI,IAAY,CAACF,GAAK,GAAGG,CAAmB,CAAC;AAQ5D,eAAsBC,EACpBC,GACAC,GACAC,GACAC,GAC8B;AAC9B,QAAMC,IAAQC,EAAQH,CAAM,GACtBI,IAAUC,EAAYN,GAAQG,CAAK,GACnCI,IAAOR,EAAO,MAAM,SAAS,KAAK,CAACS,MAAMA,EAAE,SAASR,EAAO,IAAI;AACrE,MAAI,CAACK,KAAW,CAACE,EAAM,QAAO;AAC9B,QAAME,IAAQF,EAAK,OAAO,IAAI,CAACG,MAAUA,EAAM,IAAI,EAAE,OAAO,CAACC,MAAS,CAACf,EAAO,IAAIe,CAAI,CAAC,GACjFC,IAAOb,EAAO,KAAK,EAAE,MAAMC,EAAO,MAAM,QAAQ,EAAE,QAAQN,GAAK,IAAI,KAAK,OAAOS,KAAS,QAAQ,CAACT,GAAK,GAAGe,CAAK,GAAG,GACjH,CAACI,CAAI,IAAI,MAAMD,EAAK,KAAK,CAACP,CAAO,GAAG,EAAE,QAAAH,GAAQ;AACpD,SAAI,CAACW,KAAQA,EAAK,YAAY,IAAU,OACjC;AAAA,IACL,QAAAZ;AAAA,IACA,QAAQQ,EAAM,IAAI,CAACE,MAAA;;AAAU,eAAE,MAAAA,GAAM,SAAOG,IAAAD,EAAK,SAASF,CAAI,MAAlB,gBAAAG,EAAqB,UAAU,OAAM;KAAO;AAAA,EAAA;AAE5F;"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Filter } from '@fossil-lang/corpus';
|
|
2
|
+
import { MosaicClient, Selection } from '@kanzo-tech/mosaic';
|
|
3
|
+
/**
|
|
4
|
+
* **The page's crossfilter, as scan's typed filter.** The graph listens to the `Selection` rather
|
|
5
|
+
* than being a client of the coordinator: a client hands the coordinator SQL to run, and the graph
|
|
6
|
+
* has none — it hands fossil a `Filter` and fossil binds it. So this takes the half of Mosaic's
|
|
7
|
+
* protocol that is about filtering: the `value` event, and `selection.predicate(client)`.
|
|
8
|
+
*
|
|
9
|
+
* The nodes are read by their `type`, never by importing mosaic-sql's classes: what arrives is
|
|
10
|
+
* whatever the page's copy of mosaic-sql built.
|
|
11
|
+
*/
|
|
12
|
+
/** A predicate this cannot express as a `Filter` — reported, never dropped. */
|
|
13
|
+
export declare class UntranslatableFilter extends Error {
|
|
14
|
+
readonly name = "UntranslatableFilter";
|
|
15
|
+
}
|
|
16
|
+
/** One mosaic-sql expression node → one `Filter`. */
|
|
17
|
+
export declare function translate(node: unknown): Filter;
|
|
18
|
+
/**
|
|
19
|
+
* The page's filter for the graph, or `undefined` for none. `selection.predicate` skips the clause
|
|
20
|
+
* the graph published itself, which is the exemption the next function takes back.
|
|
21
|
+
*/
|
|
22
|
+
export declare function filterFor(selection: Selection, self: MosaicClient): Filter | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* An identity for `clients`, and nothing more: it is never connected, so the coordinator never
|
|
25
|
+
* queries on its behalf.
|
|
26
|
+
*/
|
|
27
|
+
export declare function graphClient(): MosaicClient;
|
|
28
|
+
/**
|
|
29
|
+
* **The reader's pick, published** — naming the graph in `clients`, so the crossfilter skips it for
|
|
30
|
+
* the graph and applies it to every chart. A canvas that draws only what survives would otherwise
|
|
31
|
+
* answer a lasso of thirteen by removing the other 1,530.
|
|
32
|
+
*/
|
|
33
|
+
export declare function publish(selection: Selection, self: MosaicClient, column: string, dense: readonly number[] | null): void;
|
|
34
|
+
//# sourceMappingURL=filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.d.ts","sourceRoot":"","sources":["../../src/core/filter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAW,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAgB,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEhF;;;;;;;;GAQG;AAEH,+EAA+E;AAC/E,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,SAAkB,IAAI,0BAA0B;CACjD;AAoDD,qDAAqD;AACrD,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAyC/C;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,MAAM,GAAG,SAAS,CAItF;AAED;;;GAGG;AACH,wBAAgB,WAAW,IAAI,YAAY,CAE1C;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CACrB,SAAS,EAAE,SAAS,EACpB,IAAI,EAAE,YAAY,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,GAC9B,IAAI,CAON"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
var f = Object.defineProperty;
|
|
2
|
+
var h = (r, t, e) => t in r ? f(r, t, { enumerable: !0, configurable: !0, writable: !0, value: e }) : r[t] = e;
|
|
3
|
+
var p = (r, t, e) => h(r, typeof t != "symbol" ? t + "" : t, e);
|
|
4
|
+
import { MosaicClient as y, clausePoints as O } from "@kanzo-tech/mosaic";
|
|
5
|
+
class m extends Error {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
p(this, "name", "UntranslatableFilter");
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
const A = {
|
|
12
|
+
"=": "=",
|
|
13
|
+
"==": "=",
|
|
14
|
+
"IS NOT DISTINCT FROM": "=",
|
|
15
|
+
"<>": "!=",
|
|
16
|
+
"!=": "!=",
|
|
17
|
+
"<": "<",
|
|
18
|
+
"<=": "<=",
|
|
19
|
+
">": ">",
|
|
20
|
+
">=": ">="
|
|
21
|
+
}, N = { "=": "=", "!=": "!=", "<": ">", "<=": ">=", ">": "<", ">=": "<=" }, s = (r) => {
|
|
22
|
+
throw new m(
|
|
23
|
+
`the graph cannot express this crossfilter clause as a filter on the corpus: ${String(r)}`
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
function o(r) {
|
|
27
|
+
const t = r;
|
|
28
|
+
return (t == null ? void 0 : t.type) === "COLUMN_REF" && typeof t.name == "string" ? t.name : null;
|
|
29
|
+
}
|
|
30
|
+
function i(r) {
|
|
31
|
+
const t = r, e = (t == null ? void 0 : t.type) === "LITERAL" || (t == null ? void 0 : t.type) === "PARAM" ? t.value : s(r);
|
|
32
|
+
if (typeof e == "number" || typeof e == "bigint" || typeof e == "string" || typeof e == "boolean")
|
|
33
|
+
return e;
|
|
34
|
+
if (e instanceof Date) {
|
|
35
|
+
const n = e.toISOString();
|
|
36
|
+
return n.endsWith("T00:00:00.000Z") ? n.slice(0, 10) : n.replace("T", " ").replace("Z", "");
|
|
37
|
+
}
|
|
38
|
+
return s(r);
|
|
39
|
+
}
|
|
40
|
+
function g(r) {
|
|
41
|
+
const t = r;
|
|
42
|
+
return (Array.isArray(r) ? r : Array.isArray(t == null ? void 0 : t.values) ? t.values : s(r)).map(i);
|
|
43
|
+
}
|
|
44
|
+
function l(r) {
|
|
45
|
+
const t = r;
|
|
46
|
+
if (Array.isArray(r)) return c(r.map(l));
|
|
47
|
+
switch (t == null ? void 0 : t.type) {
|
|
48
|
+
case "LOGICAL_OPERATOR": {
|
|
49
|
+
const e = (t.clauses ?? []).map(l);
|
|
50
|
+
return t.op === "OR" ? { or: e } : c(e);
|
|
51
|
+
}
|
|
52
|
+
case "UNARY":
|
|
53
|
+
return t.op === "NOT" ? { not: l(t.expr) } : s(r);
|
|
54
|
+
case "UNARY_POSTFIX": {
|
|
55
|
+
const e = o(t.expr) ?? s(r);
|
|
56
|
+
return t.op === "IS NULL" ? { column: e, op: "is null" } : t.op === "IS NOT NULL" ? { column: e, op: "not null" } : s(r);
|
|
57
|
+
}
|
|
58
|
+
case "BINARY": {
|
|
59
|
+
const e = A[String(t.op).toUpperCase()] ?? s(r), n = o(t.left);
|
|
60
|
+
return n !== null ? { column: n, op: e, value: i(t.right) } : { column: o(t.right) ?? s(r), op: N[e], value: i(t.left) };
|
|
61
|
+
}
|
|
62
|
+
case "BETWEEN":
|
|
63
|
+
case "NOT_BETWEEN": {
|
|
64
|
+
const e = o(t.expr) ?? s(r), [n, a] = t.extent ?? s(r), u = c([
|
|
65
|
+
{ column: e, op: ">=", value: i(n) },
|
|
66
|
+
{ column: e, op: "<=", value: i(a) }
|
|
67
|
+
]);
|
|
68
|
+
return t.type === "BETWEEN" ? u : { not: u };
|
|
69
|
+
}
|
|
70
|
+
case "IN":
|
|
71
|
+
return { column: o(t.expr) ?? s(r), op: "in", values: g(t.values) };
|
|
72
|
+
default:
|
|
73
|
+
return s(r);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const c = (r) => r.length === 1 ? r[0] : { and: r };
|
|
77
|
+
function R(r, t) {
|
|
78
|
+
const e = r.predicate(t), n = (Array.isArray(e) ? e : [e]).filter((a) => a != null);
|
|
79
|
+
return n.length === 0 ? void 0 : l(n);
|
|
80
|
+
}
|
|
81
|
+
function T() {
|
|
82
|
+
return new y();
|
|
83
|
+
}
|
|
84
|
+
function I(r, t, e, n) {
|
|
85
|
+
r.update(
|
|
86
|
+
O([e], n && n.length > 0 ? n.map((a) => [a]) : void 0, {
|
|
87
|
+
source: t,
|
|
88
|
+
clients: /* @__PURE__ */ new Set([t])
|
|
89
|
+
})
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
m as UntranslatableFilter,
|
|
94
|
+
R as filterFor,
|
|
95
|
+
T as graphClient,
|
|
96
|
+
I as publish,
|
|
97
|
+
l as translate
|
|
98
|
+
};
|
|
99
|
+
//# sourceMappingURL=filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"filter.js","sources":["../../src/core/filter.ts"],"sourcesContent":["import type { Filter, Literal } from \"@fossil-lang/corpus\";\nimport { MosaicClient, clausePoints, type Selection } from \"@kanzo-tech/mosaic\";\n\n/**\n * **The page's crossfilter, as scan's typed filter.** The graph listens to the `Selection` rather\n * than being a client of the coordinator: a client hands the coordinator SQL to run, and the graph\n * has none — it hands fossil a `Filter` and fossil binds it. So this takes the half of Mosaic's\n * protocol that is about filtering: the `value` event, and `selection.predicate(client)`.\n *\n * The nodes are read by their `type`, never by importing mosaic-sql's classes: what arrives is\n * whatever the page's copy of mosaic-sql built.\n */\n\n/** A predicate this cannot express as a `Filter` — reported, never dropped. */\nexport class UntranslatableFilter extends Error {\n override readonly name = \"UntranslatableFilter\";\n}\n\ninterface Node {\n readonly type?: string;\n readonly op?: string;\n readonly [field: string]: unknown;\n}\n\nconst COMPARISONS: Record<string, \"=\" | \"!=\" | \"<\" | \"<=\" | \">\" | \">=\"> = {\n \"=\": \"=\",\n \"==\": \"=\",\n \"IS NOT DISTINCT FROM\": \"=\",\n \"<>\": \"!=\",\n \"!=\": \"!=\",\n \"<\": \"<\",\n \"<=\": \"<=\",\n \">\": \">\",\n \">=\": \">=\",\n};\nconst MIRRORED = { \"=\": \"=\", \"!=\": \"!=\", \"<\": \">\", \"<=\": \">=\", \">\": \"<\", \">=\": \"<=\" } as const;\n\nconst fail = (what: unknown): never => {\n throw new UntranslatableFilter(\n `the graph cannot express this crossfilter clause as a filter on the corpus: ${String(what)}`,\n );\n};\n\nfunction columnOf(node: unknown): string | null {\n const n = node as Node | null;\n if (n?.type === \"COLUMN_REF\" && typeof n.name === \"string\") return n.name;\n return null;\n}\n\nfunction literalOf(node: unknown): Literal {\n const n = node as Node | null;\n const value = n?.type === \"LITERAL\" || n?.type === \"PARAM\" ? n.value : fail(node);\n if (typeof value === \"number\" || typeof value === \"bigint\" || typeof value === \"string\" || typeof value === \"boolean\") {\n return value;\n }\n if (value instanceof Date) {\n const iso = value.toISOString();\n return iso.endsWith(\"T00:00:00.000Z\") ? iso.slice(0, 10) : iso.replace(\"T\", \" \").replace(\"Z\", \"\");\n }\n return fail(node);\n}\n\nfunction valuesOf(node: unknown): Literal[] {\n const n = node as Node | null;\n const list = Array.isArray(node) ? node : Array.isArray(n?.values) ? n.values : fail(node);\n return (list as unknown[]).map(literalOf);\n}\n\n/** One mosaic-sql expression node → one `Filter`. */\nexport function translate(node: unknown): Filter {\n const n = node as Node | null;\n if (Array.isArray(node)) return and(node.map(translate));\n switch (n?.type) {\n case \"LOGICAL_OPERATOR\": {\n const clauses = ((n.clauses as unknown[] | undefined) ?? []).map(translate);\n return n.op === \"OR\" ? { or: clauses } : and(clauses);\n }\n case \"UNARY\":\n if (n.op === \"NOT\") return { not: translate(n.expr) };\n return fail(node);\n case \"UNARY_POSTFIX\": {\n const column = columnOf(n.expr) ?? fail(node);\n if (n.op === \"IS NULL\") return { column, op: \"is null\" };\n if (n.op === \"IS NOT NULL\") return { column, op: \"not null\" };\n return fail(node);\n }\n case \"BINARY\": {\n const op = COMPARISONS[String(n.op).toUpperCase()] ?? fail(node);\n const left = columnOf(n.left);\n if (left !== null) return { column: left, op, value: literalOf(n.right) };\n const right = columnOf(n.right) ?? fail(node);\n return { column: right, op: MIRRORED[op], value: literalOf(n.left) };\n }\n case \"BETWEEN\":\n case \"NOT_BETWEEN\": {\n const column = columnOf(n.expr) ?? fail(node);\n const [lo, hi] = (n.extent as unknown[] | undefined) ?? fail(node);\n const within: Filter = and([\n { column, op: \">=\", value: literalOf(lo) },\n { column, op: \"<=\", value: literalOf(hi) },\n ]);\n return n.type === \"BETWEEN\" ? within : { not: within };\n }\n case \"IN\": {\n const column = columnOf(n.expr) ?? fail(node);\n return { column, op: \"in\", values: valuesOf(n.values) };\n }\n default:\n return fail(node);\n }\n}\n\nconst and = (clauses: Filter[]): Filter => (clauses.length === 1 ? (clauses[0] as Filter) : { and: clauses });\n\n/**\n * The page's filter for the graph, or `undefined` for none. `selection.predicate` skips the clause\n * the graph published itself, which is the exemption the next function takes back.\n */\nexport function filterFor(selection: Selection, self: MosaicClient): Filter | undefined {\n const predicate = selection.predicate(self) as unknown;\n const clauses = (Array.isArray(predicate) ? predicate : [predicate]).filter((p) => p !== undefined && p !== null);\n return clauses.length === 0 ? undefined : translate(clauses);\n}\n\n/**\n * An identity for `clients`, and nothing more: it is never connected, so the coordinator never\n * queries on its behalf.\n */\nexport function graphClient(): MosaicClient {\n return new MosaicClient();\n}\n\n/**\n * **The reader's pick, published** — naming the graph in `clients`, so the crossfilter skips it for\n * the graph and applies it to every chart. A canvas that draws only what survives would otherwise\n * answer a lasso of thirteen by removing the other 1,530.\n */\nexport function publish(\n selection: Selection,\n self: MosaicClient,\n column: string,\n dense: readonly number[] | null,\n): void {\n selection.update(\n clausePoints([column], dense && dense.length > 0 ? dense.map((d) => [d]) : undefined, {\n source: self,\n clients: new Set([self]),\n }),\n );\n}\n"],"names":["UntranslatableFilter","__publicField","COMPARISONS","MIRRORED","fail","what","columnOf","node","n","literalOf","value","iso","valuesOf","translate","and","clauses","column","op","left","lo","hi","within","filterFor","selection","self","predicate","p","graphClient","MosaicClient","publish","dense","clausePoints","d"],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Tile } from './tile';
|
|
2
|
+
/**
|
|
3
|
+
* deck.gl's `'best-available'` refinement — `updateTileStateDefault`, the only strategy.
|
|
4
|
+
*
|
|
5
|
+
* A selected tile with content is drawn. One without is covered by its nearest ancestor holding
|
|
6
|
+
* content, and failing that by whatever of its descendants holds some, so a pan never shows a hole.
|
|
7
|
+
* A parent is therefore drawn only while a selected child is loading: at rest every selected tile
|
|
8
|
+
* holds content and no stand-in is needed.
|
|
9
|
+
*
|
|
10
|
+
* "Holding content" rather than deck.gl's `isLoaded`, because a tile reloading for a new question
|
|
11
|
+
* keeps its old picture until the new one arrives.
|
|
12
|
+
*/
|
|
13
|
+
export declare function refine(tiles: Iterable<Tile>): void;
|
|
14
|
+
//# sourceMappingURL=refine.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.d.ts","sourceRoot":"","sources":["../../src/core/refine.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEnC;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAOlD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
function f(o) {
|
|
2
|
+
const n = [...o], e = /* @__PURE__ */ new Set();
|
|
3
|
+
for (const t of n)
|
|
4
|
+
t.isSelected && !c(t, e) && i(t, e);
|
|
5
|
+
for (const t of n) t.isVisible = e.has(t);
|
|
6
|
+
}
|
|
7
|
+
function c(o, n) {
|
|
8
|
+
for (let e = o; e; e = e.parent)
|
|
9
|
+
if (e.content)
|
|
10
|
+
return n.add(e), !0;
|
|
11
|
+
return !1;
|
|
12
|
+
}
|
|
13
|
+
function i(o, n) {
|
|
14
|
+
for (const e of o.children)
|
|
15
|
+
e.content ? n.add(e) : i(e, n);
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
f as refine
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=refine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refine.js","sources":["../../src/core/refine.ts"],"sourcesContent":["import type { Tile } from \"./tile\";\n\n/**\n * deck.gl's `'best-available'` refinement — `updateTileStateDefault`, the only strategy.\n *\n * A selected tile with content is drawn. One without is covered by its nearest ancestor holding\n * content, and failing that by whatever of its descendants holds some, so a pan never shows a hole.\n * A parent is therefore drawn only while a selected child is loading: at rest every selected tile\n * holds content and no stand-in is needed.\n *\n * \"Holding content\" rather than deck.gl's `isLoaded`, because a tile reloading for a new question\n * keeps its old picture until the new one arrives.\n */\nexport function refine(tiles: Iterable<Tile>): void {\n const all = [...tiles];\n const visible = new Set<Tile>();\n for (const tile of all) {\n if (tile.isSelected && !inAncestors(tile, visible)) inDescendants(tile, visible);\n }\n for (const tile of all) tile.isVisible = visible.has(tile);\n}\n\nfunction inAncestors(start: Tile, visible: Set<Tile>): boolean {\n for (let tile: Tile | null = start; tile; tile = tile.parent) {\n if (tile.content) {\n visible.add(tile);\n return true;\n }\n }\n return false;\n}\n\nfunction inDescendants(tile: Tile, visible: Set<Tile>): void {\n for (const child of tile.children) {\n if (child.content) visible.add(child);\n else inDescendants(child, visible);\n }\n}\n"],"names":["refine","tiles","all","visible","tile","inAncestors","inDescendants","start","child"],"mappings":"AAaO,SAASA,EAAOC,GAA6B;AAClD,QAAMC,IAAM,CAAC,GAAGD,CAAK,GACfE,wBAAc,IAAA;AACpB,aAAWC,KAAQF;AACjB,IAAIE,EAAK,cAAc,CAACC,EAAYD,GAAMD,CAAO,KAAGG,EAAcF,GAAMD,CAAO;AAEjF,aAAWC,KAAQF,EAAK,CAAAE,EAAK,YAAYD,EAAQ,IAAIC,CAAI;AAC3D;AAEA,SAASC,EAAYE,GAAaJ,GAA6B;AAC7D,WAASC,IAAoBG,GAAOH,GAAMA,IAAOA,EAAK;AACpD,QAAIA,EAAK;AACP,aAAAD,EAAQ,IAAIC,CAAI,GACT;AAGX,SAAO;AACT;AAEA,SAASE,EAAcF,GAAYD,GAA0B;AAC3D,aAAWK,KAASJ,EAAK;AACvB,IAAII,EAAM,UAASL,EAAQ,IAAIK,CAAK,IAC/BF,EAAcE,GAAOL,CAAO;AAErC;"}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { Slice } from './bounded';
|
|
2
1
|
/**
|
|
3
2
|
* Who is drawn, and where the GPU is drawing them.
|
|
4
3
|
*
|
|
@@ -30,7 +29,7 @@ import { Slice } from './bounded';
|
|
|
30
29
|
* where Java and Go both give `1152921504606846977`. JavaScript's `number` is 53 bits and a cell id
|
|
31
30
|
* is 64, and a binding cannot protect a language boundary that cannot hold the value. H3 settled it
|
|
32
31
|
* by decree before anyone could get it wrong: `h3-js` types `H3Index` as a string. This is the same
|
|
33
|
-
* decree with the type JavaScript grew for it.
|
|
32
|
+
* decree with the type JavaScript grew for it.
|
|
34
33
|
*
|
|
35
34
|
* **And `>>` means three different things across our three layers.** In JavaScript it converts its
|
|
36
35
|
* operand to *32 bits* and takes the shift count modulo 32, so the obvious `dense | (type << 32)`
|
|
@@ -52,7 +51,7 @@ export declare function denseOf(vertex: VertexId): number;
|
|
|
52
51
|
*
|
|
53
52
|
* Built once per residency change and never mutated, because that is what a residency change *is*: a
|
|
54
53
|
* different set of vertices, in a different order. It belongs to whoever owns residency — that is
|
|
55
|
-
*
|
|
54
|
+
* the renderer, which composes the buffers — and is read from there by everything else, because a
|
|
56
55
|
* second copy is a second copy that can disagree with the buffers on screen.
|
|
57
56
|
*/
|
|
58
57
|
export interface Resident {
|
|
@@ -68,12 +67,13 @@ export interface Resident {
|
|
|
68
67
|
verticesAt(indices: Iterable<number>): VertexId[];
|
|
69
68
|
}
|
|
70
69
|
/**
|
|
71
|
-
* The map
|
|
70
|
+
* The map a composition implies, over its first `size` slots. A composition puts its vertices
|
|
71
|
+
* first — then the cells, which have no identity, then the far ends drawn only so an edge has one —
|
|
72
|
+
* so nothing hovers, selects or frames a slot past them. Before the first composition nobody is
|
|
73
|
+
* resident, which is not an error.
|
|
72
74
|
*
|
|
73
75
|
* Keyed by the identity itself. `Map` and `Set` compare keys by SameValueZero, which for a `bigint`
|
|
74
|
-
* is *value* equality
|
|
75
|
-
* reach the same entry. That is asserted rather than assumed in `resident.test.ts`, because the
|
|
76
|
-
* whole file rests on it and BigInt being an object-shaped primitive makes it a fair thing to doubt.
|
|
76
|
+
* is *value* equality — asserted in `resident.test.ts`, because the whole file rests on it.
|
|
77
77
|
*/
|
|
78
|
-
export declare function residentOf(
|
|
78
|
+
export declare function residentOf(vertices?: BigUint64Array | null, size?: number): Resident;
|
|
79
79
|
//# sourceMappingURL=resident.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resident.d.ts","sourceRoot":"","sources":["../../src/core/resident.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;GAaG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,MAAM,CAAA;CAAE,CAAC;AAYnE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE9D;AAED,8FAA8F;AAC9F,wBAAgB,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAE/C;AAED,wBAAgB,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,CAEhD;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,QAAQ;IACvB,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,OAAO,CAAC,MAAM,EAAE,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;IAC9C,0FAA0F;IAC1F,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IACxC,+EAA+E;IAC/E,SAAS,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,MAAM,EAAE,CAAC;IAClD,+FAA+F;IAC/F,UAAU,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;CACnD;AAID;;;;;;;;GAQG;AACH,wBAAgB,UAAU,CAAC,QAAQ,GAAE,cAAc,GAAG,IAAa,EAAE,IAAI,SAAwB,GAAG,QAAQ,CA6B3G"}
|