@tangle-network/charts 0.7.0 → 0.9.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 +64 -7
- package/dist/figure.css +96 -2
- package/dist/index.d.ts +39 -4
- package/dist/index.js +732 -377
- package/dist/react/index.d.ts +12 -6
- package/dist/react/index.js +57 -7
- package/dist/react/live.css +20 -1
- package/dist/timeline-BAwebuqb.js +1185 -0
- package/dist/timeline-CNHABOS1.d.ts +293 -0
- package/package.json +1 -1
- package/dist/events-Cw6abvgR.js +0 -491
- package/dist/timeline-BAjzF-wL.d.ts +0 -183
package/README.md
CHANGED
|
@@ -164,36 +164,93 @@ A run page draws recorded events, never inferred ones. Every addition below has
|
|
|
164
164
|
|
|
165
165
|
| Need | Static | React |
|
|
166
166
|
|---|---|---|
|
|
167
|
-
| Vertical events (first pass, deadline, died) and shaded spans (after pass, idle, no data) | `timeSeries(rows, { ..., marks, bands })` | `<Lines marks bands>` |
|
|
167
|
+
| Vertical events (first pass, deadline, died, release, steer, ruling, wake) and shaded spans (after pass, idle, no data, blocked) | `timeSeries(rows, { ..., marks, bands })` | `<Lines marks bands>` |
|
|
168
168
|
| Lanes of spans with marks; an open span runs to `now` | `timeline(lanes, { measure, now, marks })` | `<Gantt lanes now marks>` |
|
|
169
|
+
| An agent tree over time: lanes under their parents, attempt ticks with ok and failed counts, walls across every lane, folding by subtree | `timeline(lanes, { measure, start, now, marks, bands, collapsed })` | `<TimelineView lanes options defaultCollapsed>` |
|
|
169
170
|
| Part of a whole with untraced time hatched | `phaseWaterfall` (unaccounted leaves and the remainder are hatched) | `<Meter total segments>` |
|
|
170
171
|
| One panel per arm on shared axes, with no-data panels and early ends | `smallMultiples(panels, { x, y, shared })` | `<FigureView figure>` |
|
|
171
172
|
| Series that stay distinct without colour | later series add a dash and a marker shape | `series[].dash`, `series[].marker` |
|
|
172
173
|
|
|
173
174
|
```ts
|
|
174
|
-
type ChartMark = { at: number; label: string; kind: "pass" | "deadline" | "died" | "event"
|
|
175
|
-
|
|
176
|
-
type
|
|
175
|
+
type ChartMark = { at: number; label: string; kind: "pass" | "deadline" | "died" | "event" | "release" | "steer" | "ruling" | "wake";
|
|
176
|
+
verdict?: "pass" | "fail" | "unknown"; source?: string; lane?: string };
|
|
177
|
+
type ChartBand = { from: number; to: number; label: string; kind: "after-pass" | "idle" | "missing" | "blocked" };
|
|
178
|
+
type TimelineLane = { id: string; label: string; spans: Array<{ start: number; end: number | null; state: string; note?: string }>;
|
|
179
|
+
parent?: string; depth?: number; ticks?: TimelineTick[]; detail?: string[] };
|
|
180
|
+
type TimelineTick = { at: number; outcome: "ok" | "quota" | "lost" | "rate-limit" | "oom" | "refused" | "aborted" | "other"; note?: string };
|
|
177
181
|
type MultiplePanel = { id: string; label: string; unit?: string; domain?: [number, number]; points?: TimePoint[];
|
|
178
182
|
missing?: { why: string; detail?: string }; end?: { at: number; kind: ChartMark["kind"]; label?: string }; marks?: ChartMark[] };
|
|
179
183
|
type MeterSegment = { label: string; value: number | null; color?: string; kind?: "measured" | "untraced" };
|
|
180
184
|
```
|
|
181
185
|
|
|
182
186
|
Mark kinds differ by stroke as well as colour: pass is solid, deadline dashed, died ends in a cross, and other events are dotted.
|
|
187
|
+
A release carries a diamond head, a steer a triangle, a ruling a square and a wake a circle; releases, steers and wakes stop at the plot's edge so frequent events never wall off the data, and a ruling crosses it.
|
|
188
|
+
A recorded `verdict` colours a mark (pass and fail take the status tones, unknown the muted tone), and a `source`, such as the operator or the keeper, follows its label.
|
|
189
|
+
Mark labels take up to three rows above the data, placed by measured width so none overlap; marks of one kind and verdict at one place share a rule and a label (`rc17 (+18)`), and a label with no room is left to the hover and the table.
|
|
190
|
+
A `blocked` band is a system-wide wall, such as a quota window: a breach wash across every lane under a solid top edge.
|
|
183
191
|
Marks and bands appear in the figure's table (`Recorded events by …`) and, for React, in a text list under the plot.
|
|
184
|
-
|
|
192
|
+
`timeSeries` and `smallMultiples` refuse marks or bands outside the x domain, and `timeline` names them at its edge instead (below); React components throw `RangeError` for marks or bands they cannot place, as `StackedBarChart` does.
|
|
193
|
+
Axis labels never overlap at 720 or 358 px: `timeSeries` labels recorded positions spread evenly across the plot, and `timeline` uses the smallest clock step (1 min to 7 days) whose labels fit, naming the date at midnight.
|
|
185
194
|
|
|
186
|
-
`timeline` refuses an open span without `now`, a span outside a supplied `start`/`end` window and reversed times. States named in `hatch` (default `missing`, `untraced`) are hatched; states in `muted` (default `idle`) use the muted tone.
|
|
187
|
-
`
|
|
195
|
+
`timeline` refuses an open span without `now`, a span, tick or `now` outside a supplied `start`/`end` window and reversed times. States named in `hatch` (default `missing`, `untraced`) are hatched; states in `muted` (default `idle`) use the muted tone.
|
|
196
|
+
The window defaults to the extent of the data (spans, ticks and `now`), so a run that ended early is not drawn out to its deadline: a mark past the window, such as the deadline, is named at the edge it falls past with its distance (`Deadline +21.9 h →`), listed in the note, and not drawn; bands are clipped to the window.
|
|
197
|
+
Pass `start` (the run's start) to show time before the first span.
|
|
198
|
+
|
|
199
|
+
Lanes form a tree through `parent`: each lane is drawn under its parent with a connector, siblings and roots keep their input order, and `depth` defaults to the parent's depth plus one. A stated depth that disagrees with the parent, a parent that is not a lane and a parent chain that loops are refused.
|
|
200
|
+
`ticks` are recorded attempts, such as driver turns, at the time each ended: ok ticks rise above the bar and failed ticks drop below it in their outcome's colour from the shared outcome palette (below), and the lane ends with its counts, `21✓ 250✗`. A lane without `ticks` shows no counts; an empty `ticks` shows `0✓ 0✗`. Ticks of one outcome within 2 px are drawn as one, with the count and the commonest `note` in its hover. An unknown outcome is refused.
|
|
201
|
+
A mark with a `lane` is drawn on that lane only (a steer to one agent, a wake of the root) instead of across every lane; a lane that is not in the figure is refused.
|
|
202
|
+
`detail` is the caller's facts about a lane (profile, model, status, attempts, cost, top error), one hover line each on the lane's label and every span, and a column of the lanes table.
|
|
203
|
+
`collapsed` folds the named lanes' subtrees: descendants are hidden, the label gains `+N`, and the folded lane's ticks and counts total its subtree. Passing `collapsed`, even empty, makes each parent lane's label a fold toggle (`data-toggle`, a button with `aria-expanded`); `TimelineView` keeps the fold state and wires the toggles to a click, Enter or Space, returning focus to the toggle.
|
|
204
|
+
`Gantt` keeps its single-span `rows` input; `lanes` takes the same shape as `timeline` and draws spans only.
|
|
188
205
|
|
|
189
206
|
`Meter` with `segments` draws each recorded part of `total`; the remainder no segment accounts for is hatched and labelled `untraced` (rename it with `untraced`). A null segment is listed as `not recorded` and takes no width; a missing total hatches the whole track. Parts that sum past the total throw.
|
|
190
207
|
|
|
191
208
|
`smallMultiples` draws one panel per arm. A `missing` panel is hatched and reads `no data: <why>`; an `end` stops the line at a mark of its kind. It refuses mixed units, values outside the shared domain, points after an end and a missing panel that also carries data. `shared: "x"` keeps one x domain and requires each panel's own y `domain`. The lede counts `n of m <noun>s have data`.
|
|
192
209
|
|
|
210
|
+
`TimelineView` is `FigureView` around `timeline(lanes, { ...options, collapsed })`; `defaultCollapsed` names the lanes folded on first render.
|
|
211
|
+
|
|
193
212
|
`FigureView` embeds any static `Figure | Refusal` in React: the wide render in containers of 720 px or more, the phone render (or the table, when a figure has none) below that, and the data, reading and method in a closed disclosure. A refusal renders as its sentence. Import `figure.css` for its styles.
|
|
194
213
|
|
|
195
214
|
`node scripts/capture-run-page.mjs [dir]` (after `npm run build`) captures each addition at 1440 px light and 390 px dark; the reviewed images are `docs/screenshots/run-page-*.png`.
|
|
196
215
|
|
|
216
|
+
### Release checks: the climb and the bar
|
|
217
|
+
|
|
218
|
+
A play's page asks how close its releases are to the check and to the goal's bar. `timeSeries` and `smallMultiples` draw it from the producer's recorded rows; Charts decides no verdict, comparability or checker.
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const climb = timeSeries(rows, {
|
|
222
|
+
x: { label: "release", domain: [-0.5, 16.5], categories: tags.map((tag, at) => ({ at, label: tag })) },
|
|
223
|
+
y: { label: "check progress", unit: "", domain: [-0.05, 1.06], strip: "no score",
|
|
224
|
+
ticks: [...stages.map((label, i) => ({ at: i / stages.length, label })), { at: 1, label: "SOLVED" }] },
|
|
225
|
+
bands: [{ from: 0, to: 16, label: "18b · 5 published, 7 withheld", kind: "group" }],
|
|
226
|
+
marks: [{ at: 9.5, label: "10.5 h", kind: "event", source: "gap" }, { at: 13.47, label: "v4 · operator amendment 20:52Z", kind: "ruling" }],
|
|
227
|
+
markers: { circle: "check", diamond: "gate" },
|
|
228
|
+
});
|
|
229
|
+
// rows: one per checker (and run), `colorIndex` 0 for the current checker; points such as
|
|
230
|
+
// { x: 13, y: 1, verdict: "pass", glyph: "check", marker: "circle", count: 3, firstAt, lastAt, annotation: line }
|
|
231
|
+
// { x: 15, y: null, verdict: "unknown", marker: "diamond", label: "6/15", count: 12 } → the strip, never a height
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
| Field | Drawn as |
|
|
235
|
+
|---|---|
|
|
236
|
+
| `verdict` | `pass` filled, `fail` outlined, `unknown` dashed; with `y: null`, a square in the strip under the plot (hatched when unknown) |
|
|
237
|
+
| `count`, `firstAt`, `lastAt` | `×n` beside the mark; first and last times in the hover and the table |
|
|
238
|
+
| `comparable` | `false` outlined with `*`, `null` outlined with `?` |
|
|
239
|
+
| `glyph` | `✓` (`check`) or `✕` (`cross`), the only marks in the status tones |
|
|
240
|
+
| `marker`, `label` | the mark's shape, named by the figure's `markers`; a short direct label such as `9/15` |
|
|
241
|
+
| `y.scale`, `y.targets`, `y.ticks` | log10 y; target bands (dashed when `stretch`); caller-named gridlines |
|
|
242
|
+
| `x.categories` | an ordinal axis of weighted columns; points sharing a column are spread across it |
|
|
243
|
+
| `colorIndex` (row) | the checker palette, 0 current; dashes follow the index |
|
|
244
|
+
|
|
245
|
+
The bar panels share the climb's columns: `smallMultiples(panels, { shared: "x", x: { label, domain, categories }, columns: 2, connect: false, markers })`, each panel with its own `unit`, `format`, `scale: "log"`, `domain` and `targets`. `docs/fixtures/magnetar-play.json` holds the Magnetar play's real 17c, 18b and 19b rows in these shapes (`docs/fixtures/export-magnetar-play.mjs` exports them on the Lab host), and `src/run-page-figures.test.ts` draws them.
|
|
246
|
+
|
|
247
|
+
Attempt outcomes and checkers have one palette in every view. `OUTCOME_ORDER` is the stack order (ok, quota, lost, rate-limit, oom, refused, aborted, other; an open attempt is hatched, never an outcome); `OUTCOME_COLORS[outcome]` and `checkerColor(index)` return the `var(--chart-outcome-*)` and `var(--chart-checker-*)` tokens `figure.css` defines as `light-dark()` pairs, so they follow the page's `color-scheme`. Aborted and other share the neutral tone and always carry a label. `node scripts/palette-check.mjs <dataviz validate_palette.js>` checks both palettes, adjacent pairs in order, on the light surface and on #161616.
|
|
248
|
+
|
|
249
|
+
| Play page figure | 1440 light | 390 dark |
|
|
250
|
+
|---|---|---|
|
|
251
|
+
| Climb |  |  |
|
|
252
|
+
| Against the bar |  |  |
|
|
253
|
+
|
|
197
254
|
### Plots without visible report controls
|
|
198
255
|
|
|
199
256
|
Use `renderFigure(figure, noteNumber, { presentation: "plot" })` to show the responsive plot alone.
|
package/dist/figure.css
CHANGED
|
@@ -310,8 +310,8 @@
|
|
|
310
310
|
.tgc-tip-bg { fill: var(--chart-ink); }
|
|
311
311
|
.tgc-tip-ink { fill: var(--chart-canvas); }
|
|
312
312
|
|
|
313
|
-
.tgc-series-line { fill: none; stroke: var(--chart-accent); stroke-width: 2; stroke-linejoin: round; }
|
|
314
|
-
.tgc-series-point, .tgc-series-key { fill: var(--chart-accent); stroke: var(--chart-canvas); stroke-width: 2; }
|
|
313
|
+
.tgc-series-line { fill: none; stroke: var(--tgc-series, var(--chart-accent)); stroke-width: 2; stroke-linejoin: round; }
|
|
314
|
+
.tgc-series-point, .tgc-series-key { fill: var(--tgc-series, var(--chart-accent)); stroke: var(--chart-canvas); stroke-width: 2; }
|
|
315
315
|
|
|
316
316
|
/* Semantic states stay tied to Brand status tokens. No-data has its own neutral mark. */
|
|
317
317
|
.tgc-heat-pass { fill: color-mix(in srgb, var(--chart-pass, var(--status-running)) 19%, var(--chart-canvas)); stroke: var(--chart-pass, var(--status-running)); stroke-width: .8; }
|
|
@@ -352,9 +352,27 @@
|
|
|
352
352
|
.tgc-mark-deadline { stroke: var(--chart-ink); stroke-dasharray: 5 3; }
|
|
353
353
|
.tgc-mark-died { stroke: var(--chart-breach, var(--status-error)); stroke-width: 2; }
|
|
354
354
|
.tgc-mark-event { stroke: var(--chart-ink-muted); stroke-dasharray: 1 3; stroke-linecap: round; }
|
|
355
|
+
.tgc-mark-release { stroke: var(--chart-ink-muted); }
|
|
356
|
+
.tgc-mark-steer { stroke: var(--chart-accent); stroke-dasharray: 1 3; stroke-linecap: round; }
|
|
357
|
+
.tgc-mark-ruling { stroke: var(--chart-ink); stroke-dasharray: 6 2 1 2; }
|
|
358
|
+
.tgc-mark-wake { stroke: var(--chart-ink-muted); stroke-dasharray: 1 3; stroke-linecap: round; }
|
|
359
|
+
.tgc-mark-head { fill: var(--chart-ink-muted); stroke: var(--chart-canvas); stroke-width: 1; }
|
|
360
|
+
[data-mark="steer"] .tgc-mark-head { fill: var(--chart-accent); }
|
|
361
|
+
[data-mark="ruling"] .tgc-mark-head { fill: var(--chart-ink); }
|
|
362
|
+
/* A recorded verdict colours the rule and head: pass and fail take the status tones, unknown the muted tone. */
|
|
363
|
+
.tgc-verdict-pass .tgc-mark { stroke: var(--chart-pass, var(--status-running)); }
|
|
364
|
+
.tgc-verdict-pass .tgc-mark-head { fill: var(--chart-pass, var(--status-running)); }
|
|
365
|
+
.tgc-verdict-fail .tgc-mark { stroke: var(--chart-breach, var(--status-error)); }
|
|
366
|
+
.tgc-verdict-fail .tgc-mark-head { fill: var(--chart-breach, var(--status-error)); }
|
|
367
|
+
.tgc-verdict-unknown .tgc-mark { stroke: var(--chart-muted); }
|
|
368
|
+
.tgc-verdict-unknown .tgc-mark-head { fill: var(--chart-muted); }
|
|
355
369
|
.tgc-mark-label { fill: var(--chart-ink); paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }
|
|
370
|
+
.tgc-mark-edge { fill: var(--chart-ink-muted); }
|
|
356
371
|
.tgc-band-after-pass { fill: color-mix(in srgb, var(--chart-pass, var(--status-running)) 12%, transparent); }
|
|
357
372
|
.tgc-band-idle { fill: var(--chart-shade); }
|
|
373
|
+
/* A system-wide wall, such as a quota window: a breach wash across every lane, topped by a solid edge. */
|
|
374
|
+
.tgc-band-blocked { fill: color-mix(in srgb, var(--chart-breach, var(--status-error)) 9%, transparent); }
|
|
375
|
+
.tgc-band-wall { stroke: var(--chart-breach, var(--status-error)); stroke-width: 2; }
|
|
358
376
|
/* Missing data: a neutral wash under hatch lines, never a zero-height mark. */
|
|
359
377
|
.tgc-hatch-bg { fill: color-mix(in srgb, var(--chart-muted) 10%, transparent); }
|
|
360
378
|
.tgc-hatch { fill: none; stroke: var(--chart-muted); stroke-width: 1; }
|
|
@@ -362,9 +380,85 @@
|
|
|
362
380
|
.tgc-span-muted { fill: var(--chart-muted); }
|
|
363
381
|
.tgc-span-open { stroke: var(--chart-ink); stroke-width: 1.5; stroke-dasharray: 3 2; }
|
|
364
382
|
.tgc-now { stroke: var(--chart-ink); stroke-width: 1.5; }
|
|
383
|
+
/* Timeline trees and attempts. Ok ticks rise above the bar and failed ticks drop below it, so they read without colour. */
|
|
384
|
+
.tgc-tree { fill: none; stroke: var(--chart-muted); stroke-width: 1; }
|
|
385
|
+
.tgc-caret { fill: var(--chart-ink-muted); }
|
|
386
|
+
.tgc-lane-toggle { cursor: pointer; }
|
|
387
|
+
.tgc-lane-toggle:focus-visible { outline: none; }
|
|
388
|
+
.tgc-lane-hit { fill: transparent; stroke: transparent; stroke-width: 2; }
|
|
389
|
+
.tgc-lane-toggle:hover .tgc-lane-hit { fill: var(--chart-shade); }
|
|
390
|
+
.tgc-lane-toggle:focus-visible .tgc-lane-hit { stroke: var(--chart-accent); }
|
|
391
|
+
.tgc-tick { stroke-width: 1.5; }
|
|
392
|
+
.tgc-tick-ok { stroke: var(--chart-outcome-ok); }
|
|
393
|
+
.tgc-tick-quota { stroke: var(--chart-outcome-quota); }
|
|
394
|
+
.tgc-tick-lost { stroke: var(--chart-outcome-lost); }
|
|
395
|
+
.tgc-tick-rate-limit { stroke: var(--chart-outcome-rate-limit); }
|
|
396
|
+
.tgc-tick-oom { stroke: var(--chart-outcome-oom); }
|
|
397
|
+
.tgc-tick-refused { stroke: var(--chart-outcome-refused); }
|
|
398
|
+
.tgc-tick-aborted, .tgc-tick-other { stroke: var(--chart-outcome-neutral); }
|
|
399
|
+
/* Lane labels and counts keep a canvas halo, so rules and ticks under them never strike through the text. */
|
|
400
|
+
.tgc-lane-label, .tgc-count { paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }
|
|
401
|
+
.tgc-count { fill: var(--chart-ink); }
|
|
402
|
+
.tgc-count-ok { fill: var(--chart-pass, var(--status-running)); }
|
|
403
|
+
.tgc-count-failed { fill: var(--chart-breach, var(--status-error)); }
|
|
365
404
|
|
|
366
405
|
/* FigureView (React) picks the render by measured width; the wide plot fills its container. */
|
|
367
406
|
.tgc-figure-view { max-width: none; margin: 0; }
|
|
368
407
|
.tgc-view-plot svg { display: block; overflow: visible; }
|
|
369
408
|
.tgc-view-wide svg { width: 100%; height: auto; }
|
|
370
409
|
.tgc-view-narrow svg { max-width: 100%; height: auto; }
|
|
410
|
+
|
|
411
|
+
/*
|
|
412
|
+
* One fixed palette for attempt outcomes and check versions in every view (src/outcomes.ts names them). Each is a
|
|
413
|
+
* light-dark() pair picked by the page's color-scheme. Outcomes pass the dataviz colour-vision checks as adjacent
|
|
414
|
+
* pairs in stack order (ok, quota, lost, rate-limit, oom, refused) on the light surface and on #161616; checkers pass
|
|
415
|
+
* as adjacent series (current, then older). `scripts/palette-check.mjs` re-runs the validator. A page may override
|
|
416
|
+
* any of these properties; :where() keeps them at zero specificity.
|
|
417
|
+
*/
|
|
418
|
+
:where(:root) {
|
|
419
|
+
--chart-outcome-ok: light-dark(#2a78d6, #3987e5);
|
|
420
|
+
--chart-outcome-quota: light-dark(#eb6834, #d95926);
|
|
421
|
+
--chart-outcome-lost: light-dark(#1baf7a, #199e70);
|
|
422
|
+
--chart-outcome-rate-limit: light-dark(#eda100, #c98500);
|
|
423
|
+
--chart-outcome-oom: light-dark(#e87ba4, #d55181);
|
|
424
|
+
--chart-outcome-refused: light-dark(#6250d6, #9085e9);
|
|
425
|
+
--chart-outcome-neutral: #898781;
|
|
426
|
+
--chart-checker-0: light-dark(#2a78d6, #3987e5);
|
|
427
|
+
--chart-checker-1: light-dark(#1baf7a, #199e70);
|
|
428
|
+
--chart-checker-2: light-dark(#6250d6, #9085e9);
|
|
429
|
+
--chart-checker-3: light-dark(#eda100, #c98500);
|
|
430
|
+
}
|
|
431
|
+
/* A series drawn in a checker's hue; past the fourth hue it is muted and named by its label. */
|
|
432
|
+
.tgc-checker-0 { --tgc-series: var(--chart-checker-0); }
|
|
433
|
+
.tgc-checker-1 { --tgc-series: var(--chart-checker-1); }
|
|
434
|
+
.tgc-checker-2 { --tgc-series: var(--chart-checker-2); }
|
|
435
|
+
.tgc-checker-3 { --tgc-series: var(--chart-checker-3); }
|
|
436
|
+
.tgc-checker-other { --tgc-series: var(--chart-muted); }
|
|
437
|
+
/* Recorded verdicts: a pass is filled, a fail or an incomparable value is an outline, an undecided one dashed. */
|
|
438
|
+
.tgc-series-point.tgc-point-outline { fill: var(--chart-canvas); stroke: var(--tgc-series, var(--chart-accent)); stroke-width: 1.75; }
|
|
439
|
+
.tgc-series-point.tgc-point-undecided { fill: var(--chart-canvas); stroke: var(--tgc-series, var(--chart-accent)); stroke-width: 1.5; stroke-dasharray: 2 1.5; }
|
|
440
|
+
.tgc-strip-hatch .tgc-hatch { stroke: var(--tgc-series, var(--chart-muted)); }
|
|
441
|
+
.tgc-strip-edge { fill: none; stroke: var(--tgc-series, var(--chart-muted)); stroke-width: 1.25; }
|
|
442
|
+
.tgc-strip-observation:focus-visible { outline: none; }
|
|
443
|
+
.tgc-strip-observation:focus-visible .tgc-series-hit { stroke: var(--chart-ink); stroke-width: 2; }
|
|
444
|
+
.tgc-point-badge { paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; font-family: var(--font-mono, "JetBrains Mono", ui-monospace, monospace); }
|
|
445
|
+
.tgc-point-label { fill: var(--chart-ink-muted); }
|
|
446
|
+
.tgc-glyph-note { fill: var(--chart-ink); font-weight: 600; }
|
|
447
|
+
/* Status colours appear only on these glyphs. */
|
|
448
|
+
.tgc-glyph-check { fill: var(--chart-pass, var(--status-running)); font-weight: 600; }
|
|
449
|
+
.tgc-glyph-cross { fill: var(--chart-breach, var(--status-error)); font-weight: 600; }
|
|
450
|
+
/* Recorded targets sit under the data: a target is a soft band between solid edges, a stretch a dashed outline. */
|
|
451
|
+
.tgc-target-target { fill: color-mix(in srgb, var(--chart-ink) 7%, transparent); }
|
|
452
|
+
.tgc-target-stretch { fill: none; }
|
|
453
|
+
.tgc-target-target-edge, .tgc-target-target.tgc-target-line { stroke: var(--chart-ink-muted); stroke-width: 1; }
|
|
454
|
+
.tgc-target-stretch-edge, .tgc-target-stretch.tgc-target-line { stroke: var(--chart-ink-muted); stroke-width: 1; stroke-dasharray: 4 3; }
|
|
455
|
+
.tgc-target-label { fill: var(--chart-ink-muted); paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }
|
|
456
|
+
/* Group headers: a labelled bracket above the plot and a light rule at each inner edge. */
|
|
457
|
+
.tgc-group-rule { stroke: var(--chart-ink-muted); stroke-width: 1.5; }
|
|
458
|
+
.tgc-group-edge { stroke: var(--chart-rule); stroke-width: 1; }
|
|
459
|
+
.tgc-group-label { fill: var(--chart-ink); paint-order: stroke; stroke: var(--chart-canvas); stroke-width: 3px; stroke-linejoin: round; }
|
|
460
|
+
/* The verdict key: glyphs in the neutral ink, so they describe a mark's form, not a series. */
|
|
461
|
+
.tgc-key-mark { stroke-width: 1.5; }
|
|
462
|
+
.tgc-key-filled { fill: var(--chart-ink-muted); stroke: none; }
|
|
463
|
+
.tgc-key-outline { fill: none; stroke: var(--chart-ink-muted); }
|
|
464
|
+
.tgc-key-dashed { fill: none; stroke: var(--chart-ink-muted); stroke-dasharray: 2 1.5; }
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as isRefusal, S as
|
|
1
|
+
import { A as IntervalMethod, C as BreakdownInput, D as Exclusion, E as Estimate, F as Tier, I as TierCounts, L as isRefusal, M as RateRow, N as Refusal, O as Figure, P as Setup, S as YTick, T as CostBasis, _ as MarkVerdict, a as timeline, b as YScale, c as OUTCOME_ORDER, d as PointFields, f as PointGlyph, g as MarkKind, h as ChartMark, i as TimelineTick, j as MatrixCell, k as Interval, l as TickOutcome, m as ChartBand, n as TimelineOptions, o as CHECKER_HUES, p as BandKind, r as TimelineSpan, s as OUTCOME_COLORS, t as TimelineLane, u as checkerColor, v as MarkerShape, w as ComparisonRow, x as YTarget, y as XCategory } from "./timeline-CNHABOS1.js";
|
|
2
2
|
//#region src/block.d.ts
|
|
3
3
|
interface RenderFigureOptions {
|
|
4
4
|
/** Chart uses a closed data disclosure; plot keeps only the SVG and accessible data. */
|
|
@@ -185,7 +185,7 @@ interface MetricBarsOptions {
|
|
|
185
185
|
export declare function metricBars(rows: MetricRow[], o: MetricBarsOptions): Figure | Refusal;
|
|
186
186
|
//#endregion
|
|
187
187
|
//#region src/time-series.d.ts
|
|
188
|
-
interface TimePoint {
|
|
188
|
+
interface TimePoint extends PointFields {
|
|
189
189
|
x: number;
|
|
190
190
|
y: number | null;
|
|
191
191
|
observations?: Observations;
|
|
@@ -197,16 +197,32 @@ interface TimeSeriesRow {
|
|
|
197
197
|
id: string;
|
|
198
198
|
label: string;
|
|
199
199
|
points: TimePoint[];
|
|
200
|
+
/** Draw this series in checker `colorIndex`'s hue (0 is the current checker); past the fourth hue it is muted. */
|
|
201
|
+
colorIndex?: number;
|
|
200
202
|
}
|
|
201
203
|
interface TimeSeriesOptions {
|
|
202
204
|
x: {
|
|
203
205
|
label: string;
|
|
204
206
|
domain: [number, number];
|
|
207
|
+
/**
|
|
208
|
+
* An ordinal axis: one column per category, its width proportional to `weight`. Every point sits at a category's
|
|
209
|
+
* `at`; several points may share a column and are spread across it. Marks and bands between categories are placed
|
|
210
|
+
* between their columns, and a band bound that names a category covers that column.
|
|
211
|
+
*/
|
|
212
|
+
categories?: XCategory[];
|
|
205
213
|
};
|
|
206
214
|
y: {
|
|
207
215
|
label: string;
|
|
208
216
|
unit: string;
|
|
209
217
|
domain: [number, number];
|
|
218
|
+
/** `log` places values on a log10 scale and needs a positive domain. Default: linear. */
|
|
219
|
+
scale?: YScale;
|
|
220
|
+
/** Caller-named gridlines, such as check stages, in place of evenly spaced values. */
|
|
221
|
+
ticks?: YTick[];
|
|
222
|
+
/** Recorded goals drawn under the data: a shaded band (target) or a dashed one (stretch), a line when from equals to. */
|
|
223
|
+
targets?: YTarget[];
|
|
224
|
+
/** The label of the strip under the plot that holds verdicts recorded without a value. Default: no value. */
|
|
225
|
+
strip?: string;
|
|
210
226
|
};
|
|
211
227
|
formatX?: (value: number) => string;
|
|
212
228
|
formatY?: (value: number) => string;
|
|
@@ -214,6 +230,8 @@ interface TimeSeriesOptions {
|
|
|
214
230
|
marks?: ChartMark[];
|
|
215
231
|
/** Recorded shaded spans on the x axis, such as time after the first pass or idle time; `missing` is hatched. */
|
|
216
232
|
bands?: ChartBand[];
|
|
233
|
+
/** What each point `marker` stands for, such as `{ circle: "check", diamond: "gate" }`, named in the figure's key. */
|
|
234
|
+
markers?: Partial<Record<MarkerShape, string>>;
|
|
217
235
|
id?: string;
|
|
218
236
|
}
|
|
219
237
|
export declare function timeSeries(rows: TimeSeriesRow[], o: TimeSeriesOptions): Figure | Refusal;
|
|
@@ -222,10 +240,19 @@ export declare function timeSeries(rows: TimeSeriesRow[], o: TimeSeriesOptions):
|
|
|
222
240
|
interface MultiplePanel {
|
|
223
241
|
id: string;
|
|
224
242
|
label: string;
|
|
225
|
-
/**
|
|
243
|
+
/**
|
|
244
|
+
* The panel's recorded unit. With `shared: "both"` it must match the figure's y unit; with `shared: "x"` each panel
|
|
245
|
+
* may record its own (a rate, a size, a time), and the figure's y unit is the default for panels that set none.
|
|
246
|
+
*/
|
|
226
247
|
unit?: string;
|
|
248
|
+
/** `shared: "x"` only: formats this panel's y values in place of the figure's `formatY`. */
|
|
249
|
+
format?: (value: number) => string;
|
|
227
250
|
/** The panel's own y domain; required when only the x axis is shared. */
|
|
228
251
|
domain?: [number, number];
|
|
252
|
+
/** `log` places values on a log10 scale and needs a positive domain. Default: linear. */
|
|
253
|
+
scale?: YScale;
|
|
254
|
+
/** Recorded goals drawn under the panel's data, such as a paper's bar: a shaded band, dashed for a stretch. */
|
|
255
|
+
targets?: YTarget[];
|
|
229
256
|
points?: TimePoint[];
|
|
230
257
|
/** The arm produced no data. The panel is hatched and names the reason. */
|
|
231
258
|
missing?: {
|
|
@@ -241,9 +268,11 @@ interface MultiplePanel {
|
|
|
241
268
|
marks?: ChartMark[];
|
|
242
269
|
}
|
|
243
270
|
interface SmallMultiplesOptions {
|
|
271
|
+
/** `categories` makes x ordinal, as in `timeSeries`: every panel shares the same columns. */
|
|
244
272
|
x: {
|
|
245
273
|
label: string;
|
|
246
274
|
domain: [number, number];
|
|
275
|
+
categories?: XCategory[];
|
|
247
276
|
};
|
|
248
277
|
y: {
|
|
249
278
|
label: string;
|
|
@@ -254,10 +283,16 @@ interface SmallMultiplesOptions {
|
|
|
254
283
|
shared: "both" | "x";
|
|
255
284
|
/** What one panel is, for the lede: "3 of 4 arms have data". Default: panel. */
|
|
256
285
|
noun?: string;
|
|
286
|
+
/** Panels per row in the wide render (default 3); the phone render is one column. */
|
|
287
|
+
columns?: number;
|
|
288
|
+
/** false draws points without joining them, for values that are not one trajectory. Default true. */
|
|
289
|
+
connect?: boolean;
|
|
290
|
+
/** What each point `marker` stands for, such as `{ circle: "check", diamond: "gate" }`, named in the figure's key. */
|
|
291
|
+
markers?: Partial<Record<MarkerShape, string>>;
|
|
257
292
|
formatX?: (value: number) => string;
|
|
258
293
|
formatY?: (value: number) => string;
|
|
259
294
|
id?: string;
|
|
260
295
|
}
|
|
261
296
|
export declare function smallMultiples(panels: MultiplePanel[], o: SmallMultiplesOptions): Figure | Refusal;
|
|
262
297
|
//#endregion
|
|
263
|
-
export { type BandKind, type BreakdownInput, type BreakdownOptions, type ChartBand, type ChartMark, type ComparisonIntervalsOptions, type ComparisonRow, type CostBasis, type CostFrontierOptions, type Estimate, type Exclusion, type Figure, type HeatmapCell, type HeatmapColumn, type HeatmapOptions, type HeatmapRow, type HeatmapStatus, type Interval, type IntervalMethod, type LatencyRangeOptions, type LatencyRangeRow, type MarkKind, type MatrixCell, type MetricBarsOptions, type MetricRow, type MultiplePanel, type Observations, type PhaseWaterfallOptions, type RankedRatesOptions, type RateIdentity, type RateRow, type Refusal, type RenderFigureOptions, type Setup, type SmallMultiplesOptions, type TaskMatrixOptions, type Tier, type TierCounts, type TimePoint, type TimeSeriesOptions, type TimeSeriesRow, type TimelineLane, type TimelineOptions, type TimelineSpan, type WaterfallPhase, isRefusal, timeline };
|
|
298
|
+
export { type BandKind, type BreakdownInput, type BreakdownOptions, CHECKER_HUES, type ChartBand, type ChartMark, type ComparisonIntervalsOptions, type ComparisonRow, type CostBasis, type CostFrontierOptions, type Estimate, type Exclusion, type Figure, type HeatmapCell, type HeatmapColumn, type HeatmapOptions, type HeatmapRow, type HeatmapStatus, type Interval, type IntervalMethod, type LatencyRangeOptions, type LatencyRangeRow, type MarkKind, type MarkVerdict, type MatrixCell, type MetricBarsOptions, type MetricRow, type MultiplePanel, OUTCOME_COLORS, OUTCOME_ORDER, type Observations, type PhaseWaterfallOptions, type PointFields, type PointGlyph, type RankedRatesOptions, type RateIdentity, type RateRow, type Refusal, type RenderFigureOptions, type Setup, type SmallMultiplesOptions, type TaskMatrixOptions, type TickOutcome, type Tier, type TierCounts, type TimePoint, type TimeSeriesOptions, type TimeSeriesRow, type TimelineLane, type TimelineOptions, type TimelineSpan, type TimelineTick, type WaterfallPhase, type XCategory, type YScale, type YTarget, type YTick, checkerColor, isRefusal, timeline };
|