@pond-ts/charts 0.54.0 → 0.56.2
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/CHANGELOG.md +451 -1
- package/dist/AreaChart.d.ts +47 -22
- package/dist/AreaChart.js +24 -1
- package/dist/BandChart.d.ts +29 -17
- package/dist/BarChart.d.ts +92 -49
- package/dist/BarChart.js +65 -8
- package/dist/BarList.d.ts +127 -0
- package/dist/BarList.js +84 -0
- package/dist/BoxList.d.ts +108 -0
- package/dist/BoxList.js +125 -0
- package/dist/BoxPlot.d.ts +63 -30
- package/dist/Candlestick.d.ts +5 -4
- package/dist/ChartRow.js +57 -6
- package/dist/Layers.js +22 -2
- package/dist/LineChart.d.ts +29 -26
- package/dist/ListTable.d.ts +51 -0
- package/dist/ListTable.js +143 -0
- package/dist/ScatterChart.d.ts +27 -17
- package/dist/YAxis.d.ts +29 -1
- package/dist/YAxis.js +19 -5
- package/dist/area.js +46 -15
- package/dist/band.js +13 -0
- package/dist/bars.d.ts +89 -18
- package/dist/bars.js +141 -30
- package/dist/column-names.d.ts +74 -0
- package/dist/column-names.js +2 -0
- package/dist/context.d.ts +40 -2
- package/dist/data.d.ts +19 -0
- package/dist/data.js +46 -0
- package/dist/dev.d.ts +2 -0
- package/dist/dev.js +2 -0
- package/dist/domain.d.ts +54 -1
- package/dist/domain.js +195 -2
- package/dist/format.d.ts +20 -0
- package/dist/format.js +23 -10
- package/dist/gaps.d.ts +33 -0
- package/dist/gaps.js +49 -0
- package/dist/index.d.ts +19 -13
- package/dist/index.js +21 -13
- package/dist/line.js +10 -1
- package/dist/list-source.d.ts +61 -0
- package/dist/list-source.js +5 -0
- package/dist/list.d.ts +205 -0
- package/dist/list.js +165 -0
- package/dist/theme.d.ts +42 -0
- package/dist/theme.js +24 -0
- package/dist/viewport.d.ts +9 -1
- package/dist/viewport.js +40 -4
- package/dist/yticks.d.ts +44 -0
- package/dist/yticks.js +55 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -8,7 +8,11 @@ The `@pond-ts` packages — `pond-ts`, `@pond-ts/react`, `@pond-ts/charts`,
|
|
|
8
8
|
under a single `v*` tag, so this file covers them all. Pre-1.0: minor bumps may
|
|
9
9
|
include new features and type-level changes; patch bumps are strictly additive.
|
|
10
10
|
|
|
11
|
-
[Unreleased]: https://github.com/pond-ts/pond/compare/v0.
|
|
11
|
+
[Unreleased]: https://github.com/pond-ts/pond/compare/v0.56.2...HEAD
|
|
12
|
+
[0.56.2]: https://github.com/pond-ts/pond/compare/v0.56.1...v0.56.2
|
|
13
|
+
[0.56.1]: https://github.com/pond-ts/pond/compare/v0.56.0...v0.56.1
|
|
14
|
+
[0.56.0]: https://github.com/pond-ts/pond/compare/v0.55.0...v0.56.0
|
|
15
|
+
[0.55.0]: https://github.com/pond-ts/pond/compare/v0.54.0...v0.55.0
|
|
12
16
|
[0.54.0]: https://github.com/pond-ts/pond/compare/v0.53.1...v0.54.0
|
|
13
17
|
[0.53.1]: https://github.com/pond-ts/pond/compare/v0.53.0...v0.53.1
|
|
14
18
|
[0.53.0]: https://github.com/pond-ts/pond/compare/v0.52.0...v0.53.0
|
|
@@ -55,8 +59,454 @@ include new features and type-level changes; patch bumps are strictly additive.
|
|
|
55
59
|
|
|
56
60
|
## [Unreleased]
|
|
57
61
|
|
|
62
|
+
## [0.56.2] — 2026-08-05
|
|
63
|
+
|
|
64
|
+
### Fixed
|
|
65
|
+
|
|
66
|
+
- **charts (tests only, no shipped change):** the log-axis rendered-label test
|
|
67
|
+
is no longer an exact-set assertion over every digit-bearing node in the
|
|
68
|
+
render tree. It passed on Node 22 and failed on CI's Node 18 with one extra
|
|
69
|
+
element, blocking the publish twice. The discrepancy is **unreproduced and
|
|
70
|
+
still open** — recorded as `[PND-LOGTICK-N18]` in `PND_CHARTS_PLAN.md` with
|
|
71
|
+
everything measured about it. The assertion now checks that every chosen tick
|
|
72
|
+
renders in order, which is the wiring this test exists to cover; the tick
|
|
73
|
+
_selection_ it was really about is pinned deterministically by the
|
|
74
|
+
`yTickValues` unit tests.
|
|
75
|
+
|
|
76
|
+
## [0.56.1] — 2026-08-05
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- **charts (tests only, no shipped change):** a log-axis test asserted on
|
|
81
|
+
rendered label _text_, parsing numbers back out of the DOM to infer scale
|
|
82
|
+
behaviour. It passed locally and failed in CI on a value it could not have
|
|
83
|
+
produced there, which blocked the v0.56.0 publish. The root cause was never
|
|
84
|
+
reproduced; rather than guess at it, the assertion now compares the rendered
|
|
85
|
+
labels against the ticks the axis is specified to draw, formatted through the
|
|
86
|
+
same formatter — deterministic regardless of locale, formatting or DOM
|
|
87
|
+
differences, and the numeric guarantee itself was already pinned directly by
|
|
88
|
+
the `yTickValues` unit tests. The published artifact is identical to what
|
|
89
|
+
v0.56.0 would have been.
|
|
90
|
+
|
|
91
|
+
## [0.56.0] — 2026-08-05
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- **charts:** **`<YAxis scale="log">` — a base-10 logarithmic y axis.** Every y
|
|
96
|
+
scale was `scaleLinear`, so data spanning orders of magnitude was
|
|
97
|
+
undrawable: on a linear axis everything below the top decade collapses onto
|
|
98
|
+
the baseline. Set `scale="log"` and the axis maps by ratio, ticking the
|
|
99
|
+
decades. `format` still formats the **value**, so a readout says `1.2 PB`
|
|
100
|
+
rather than its logarithm — the transform is in the scale, not in the data,
|
|
101
|
+
which is what keeps it transparent to every draw layer, annotation and
|
|
102
|
+
cursor readout.
|
|
103
|
+
|
|
104
|
+
A log domain cannot contain zero, and d3 maps a non-positive value to
|
|
105
|
+
**`NaN`** — a coordinate the canvas silently _drops_, which is why every
|
|
106
|
+
consequence below is about something failing invisibly rather than throwing.
|
|
107
|
+
So the axis is deliberate about it:
|
|
108
|
+
- **Domain policy matches the linear axis exactly.** Auto-fit takes the
|
|
109
|
+
smallest **positive** extent (one zero sample can't collapse the axis, and
|
|
110
|
+
a `BarChart` — whose extent always widens to include zero — can still share
|
|
111
|
+
it); a positive explicit `min`/`max` is honoured verbatim and never
|
|
112
|
+
discarded, with the _auto-fit_ side moving if the domain would otherwise
|
|
113
|
+
invert; a fully auto-fit domain is `.nice()`d out to whole powers of ten, so
|
|
114
|
+
the extremes get headroom instead of sitting clipped on the plot edge. A
|
|
115
|
+
non-positive bound has no position and is refused in favour of the data.
|
|
116
|
+
`pad` is applied multiplicatively, adding the same fraction of a decade at
|
|
117
|
+
both ends.
|
|
118
|
+
- **A value with no position on the axis renders as a gap.** Previously the
|
|
119
|
+
gap test was `Number.isFinite(value)`, and `0` is finite — so the coordinate
|
|
120
|
+
became `NaN`, the canvas dropped the path op without breaking the path, and
|
|
121
|
+
the two neighbours were joined by a straight line _over_ the missing data.
|
|
122
|
+
Lines, area fills and outlines, and band envelopes now all break there.
|
|
123
|
+
- **Layers that reach for a baseline rest on the axis floor.** `AreaChart`
|
|
124
|
+
resolves an out-of-domain `baseline` there (writing `baseline={0}` is
|
|
125
|
+
natural and correct on a linear axis), and a **stacked** bar layer starts
|
|
126
|
+
its first segment there — starting at zero made the bottom segment of every
|
|
127
|
+
stack both invisible and unhittable. Unchanged on a linear axis, where zero
|
|
128
|
+
clamped into the domain _is_ zero.
|
|
129
|
+
- **The dev-mode warning names only unambiguous mistakes**: a refused
|
|
130
|
+
`min`/`max`, negative data, or an axis with no positive data at all. It
|
|
131
|
+
deliberately says nothing about an extent of exactly `[0, hi]`, which a
|
|
132
|
+
line touching zero and a bar layer on strictly positive data both report
|
|
133
|
+
identically — warning there fired on _every_ bar chart on a log axis. It
|
|
134
|
+
warns once per distinct complaint rather than on every repaint.
|
|
135
|
+
|
|
136
|
+
- **charts:** **pan and zoom now yield whole-millisecond view ranges.** A
|
|
137
|
+
wheel-zoom derives its range from pixel positions through `xScale.invert()`,
|
|
138
|
+
so the result was fractional by construction — an ordinary scroll produced
|
|
139
|
+
`1.7e12 + 0.37`. The epoch millisecond is this model's atomic unit and
|
|
140
|
+
consumers are entitled to assume it; one did, and a calendar `cursorSequence`
|
|
141
|
+
threw on a plain scroll. `zoomRange` / `panRange` round both ends, and never
|
|
142
|
+
collapse a positive span to zero width in doing so. (Core's fractional-instant
|
|
143
|
+
fix covers the same crash from the other side; this closes the class.)
|
|
144
|
+
|
|
145
|
+
- **charts:** **`AreaStyle.flatFill` — stacked areas that read as slabs.** An
|
|
146
|
+
area's fill has always graded to transparent at the baseline, which is right
|
|
147
|
+
for the elevation form and wrong for a stack: every band showed the one
|
|
148
|
+
beneath it through the fade, so a stacked area was not really drawable. Set
|
|
149
|
+
`flatFill` and the fill is flat; omitted, the gradient is unchanged, so no
|
|
150
|
+
existing theme shifts. The docs theme's `seq1…seq8` area roles set it, since
|
|
151
|
+
stacking is what they exist for.
|
|
152
|
+
|
|
153
|
+
- **docs theme:** **a sequential ramp — `seq1…seq8` — for charts with more
|
|
154
|
+
series than the categorical set has hues.** `--pond-viz-1…5` were, and
|
|
155
|
+
remain, the categorical set; a chart needing more slots (an eight-source
|
|
156
|
+
stack, a wall of climate stripes) now steps **tonally** through the brand
|
|
157
|
+
teal instead of introducing competing hues. Eight steps, evenly spaced
|
|
158
|
+
(~ΔL\* 9 in CIELAB), defined for light and dark, each mode's ramp containing
|
|
159
|
+
that mode's `--pond-viz-1` exactly. Exposed as `line` / `area` / `bar` theme
|
|
160
|
+
roles on `docsTheme` (Storybook) and the docs site's `useSiteChartTheme`,
|
|
161
|
+
and as an array from the site's `useSequentialRamp()`. Dev-only: the ramp
|
|
162
|
+
lives in the `docs-theme.fixture.ts` Storybook fixture and the website's
|
|
163
|
+
CSS, both excluded from the published `@pond-ts/charts` build — the library
|
|
164
|
+
still ships no palette.
|
|
165
|
+
|
|
166
|
+
### Fixed
|
|
167
|
+
|
|
168
|
+
- **core:** **a fractional epoch millisecond no longer crashes calendar
|
|
169
|
+
math.** `Temporal.Instant` refuses a non-integer epoch ms outright
|
|
170
|
+
(`epoch milliseconds must be an integer`), and `toPlainDateStart` passed
|
|
171
|
+
whatever it was given straight through — so realizing a `Sequence.calendar`
|
|
172
|
+
over a fractional range threw, and in a React app the exception unmounted the
|
|
173
|
+
page. A fraction is not a caller error: a chart's wheel-zoom derives its view
|
|
174
|
+
range from pixel positions via `xScale.invert()`, so an ordinary scroll
|
|
175
|
+
produces `1.7e12 + 0.37`. The instant is now floored to the millisecond
|
|
176
|
+
containing it — the epoch millisecond is this model's atomic unit and
|
|
177
|
+
calendar boundaries are themselves whole milliseconds, so the bucket
|
|
178
|
+
containing `t` and the one containing `t + 0.37` are necessarily the same,
|
|
179
|
+
and integer inputs are untouched. (`Math.floor`, not `Math.trunc`: pre-1970
|
|
180
|
+
they disagree, and `-5.5` lies inside the millisecond spanning `[-6, -5)`.)
|
|
181
|
+
|
|
182
|
+
- **charts:** toggling **`<ChartContainer grid>`** now repaints immediately.
|
|
183
|
+
`Layers`' draw callback read `container.grid` but didn't depend on it, so
|
|
184
|
+
switching gridlines off changed nothing until an unrelated dependency moved —
|
|
185
|
+
in practice you had to pan or zoom a little to force the update. The same
|
|
186
|
+
omission covered `sessionDividers` and `xKind`.
|
|
187
|
+
|
|
188
|
+
- **charts:** the log axis's dev-mode warning no longer requires **node's
|
|
189
|
+
ambient types**. It was guarded by a bare `process.env.NODE_ENV`, which
|
|
190
|
+
typechecks only when a tool happens to resolve `@types/node` from a parent
|
|
191
|
+
`node_modules` — so `tsc` inside the package passed while running the _same_
|
|
192
|
+
tsconfig from a consumer's directory failed with `TS2591: Cannot find name
|
|
193
|
+
'process'`. That took out the docs site's TypeDoc step, and would equally hit
|
|
194
|
+
any consumer typechecking the package's sources. The guard now lives in
|
|
195
|
+
`src/dev.ts` behind a local declaration and a `typeof` check, so a browser
|
|
196
|
+
bundle with no `process` global doesn't throw at import either.
|
|
197
|
+
|
|
198
|
+
## [0.55.0] — 2026-08-04
|
|
199
|
+
|
|
200
|
+
### Added
|
|
201
|
+
|
|
202
|
+
- **process:** **`@pond-ts/process` publishes for the first time —
|
|
203
|
+
experimental, pre-1.0.** Computations as data over pond-ts: a processing
|
|
204
|
+
graph authored fluently in application code (or composed as JSON by a saved
|
|
205
|
+
view or a tool-calling model) resolves against a declared op vocabulary and
|
|
206
|
+
runs over a bound `TimeSeries`, with content-addressed caching, provenance,
|
|
207
|
+
and per-node timings on every response. Two entry points: the plan layer at
|
|
208
|
+
`.` and the Node worker pool at `./pool`. The docs section
|
|
209
|
+
([pond-ts.org/docs/process](https://pond-ts.org/docs/process/)) is listed on
|
|
210
|
+
the site with a TypeDoc API reference; the publication follows the 2026-08
|
|
211
|
+
external audit hardening (all P1 findings fixed and regression-pinned). The
|
|
212
|
+
API is expected to move as friction reports land — pin an exact version.
|
|
213
|
+
|
|
214
|
+
- **charts:** **`<BarChart categories>` now works horizontally** ([PND-HCAT],
|
|
215
|
+
the 2026-08 API review's #3 item) — the funnel / ranking / comparison shape.
|
|
216
|
+
`orientation="horizontal"` puts the categories on the **y** axis as unit
|
|
217
|
+
slots with the value on x, and a `<YAxis>` with no explicit `ticks` **derives
|
|
218
|
+
one label per category by itself**, so the chart no longer needs a
|
|
219
|
+
hand-built `i + 0.5` tick list. It previously threw ("horizontal category
|
|
220
|
+
axes are not yet supported"), which forced consumers to convert their
|
|
221
|
+
categories into ordinal `bins` records _and_ hand-place the labels — the
|
|
222
|
+
workaround the gallery funnel documents.
|
|
223
|
+
|
|
224
|
+
Explicit `<YAxis ticks>` still wins, and vertical categorical charts are
|
|
225
|
+
untouched (categories stay on the container's ordinal x band scale). A new
|
|
226
|
+
internal `RowLayer.binCategories()` channel carries the names to whichever
|
|
227
|
+
axis they land on.
|
|
228
|
+
|
|
229
|
+
- **charts:** **the list family's series door** — `<BarList series={splits}
|
|
230
|
+
label={…}>` / `<BoxList series>` take a `TimeSeries` / `ValueSeries`
|
|
231
|
+
directly (one row per event; exactly-one-of with `rows`), closing the
|
|
232
|
+
"required adapter" gap the 2026-08 API review named: starting from a pond
|
|
233
|
+
series there is no shaping step. The `listRowsFrom*` readers remain for
|
|
234
|
+
record rows. Docs across the charts hub, cheat sheet, and type pages now
|
|
235
|
+
present the series as the whole data contract, with the exported `from*`
|
|
236
|
+
builders re-documented as **interop escape hatches for non-pond data**.
|
|
237
|
+
|
|
238
|
+
- **charts:** **`<BarList>` + `<BoxList>` — standalone ranked row lists** (the
|
|
239
|
+
react-timeseries-charts `HorizontalBarChart` shape, rebuilt as what it
|
|
240
|
+
always was: a table). One DOM row per _entity_ — an interface, a split, a
|
|
241
|
+
symbol — with a label cell (any node, links included), one glyph line per
|
|
242
|
+
configured column on **one shared value scale**, optional data cells
|
|
243
|
+
before/after the glyphs, `sortBy`/`sortDirection` or a full custom
|
|
244
|
+
comparator (missing values sort last either direction), an optional per-row
|
|
245
|
+
expander (`renderExpanded`, keyed on row identity so it survives a re-sort),
|
|
246
|
+
and consumer-owned row selection with an accent edge in the marks register.
|
|
247
|
+
A vertical **baseline rule** at the scale origin anchors the rows to one
|
|
248
|
+
reference (on by default for `<BoxList>`, whose lines float at their lower
|
|
249
|
+
quantile; opt-in for `<BarList>`, whose tracks already show zero), and
|
|
250
|
+
reference **`markers`** (`{ value, label? }`) draw a labelled dotted rule
|
|
251
|
+
through every row in the annotation register — an SLA / capacity line —
|
|
252
|
+
with marker values joining the auto domain fit.
|
|
253
|
+
`<BarList>` draws proportional value bars; its sister `<BoxList>` draws a
|
|
254
|
+
five-number distribution per line — range band, `q1`→`q3` body, median line
|
|
255
|
+
— plus an optional **current-value tick** with a formatted inline label (the
|
|
256
|
+
esnet traffic-by-interface look), using the same quantile vocabulary as the
|
|
257
|
+
canvas `<BoxPlot>` (`lower`/`q1`/`median`/`q3`/`upper`, both-or-neither
|
|
258
|
+
body, quantiles computed upstream — `reduce` facts — never by the chart).
|
|
259
|
+
Styling stays on the one channel: bars resolve `theme.bar[as]`, boxes
|
|
260
|
+
`theme.box[as]`; both built-in themes gain a `box.secondary` role for the
|
|
261
|
+
paired-direction case. Readers `listRowsFromTimeSeries` /
|
|
262
|
+
`listRowsFromValueSeries` build one row per event / axis key. The in-plot
|
|
263
|
+
histogram remains `<BarChart orientation="horizontal">` — the lists are for
|
|
264
|
+
the table-shaped cases it can't be (link labels, cells, expanders, custom
|
|
265
|
+
sort).
|
|
266
|
+
|
|
267
|
+
- **charts:** **`BarStyle.hover` — a distinct hover colour for bars**
|
|
268
|
+
([#577](https://github.com/pond-ts/pond/issues/577)). A theme may now give
|
|
269
|
+
bars a three-step emphasis — `fill` at rest → `hover` under the pointer →
|
|
270
|
+
`highlight` (plus the outline) when selected. Previously one `highlight`
|
|
271
|
+
served both live states, so hover and select differed only by the presence of
|
|
272
|
+
an outline; `ScatterStyle` has carried distinct rest / selected treatments
|
|
273
|
+
(`outline` vs `selectedOutline`) all along, making bars the less expressive
|
|
274
|
+
layer for the same two-state interaction.
|
|
275
|
+
|
|
276
|
+
**Optional, with a `highlight` fallback**, so no existing theme changes
|
|
277
|
+
meaning or rendering — a theme that wants the distinction adds one colour.
|
|
278
|
+
Selection outranks hover on a bar that is both. Single-series only: a stacked
|
|
279
|
+
or per-bin-coloured bar has no separate highlight colour to replace (it pops
|
|
280
|
+
its _own_ fill, so a red/green volume bar keeps its meaning while live), and
|
|
281
|
+
that convention is unchanged.
|
|
282
|
+
|
|
283
|
+
### Changed
|
|
284
|
+
|
|
285
|
+
- **charts:** **a bar's capabilities now follow the mark it draws, not the
|
|
286
|
+
prop that fed it** ([PND-BARSEM], the 2026-08 API review's #2 item). A
|
|
287
|
+
**one-column vertical** histogram (`bins` + a single `column`) and a
|
|
288
|
+
one-entry `columns` draw exactly the mark a `series` + `column` chart
|
|
289
|
+
draws, but they used to route through the stacked path purely because of
|
|
290
|
+
which prop supplied them — and so silently lost whole-slot hit-testing
|
|
291
|
+
(#584), the `BarStyle.hover` colour, the cursor readout, stable per-bar
|
|
292
|
+
identity and per-bar decimation. They now take the single-series path, so
|
|
293
|
+
visually identical bars behave identically.
|
|
294
|
+
|
|
295
|
+
**What this changes in practice:** on a one-column histogram, hover and
|
|
296
|
+
click now hit the bar's **whole slot** rather than only the drawn
|
|
297
|
+
rectangle (so the space above a short bar is live, and slots tile the
|
|
298
|
+
axis); the layer gains a cursor readout; and `theme.bar.hover` applies.
|
|
299
|
+
A genuine multi-group stack, `categories`, and horizontal charts are
|
|
300
|
+
unchanged — their segments share a bin's x-range, so only y distinguishes
|
|
301
|
+
them. New reader `barsFromBins` backs the normalized path.
|
|
302
|
+
|
|
303
|
+
**Not a pure widening, in one respect:** dense-bar envelope decimation is
|
|
304
|
+
now live on a one-column histogram (it was single-series-only). It engages
|
|
305
|
+
only once bars fall under ~1px, where it is visually lossless, but at that
|
|
306
|
+
density the per-bar `gap` and highlight give way to envelope rects — pass
|
|
307
|
+
`decimate={false}` to keep every bar drawn. The `colors` map, the
|
|
308
|
+
`theme.bar[<column>]` role and `SelectInfo.label` are all preserved across
|
|
309
|
+
the reroute (each was a silent regression caught in review).
|
|
310
|
+
|
|
311
|
+
This shrinks `BarStyle.hover`'s scope warning from a list of five
|
|
312
|
+
path-accidents to the two real exclusions (a multi-group stack has no
|
|
313
|
+
hover channel on `StackStyle`; `binColors` keeps each bar's own colour by
|
|
314
|
+
design) — which was the acceptance test the task set itself.
|
|
315
|
+
|
|
316
|
+
- **charts:** **column names and source modes are now checked at compile
|
|
317
|
+
time** ([PND-CHARTAPI], the 2026-08 API review's #1 item). Every draw
|
|
318
|
+
layer's column props are derived from the series' schema, so
|
|
319
|
+
`<LineChart series={cpu} column="cpuu" />` — and a numeric prop pointed at
|
|
320
|
+
a string column, where the schema has some other numeric column — fail to
|
|
321
|
+
**compile** instead of throwing at render; the
|
|
322
|
+
same holds for `readout`, the band edges, the box quantiles, and the OHLC
|
|
323
|
+
prices. `<BarChart>`'s props became a **union of its legal source modes**,
|
|
324
|
+
so mixing sources (`series` + `bins`) or column forms (`column` +
|
|
325
|
+
`columns`), or passing `categories` a `column`, are compile errors too.
|
|
326
|
+
`<BarList>` / `<BoxList>` get the same treatment for `rows` XOR `series`,
|
|
327
|
+
which additionally closes the row-type hole #590 documented (annotating a
|
|
328
|
+
callback with a custom row type while passing `series` claimed a shape the
|
|
329
|
+
series door cannot produce).
|
|
330
|
+
|
|
331
|
+
**This narrows what compiles — deliberately.** Code carrying a typo, an
|
|
332
|
+
illegal mode mix, or a lying row annotation stops building; that is the
|
|
333
|
+
point, and each case was already a runtime failure. Two compatibility
|
|
334
|
+
behaviours are preserved on purpose: a **loosely-typed** series
|
|
335
|
+
(`TimeSeries<SeriesSchema>`, e.g. from a helper that doesn't narrow) still
|
|
336
|
+
accepts any column name, because an unparameterized schema leaves the name
|
|
337
|
+
union open and nothing can be checked against it; and `bins` column names
|
|
338
|
+
stay `string`, since they name aggregate fields of a bin record rather than
|
|
339
|
+
schema columns. Note the deliberate distinction: a schema that _does_ name
|
|
340
|
+
its columns but has **no numeric one** rejects every name — there is nothing
|
|
341
|
+
numeric to plot — which is not the same as the loose case.
|
|
342
|
+
|
|
343
|
+
**One new limitation.** Because a layer's props are a union _per series
|
|
344
|
+
kind_, a value typed as _either_ kind (`TimeSeries<A> | ValueSeries<B>` — a
|
|
345
|
+
wrapper that forwards whatever it is given) matches no single member and
|
|
346
|
+
must be narrowed or cast at the boundary. `DurationAxis.stories.tsx` is the
|
|
347
|
+
worked example. The alternative design (one generic over the series type)
|
|
348
|
+
handles that case but changes every props type's public generic parameters;
|
|
349
|
+
the trade is recorded in `spikes/charts-type-seam/REPORT.md`.
|
|
350
|
+
|
|
351
|
+
- **charts:** **a bar's hover / click target is now its whole slot**, not the
|
|
352
|
+
rectangle it draws. A bar _is_ the full width of its interval; the `gap` that
|
|
353
|
+
separates adjacent columns is a display affordance. Hit-testing the drawn
|
|
354
|
+
rect made that affordance interactive — the gap was a dead channel you could
|
|
355
|
+
point at and select nothing, and so was the empty plot space above a short
|
|
356
|
+
bar, even though the x-scrub cursor at that same x reported the bar quite
|
|
357
|
+
happily. `barAt` now tests the bar's full interval width and the full plot
|
|
358
|
+
height, so hover, click and the cursor readout all agree on which bar you are
|
|
359
|
+
on, and slots tile the axis.
|
|
360
|
+
|
|
361
|
+
**Widening, with one exception.** Points that previously selected _nothing_
|
|
362
|
+
now select the bar whose slot they fall in. The exception: a bar whose value
|
|
363
|
+
exceeds an explicit `<YAxis max>` used to draw — and be clickable — above the
|
|
364
|
+
plot top, in the strip a `'top'` axis title reserves; the slot stops at the
|
|
365
|
+
axis domain, so that sliver no longer hits. Everything inside the plot that
|
|
366
|
+
hit before still hits.
|
|
367
|
+
|
|
368
|
+
**It reaches across the full plot height, so it can shadow layers beneath
|
|
369
|
+
it.** The topmost hit wins, so a `<BarChart>` declared _after_ a
|
|
370
|
+
`<ScatterChart>` / `<BoxPlot>` / another `<BarChart>` in the same row now
|
|
371
|
+
claims every hit in its x-range at any y. Declare a bar layer **below** the
|
|
372
|
+
marks that should stay clickable.
|
|
373
|
+
|
|
374
|
+
**Single-series vertical only** — a stacked, `bins`, `categories` or
|
|
375
|
+
horizontal chart still hit-tests the drawn segment, because a stack's
|
|
376
|
+
segments share a bin's x-range and only y tells them apart.
|
|
377
|
+
|
|
378
|
+
Unchanged: a genuine hole between non-contiguous intervals still misses (the
|
|
379
|
+
change makes the drawing gap hittable, it doesn't invent coverage the data
|
|
380
|
+
lacks), a gap (`NaN`) bar owns no slot, and a shared edge goes to the left
|
|
381
|
+
bar — the rule `barIndexAtTime` already documented, so the two now agree by
|
|
382
|
+
construction.
|
|
383
|
+
|
|
384
|
+
### Fixed
|
|
385
|
+
|
|
386
|
+
- **process:** **audit hardening — five wrong-answer / silent-acceptance paths
|
|
387
|
+
in the plan layer closed** (external Codex audit, 2026-08; all reproduced,
|
|
388
|
+
all regression-pinned). Unit validation of a **picked output** read
|
|
389
|
+
`outputs[0]` instead of the selected output, so a picked `variance` was
|
|
390
|
+
refused where variance was demanded and — worse, silently — accepted where
|
|
391
|
+
price was. `Registry.define()` now rejects duplicate input roles and
|
|
392
|
+
duplicate output ids (both used to _collapse_ at run time rather than fail:
|
|
393
|
+
inputs resolved to the last role, outputs dropped the earlier column),
|
|
394
|
+
invalid param defaults, and `dependsOn` naming unknown params. An op result
|
|
395
|
+
whose length does not match the bound series is refused at the producer —
|
|
396
|
+
it used to ride out unchecked whenever `assemble: false` skipped the only
|
|
397
|
+
length check. The column-selection loop now honours `onError` (an operator
|
|
398
|
+
exception escaped `'collect'`), and a selector naming a nonexistent output
|
|
399
|
+
is a `skipped` entry instead of silently surfacing nothing. Fact provenance
|
|
400
|
+
(`id`, `name`, `op`, `unit`) now wins over a custom fold body's fields, and
|
|
401
|
+
`columnBytes` sums a chunked column's chunks instead of reporting 0 — which
|
|
402
|
+
a byte budget would read as "free".
|
|
403
|
+
|
|
404
|
+
Also: the derived fold slots in both builders now key by **params** —
|
|
405
|
+
`shape({points: 100})` after `shape({points: 20})` silently returned the
|
|
406
|
+
20-point node — and `shape` itself uses a `ceil` stride, so 200 points
|
|
407
|
+
asked of 399 rows returns ≤200 rather than all 399. The nested JSON Schema
|
|
408
|
+
projection can now express the `PickedOutput` input form, `Host` accepts
|
|
409
|
+
`budgetBytes` (the [PND-PROCCACHE] cap was unreachable from the long-lived
|
|
410
|
+
host shape) and grows `remove(id)`, and CI's package-content check covers
|
|
411
|
+
`@pond-ts/process`. Package remains **unpublished** (`private: true`).
|
|
412
|
+
|
|
413
|
+
A second audit round tightened the same seams. `columnBytes` now counts
|
|
414
|
+
what is actually retained: the **backing buffer's capacity** rather than
|
|
415
|
+
the column's logical length (core documents `_values` as possibly
|
|
416
|
+
oversized, so a one-row column viewing a 1000-slot buffer retains 8,000
|
|
417
|
+
bytes, not 8 — an undercount that defeats the budget), the chunk-offset
|
|
418
|
+
index and the bitmap's real bytes on chunked columns. The
|
|
419
|
+
**request-driven half of a `Host`'s footprint is now boundable**:
|
|
420
|
+
`runAsync` binds a graph per distinct caller-supplied `SourceRef`, so
|
|
421
|
+
`maxSources` caps registry-loaded sources LRU (author-added datasets are
|
|
422
|
+
never evicted), and a `remove()` racing an in-flight load now wins — the
|
|
423
|
+
landing load discards its result instead of resurrecting the dataset.
|
|
424
|
+
And an omitted param now unifies with its explicit default in the fluent
|
|
425
|
+
layer's derived fold slots (`shape()` ≡ `shape({points: 40})`, the same
|
|
426
|
+
rule `specId` applies), while the response labels a computation with the
|
|
427
|
+
**first** slot that named it rather than whichever was declared last.
|
|
428
|
+
|
|
429
|
+
- **charts:** **a hovered or selected single-series bar now pops to full
|
|
430
|
+
opacity** ([#576](https://github.com/pond-ts/pond/issues/576)). `drawBars`
|
|
431
|
+
set `globalAlpha` once to the resting `style.opacity` and never lifted it for
|
|
432
|
+
the highlight **fill** on the single-series path — only for the selected
|
|
433
|
+
bar's outline. The per-bar-`binColors` branch in the same function and
|
|
434
|
+
`drawStacks` both already popped to 1, and `drawBars`' own docstring claimed
|
|
435
|
+
it did too. So on a theme with `opacity < 1` a **hovered** bar (which has no
|
|
436
|
+
outline) barely changed, and a **selected** one read only by its outline.
|
|
437
|
+
All three paths now treat the highlight fill identically.
|
|
438
|
+
|
|
439
|
+
**This changes pixels** on any single-series `<BarChart>` with an alpha'd
|
|
440
|
+
theme: highlighted bars are brighter. A theme that raised its base `opacity`
|
|
441
|
+
to compensate may now want it back down.
|
|
442
|
+
|
|
443
|
+
**It also flattens select against hover**, which is worth knowing before you
|
|
444
|
+
upgrade. The selected bar's outline strokes in `highlight` — previously that
|
|
445
|
+
read as a brighter ring over an alpha'd fill, and it was the main thing
|
|
446
|
+
separating a selected bar from a hovered one. Now the fill underneath is the
|
|
447
|
+
same colour at the same alpha, so only the half of the stroke falling
|
|
448
|
+
outside the rect distinguishes them. Hover is no longer nearly invisible,
|
|
449
|
+
but the two live states are closer together. A theme that needs them clearly
|
|
450
|
+
apart should set the new `BarStyle.hover`.
|
|
451
|
+
|
|
58
452
|
## [0.54.0] — 2026-08-02
|
|
59
453
|
|
|
454
|
+
### Fixed
|
|
455
|
+
|
|
456
|
+
- **core:** **`fromArrow` now reads a field's declared Arrow type instead of
|
|
457
|
+
guessing from the runtime shape of `toArray()`** — closing a
|
|
458
|
+
silent-corruption class. The reader worked out what a column held from what
|
|
459
|
+
`toArray()` handed back, which is correct for the types it supports and
|
|
460
|
+
quietly wrong outside them, because Arrow's physical layouts do not all store
|
|
461
|
+
one machine word per logical value. Measured, before the fix: **`Float16`
|
|
462
|
+
ingested `1.5` as `15872`** (its half-float bit pattern — the length matched,
|
|
463
|
+
so nothing caught it), and a **`Decimal128` column with a single null
|
|
464
|
+
ingested `123.45` as `12345`** (the per-element path produced exactly `rows`
|
|
465
|
+
values, so the length check never fired). A dense `Decimal` merely threw the
|
|
466
|
+
wrong error, blaming a length mismatch.
|
|
467
|
+
|
|
468
|
+
The readable set is now an explicit allowlist — `Int` (any width),
|
|
469
|
+
`Float32`/`Float64`, `Date32`/`Date64`, `Time32`/`Time64`, `Timestamp`,
|
|
470
|
+
`Utf8`/`LargeUtf8`/`Utf8View`, `Null` (an all-missing value column), and a
|
|
471
|
+
`Dictionary` of any of those (the encoding is transparent; readability
|
|
472
|
+
follows the value type) — checked per field, on the key and value columns of every
|
|
473
|
+
Arrow door (`TimeSeries.fromArrow`, `ValueSeries.fromArrow`, and the
|
|
474
|
+
flattened key edges). Anything else is refused **by name**, with the cast
|
|
475
|
+
that would fix it: `Decimal` names the float64 precision trade-off, `Float16`
|
|
476
|
+
says to cast, `Bool` names the real reason (the columnar ingest engine
|
|
477
|
+
carries `number` and `string` value columns only). A duck-typed stand-in
|
|
478
|
+
carrying no `typeId` keeps working — the `ArrowTableLike` contract is
|
|
479
|
+
deliberately structural — and gains a width check that catches the Decimal
|
|
480
|
+
shape anyway.
|
|
481
|
+
|
|
482
|
+
Behavioural change worth noting: a `Utf8` **key** now throws on its declared
|
|
483
|
+
type rather than on its shape, so the message names the type and points at
|
|
484
|
+
passing it as a value column instead.
|
|
485
|
+
|
|
486
|
+
### Changed
|
|
487
|
+
|
|
488
|
+
- **A fold no longer builds a `TimeSeries`** ([PND-PROCTERM]). Every node's
|
|
489
|
+
`compute` widened the source with `appendColumn` for each nested input, so
|
|
490
|
+
an op could call the corpus normally — the studies take
|
|
491
|
+
`(series, { column })`. For a fold that was waste twice over: the column it
|
|
492
|
+
reads is already in its inputs, and it was being packed into a series only
|
|
493
|
+
to be read straight back out.
|
|
494
|
+
|
|
495
|
+
The cost was not incidental. `appendColumn` **boxes a gapped column** on
|
|
496
|
+
the way in, because core's `withColumn` takes values rather than a column —
|
|
497
|
+
22.4 ms per column at 1M rows. Every rolling study is gapped, so the
|
|
498
|
+
expensive path was the ordinary one.
|
|
499
|
+
|
|
500
|
+
20 folds × 500k rows, on top of the columnar fold context below:
|
|
501
|
+
**383 → 129 ms** (2.96×), rss 173 → 113 MB. Against the boxed, assembling
|
|
502
|
+
baseline the two changes together are **606 → 129 ms**.
|
|
503
|
+
|
|
504
|
+
A facts-only request now returns no `series` at all, and the upstream
|
|
505
|
+
column still resolves through the node graph rather than the terminal's
|
|
506
|
+
`needed` set — so the failure the plan warned about, a fact silently
|
|
507
|
+
coming back with no value because its column was never selected, cannot
|
|
508
|
+
happen.
|
|
509
|
+
|
|
60
510
|
### Added
|
|
61
511
|
|
|
62
512
|
- **`ctx.out` — prepared output buffers for a ranged recompute**
|
package/dist/AreaChart.d.ts
CHANGED
|
@@ -1,30 +1,10 @@
|
|
|
1
1
|
import { ValueSeries } from 'pond-ts';
|
|
2
2
|
import type { SeriesSchema, TimeSeries, ValueSeriesSchema } from 'pond-ts';
|
|
3
|
+
import type { NumericColumn, ValueNumericColumn } from './column-names.js';
|
|
3
4
|
import type { DecimateOption } from './decimate.js';
|
|
4
5
|
import { type Curve } from './curve.js';
|
|
5
6
|
import { type GapMode } from './gaps.js';
|
|
6
|
-
export interface
|
|
7
|
-
/**
|
|
8
|
-
* The source series. A `TimeSeries` fills against the time axis; a
|
|
9
|
-
* `ValueSeries` (`series.byValue('dist')`) against its value axis — the
|
|
10
|
-
* container infers which from the data, no axis-type prop (mirrors
|
|
11
|
-
* `<LineChart>`). Either way `column` names the numeric value to fill from.
|
|
12
|
-
*
|
|
13
|
-
* **Live charts:** `series.byValue(…)` mints a *fresh* projection each call, so
|
|
14
|
-
* an inline `series={s.byValue('dist')}` re-registers this layer every render —
|
|
15
|
-
* on a frequently re-rendering chart, memoize the projection (`useMemo`).
|
|
16
|
-
*/
|
|
17
|
-
series: TimeSeries<S> | ValueSeries<VS>;
|
|
18
|
-
/** Name of the numeric value column to fill from. */
|
|
19
|
-
column: string;
|
|
20
|
-
/**
|
|
21
|
-
* Optional column to **read out** at the cursor instead of the plotted
|
|
22
|
-
* `column` — the area still fills `column`, but each tracker sample also
|
|
23
|
-
* carries this column's value as {@link TrackerSample.readout}, so an
|
|
24
|
-
* off-chart readout can show a **source** value while the area draws a derived
|
|
25
|
-
* one. Mirrors `<LineChart readout>`. **Omitted ⇒ no readout channel.**
|
|
26
|
-
*/
|
|
27
|
-
readout?: string;
|
|
7
|
+
export interface AreaChartCommon<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema> {
|
|
28
8
|
/**
|
|
29
9
|
* The series' semantic identifier — what the data _is_ / how it should read
|
|
30
10
|
* (e.g. `elevation`, or a signed-traffic role like `in` / `out`). The theme
|
|
@@ -96,6 +76,50 @@ export interface AreaChartProps<S extends SeriesSchema = SeriesSchema, VS extend
|
|
|
96
76
|
*/
|
|
97
77
|
index?: number;
|
|
98
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* AreaChart's source + column props, a **union over the series kind** so the
|
|
81
|
+
* column names are checked against the schema that was actually passed
|
|
82
|
+
* ([PND-CHARTAPI]). A single member carrying `NumericColumn<S> |
|
|
83
|
+
* ValueNumericColumn<VS>` would silently widen to `string`: only one of the
|
|
84
|
+
* two generics is ever inferred, and the other falls back (measured in
|
|
85
|
+
* `spikes/charts-type-seam/`). Loosely-typed series still accept any name.
|
|
86
|
+
*/
|
|
87
|
+
type AreaChartSource<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema> = {
|
|
88
|
+
/**
|
|
89
|
+
* The source series. **Live charts:** `series.byValue(…)` mints a
|
|
90
|
+
* *fresh* projection each call, so an inline `series={s.byValue('d')}`
|
|
91
|
+
* re-registers this layer every render — on a frequently re-rendering
|
|
92
|
+
* (e.g. scrub-driven) chart, memoize the projection (`useMemo`) so the
|
|
93
|
+
* layer isn't rebuilt each frame.
|
|
94
|
+
*/
|
|
95
|
+
series: TimeSeries<S>;
|
|
96
|
+
column: NumericColumn<S>;
|
|
97
|
+
readout?: NumericColumn<S>;
|
|
98
|
+
} | {
|
|
99
|
+
series: ValueSeries<VS>;
|
|
100
|
+
column: ValueNumericColumn<VS>;
|
|
101
|
+
readout?: ValueNumericColumn<VS>;
|
|
102
|
+
};
|
|
103
|
+
/** `<AreaChart>`'s props: the shared knobs plus one series-kind source shape. */
|
|
104
|
+
export type AreaChartProps<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema> = AreaChartCommon<S, VS> & AreaChartSource<S, VS>;
|
|
105
|
+
/** Read a d3 linear scale's domain lower bound (the axis floor) from the plain
|
|
106
|
+
* `(value) => pixel` function the row hands to `draw`. The runtime object is a
|
|
107
|
+
* d3 `ScaleLinear` (it carries `.domain()`); the {@link RowLayer} type narrows
|
|
108
|
+
* it to the call signature, so this reads the bound through a localized,
|
|
109
|
+
* documented shape rather than widening `drawArea`'s contract to d3-scale. */
|
|
110
|
+
/**
|
|
111
|
+
* The area's baseline in **data** units: the caller's `baseline` when it has a
|
|
112
|
+
* finite position on this axis, else the axis floor.
|
|
113
|
+
*
|
|
114
|
+
* The fallback is not defensive padding — it's the log case. `baseline={0}` is
|
|
115
|
+
* the natural thing to write and is correct on a linear axis; on a log axis
|
|
116
|
+
* zero has no position at all — `scaleLog()(0)` is **`NaN`** (the `-Infinity`
|
|
117
|
+
* the log *transform* produces is then interpolated into the range, and
|
|
118
|
+
* `∞ − ∞` is what comes out) — and a single non-finite coordinate turns the
|
|
119
|
+
* whole filled path into nothing drawn at all. Resolving to the floor keeps the
|
|
120
|
+
* layer's meaning ("fill from the bottom") on both scale kinds.
|
|
121
|
+
*/
|
|
122
|
+
export declare function resolveAreaBaseline(baseline: number | undefined, yScale: (value: number) => number): number;
|
|
99
123
|
/**
|
|
100
124
|
* An area draw layer: fills between a value `column` and a `baseline`, with a
|
|
101
125
|
* graded (gradient) shade — opaque at the line, transparent at the baseline —
|
|
@@ -117,4 +141,5 @@ export interface AreaChartProps<S extends SeriesSchema = SeriesSchema, VS extend
|
|
|
117
141
|
* ```
|
|
118
142
|
*/
|
|
119
143
|
export declare function AreaChart<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema>({ series, column, readout, as: semantic, axis, baseline, curve, gaps, decimate, legend, index, }: AreaChartProps<S, VS>): null;
|
|
144
|
+
export {};
|
|
120
145
|
//# sourceMappingURL=AreaChart.d.ts.map
|
package/dist/AreaChart.js
CHANGED
|
@@ -12,6 +12,24 @@ import { useSlotKey } from './use-slot-key.js';
|
|
|
12
12
|
* d3 `ScaleLinear` (it carries `.domain()`); the {@link RowLayer} type narrows
|
|
13
13
|
* it to the call signature, so this reads the bound through a localized,
|
|
14
14
|
* documented shape rather than widening `drawArea`'s contract to d3-scale. */
|
|
15
|
+
/**
|
|
16
|
+
* The area's baseline in **data** units: the caller's `baseline` when it has a
|
|
17
|
+
* finite position on this axis, else the axis floor.
|
|
18
|
+
*
|
|
19
|
+
* The fallback is not defensive padding — it's the log case. `baseline={0}` is
|
|
20
|
+
* the natural thing to write and is correct on a linear axis; on a log axis
|
|
21
|
+
* zero has no position at all — `scaleLog()(0)` is **`NaN`** (the `-Infinity`
|
|
22
|
+
* the log *transform* produces is then interpolated into the range, and
|
|
23
|
+
* `∞ − ∞` is what comes out) — and a single non-finite coordinate turns the
|
|
24
|
+
* whole filled path into nothing drawn at all. Resolving to the floor keeps the
|
|
25
|
+
* layer's meaning ("fill from the bottom") on both scale kinds.
|
|
26
|
+
*/
|
|
27
|
+
export function resolveAreaBaseline(baseline, yScale) {
|
|
28
|
+
const floor = domainFloor(yScale);
|
|
29
|
+
if (baseline === undefined)
|
|
30
|
+
return floor;
|
|
31
|
+
return Number.isFinite(yScale(baseline)) ? baseline : floor;
|
|
32
|
+
}
|
|
15
33
|
function domainFloor(yScale) {
|
|
16
34
|
const d = yScale.domain?.();
|
|
17
35
|
return d && d.length > 0 ? d[0] : 0;
|
|
@@ -137,7 +155,12 @@ export function AreaChart({ series, column, readout, as: semantic, axis, baselin
|
|
|
137
155
|
// Omitted baseline rests on the axis floor (resolved late from the
|
|
138
156
|
// scale, so it tracks the auto-fit domain); a fixed baseline is used
|
|
139
157
|
// verbatim.
|
|
140
|
-
|
|
158
|
+
// A log axis has no position for zero — or anything at or below
|
|
159
|
+
// it — so an explicit out-of-domain `baseline` would scale to
|
|
160
|
+
// `NaN` and poison every coordinate in the fill path. Fall back
|
|
161
|
+
// to the axis floor, which is exactly what an omitted baseline
|
|
162
|
+
// already resolves to.
|
|
163
|
+
resolveAreaBaseline(baseline, yScale), curveFactory, gaps, gapConnectorOpacity, decimate),
|
|
141
164
|
},
|
|
142
165
|
axisId: axis,
|
|
143
166
|
index,
|
package/dist/BandChart.d.ts
CHANGED
|
@@ -1,24 +1,9 @@
|
|
|
1
1
|
import { ValueSeries } from 'pond-ts';
|
|
2
2
|
import type { SeriesSchema, TimeSeries, ValueSeriesSchema } from 'pond-ts';
|
|
3
|
+
import type { NumericColumn, ValueNumericColumn } from './column-names.js';
|
|
3
4
|
import { type Curve } from './curve.js';
|
|
4
5
|
import type { DecimateOption } from './decimate.js';
|
|
5
|
-
export interface
|
|
6
|
-
/**
|
|
7
|
-
* The source series. A `TimeSeries` fills the envelope against the time axis;
|
|
8
|
-
* a `ValueSeries` (`series.byValue('dist')`) against its value axis — the
|
|
9
|
-
* container infers which from the data, no axis-type prop (mirrors
|
|
10
|
-
* `<LineChart>` / `<AreaChart>`). Either way `lower`/`upper` name the numeric
|
|
11
|
-
* edge columns.
|
|
12
|
-
*
|
|
13
|
-
* **Live charts:** `series.byValue(…)` mints a *fresh* projection each call, so
|
|
14
|
-
* an inline `series={s.byValue('dist')}` re-registers this layer every render —
|
|
15
|
-
* on a frequently re-rendering chart, memoize the projection (`useMemo`).
|
|
16
|
-
*/
|
|
17
|
-
series: TimeSeries<S> | ValueSeries<VS>;
|
|
18
|
-
/** Name of the numeric column for the band's lower edge (e.g. `p25`). */
|
|
19
|
-
lower: string;
|
|
20
|
-
/** Name of the numeric column for the band's upper edge (e.g. `p75`). */
|
|
21
|
-
upper: string;
|
|
6
|
+
export interface BandChartCommon<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema> {
|
|
22
7
|
/**
|
|
23
8
|
* The band's semantic identifier — what the spread _is_ (e.g. `outer` for a
|
|
24
9
|
* p5/p95 envelope, `inner` for p25/p75). The theme maps it to a
|
|
@@ -64,6 +49,32 @@ export interface BandChartProps<S extends SeriesSchema = SeriesSchema, VS extend
|
|
|
64
49
|
*/
|
|
65
50
|
index?: number;
|
|
66
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* BandChart's source + column props, a **union over the series kind** so the
|
|
54
|
+
* column names are checked against the schema that was actually passed
|
|
55
|
+
* ([PND-CHARTAPI]). A single member carrying `NumericColumn<S> |
|
|
56
|
+
* ValueNumericColumn<VS>` would silently widen to `string`: only one of the
|
|
57
|
+
* two generics is ever inferred, and the other falls back (measured in
|
|
58
|
+
* `spikes/charts-type-seam/`). Loosely-typed series still accept any name.
|
|
59
|
+
*/
|
|
60
|
+
type BandChartSource<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema> = {
|
|
61
|
+
/**
|
|
62
|
+
* The source series. **Live charts:** `series.byValue(…)` mints a
|
|
63
|
+
* *fresh* projection each call, so an inline `series={s.byValue('d')}`
|
|
64
|
+
* re-registers this layer every render — on a frequently re-rendering
|
|
65
|
+
* (e.g. scrub-driven) chart, memoize the projection (`useMemo`) so the
|
|
66
|
+
* layer isn't rebuilt each frame.
|
|
67
|
+
*/
|
|
68
|
+
series: TimeSeries<S>;
|
|
69
|
+
lower: NumericColumn<S>;
|
|
70
|
+
upper: NumericColumn<S>;
|
|
71
|
+
} | {
|
|
72
|
+
series: ValueSeries<VS>;
|
|
73
|
+
lower: ValueNumericColumn<VS>;
|
|
74
|
+
upper: ValueNumericColumn<VS>;
|
|
75
|
+
};
|
|
76
|
+
/** `<BandChart>`'s props: the shared knobs plus one series-kind source shape. */
|
|
77
|
+
export type BandChartProps<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema> = BandChartCommon<S, VS> & BandChartSource<S, VS>;
|
|
67
78
|
/**
|
|
68
79
|
* A variance-band draw layer: fills the envelope between the `lower` and `upper`
|
|
69
80
|
* columns of `series` (typically `rollingByColumn` percentiles), gap-aware, and
|
|
@@ -82,4 +93,5 @@ export interface BandChartProps<S extends SeriesSchema = SeriesSchema, VS extend
|
|
|
82
93
|
* ```
|
|
83
94
|
*/
|
|
84
95
|
export declare function BandChart<S extends SeriesSchema = SeriesSchema, VS extends ValueSeriesSchema = ValueSeriesSchema>({ series, lower, upper, as: semantic, axis, curve, decimate, legend, index, }: BandChartProps<S, VS>): null;
|
|
96
|
+
export {};
|
|
85
97
|
//# sourceMappingURL=BandChart.d.ts.map
|