goro-charts 1.0.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +113 -0
- package/README.md +46 -19
- package/dist/charts/chart-base.d.ts +80 -17
- package/dist/data/series-store.d.ts +25 -2
- package/dist/defaults.d.ts +2 -2
- package/dist/goro-charts.js +229 -121
- package/dist/goro-charts.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/types.d.ts +23 -4
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,119 @@ All notable changes to this project are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.0] — 2026-07-06
|
|
9
|
+
|
|
10
|
+
### Behavior fixes
|
|
11
|
+
|
|
12
|
+
- **Data ownership contract (`copy`/`borrowed`).**
|
|
13
|
+
`setData` now **copies** the arrays by default (`'copy'`), making the chart
|
|
14
|
+
immune to external mutation. The `'borrowed'` (zero-copy) mode is available
|
|
15
|
+
as an opt-in but requires the caller to treat the arrays as immutable.
|
|
16
|
+
_(minor, behavior fix — the default semantics changed from borrowed to copy)_
|
|
17
|
+
- **Numeric input validation.**
|
|
18
|
+
Length mismatches, non-monotonic X, non-finite X (`Infinity`, `-Infinity`,
|
|
19
|
+
`NaN`), and non-finite Y (`±Infinity`) are now rejected with a descriptive
|
|
20
|
+
error naming the series and position — the same contract applies both in
|
|
21
|
+
snapshot mode (`setData`) and in streaming mode (`append`/`appendBatch`).
|
|
22
|
+
`NaN` in Y is the only accepted exception (see below). Inputs previously
|
|
23
|
+
accepted silently (or only with a `console.warn`) now throw.
|
|
24
|
+
_(minor, behavior fix)_
|
|
25
|
+
- **Non-monotonic append now throws.**
|
|
26
|
+
The previous `console.warn` was promoted to a thrown error to fail fast.
|
|
27
|
+
`appendBatch` validates the entire batch before pushing any sample — partial
|
|
28
|
+
batches never corrupt the ring state. _(minor, behavior fix)_
|
|
29
|
+
- **NaN in Y accepted and documented.**
|
|
30
|
+
`NaN` in Y is accepted, excluded from the extent computation, and reserved
|
|
31
|
+
for gap rendering in v1.6.0. Arrays where every Y is `NaN` produce a safe
|
|
32
|
+
degenerate range. _(minor, behavior fix)_
|
|
33
|
+
|
|
34
|
+
### Added
|
|
35
|
+
|
|
36
|
+
- `DataOwnership = 'copy' | 'borrowed'` type and the optional `ownership`
|
|
37
|
+
parameter on `setData(index, x, y, ownership?)`.
|
|
38
|
+
- `npm run check:readme` script — extracts every `ts` block from the README
|
|
39
|
+
and typechecks it against the real exported types. Wired into CI.
|
|
40
|
+
- New `Check README examples` CI step (before Typecheck).
|
|
41
|
+
- Reserved (commented-out TODO) slot for `docs/assets/streaming.gif` in the
|
|
42
|
+
README's first fold — the `![…]` stays commented until the asset exists, so
|
|
43
|
+
a broken image is never published.
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- `setData(index, x, y)` now takes an optional fourth argument `ownership`
|
|
48
|
+
(default `'copy'`).
|
|
49
|
+
- README signature-reference blocks (e.g. `new LineChart(canvas, opts?:
|
|
50
|
+
ChartOpts)`) are marked with `// signature` and skipped by `check:readme`,
|
|
51
|
+
keeping the readable form without breaking the semantic checking of the
|
|
52
|
+
runnable examples.
|
|
53
|
+
|
|
54
|
+
## [1.2.0] — 2026-07-06
|
|
55
|
+
|
|
56
|
+
### Behavior fixes
|
|
57
|
+
|
|
58
|
+
- **Crosshair sync by X value, not by pixel.**
|
|
59
|
+
Charts with different sizes, margins, and domains now sync correctly: the
|
|
60
|
+
data value is converted from pixel at the origin and back to pixel at the
|
|
61
|
+
target via pxToX/xToPx. A value outside the domain hides the crosshair on
|
|
62
|
+
the target. _(minor, behavior fix)_
|
|
63
|
+
- **Stacking separates positives and negatives.**
|
|
64
|
+
Positives accumulate on an ascending track, negatives on a descending track,
|
|
65
|
+
without cancelling each other out. In development, series in the same `stack`
|
|
66
|
+
with divergent axes or lengths emit a descriptive warning.
|
|
67
|
+
_(minor, behavior fix)_
|
|
68
|
+
- **`renderedPointCount` renamed to `windowPointCount`.**
|
|
69
|
+
The old metric lied: it returned the total points in the window, not those
|
|
70
|
+
actually drawn (the renderer decimates to ~2·plotW columns in the dense
|
|
71
|
+
regime). There are now two honest metrics: `windowPointCount` (data volume)
|
|
72
|
+
and `drawnPointCount` (post-decimation estimate). Anyone using
|
|
73
|
+
`renderedPointCount` should migrate to `windowPointCount`.
|
|
74
|
+
_(minor, behavior fix)_
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- `unsync(other)` — removes bidirectional crosshair synchronization.
|
|
79
|
+
- `drawnPointCount` — estimate of segments actually drawn after decimation
|
|
80
|
+
(useful to verify that decimation is active).
|
|
81
|
+
- Stacking: alignment validation between series in the same group (axis and
|
|
82
|
+
length) in development.
|
|
83
|
+
|
|
84
|
+
### Changed
|
|
85
|
+
|
|
86
|
+
- `injectCursor` (private) now receives an X value instead of a pixel —
|
|
87
|
+
aligned with value-based sync. `notifySyncCrosshair` sends a value instead
|
|
88
|
+
of a screen coordinate.
|
|
89
|
+
- `destroy` now removes the chart from all synced peers before clearing the
|
|
90
|
+
stores.
|
|
91
|
+
- `accumulateStackGroup` returns separate `{ posCum, negCum }` instead of a
|
|
92
|
+
single net accumulation.
|
|
93
|
+
|
|
94
|
+
## [1.1.0] — 2026-07-06
|
|
95
|
+
|
|
96
|
+
### Behavior fixes
|
|
97
|
+
|
|
98
|
+
- **`yMin`/`yMax` sentinel: `0` is now a legitimate bound.**
|
|
99
|
+
Previously `yMin: 0` and `yMax: 0` were treated as "auto" (discarded). They
|
|
100
|
+
now fall back to an automatic domain only when `undefined`. An anchored
|
|
101
|
+
`yMin: 0` is the most common case and finally works. _(minor, behavior fix)_
|
|
102
|
+
- **Keyboard: navigation by data point, not by pixel.**
|
|
103
|
+
The arrow keys move the crosshair point by point (logical) across the first
|
|
104
|
+
non-empty series. `Shift+arrow` advances 10 points. It previously navigated
|
|
105
|
+
by pixel, without anchoring to real data. _(minor, behavior fix)_
|
|
106
|
+
- **`prefers-reduced-motion` no longer stops streaming.**
|
|
107
|
+
It previously turned off `autoDraw`, interrupting the coalesced repaint of
|
|
108
|
+
live data. It now only sets a flag to suppress visual animations (when
|
|
109
|
+
present) without affecting the chart's continuous updates.
|
|
110
|
+
_(minor, behavior fix)_
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
|
|
114
|
+
- `ResolvedOpts.yMin` / `ResolvedOpts.yMax` are now `number | undefined`.
|
|
115
|
+
The "auto" sentinel changed from `0` to `undefined`. Code that relied on the
|
|
116
|
+
old behavior (e.g. `yMin !== 0` checks) should use `yMin !== undefined`.
|
|
117
|
+
- `prefers-reduced-motion` adds a runtime `change` listener to re-evaluate the
|
|
118
|
+
preference without recreating the chart. The listener is removed in
|
|
119
|
+
`destroy()`.
|
|
120
|
+
|
|
8
121
|
## [1.0.0]
|
|
9
122
|
|
|
10
123
|
Initial stable release.
|
package/README.md
CHANGED
|
@@ -7,6 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
**[Live demo →](https://stefanelloisaac.github.io/goro-charts/)**
|
|
9
9
|
|
|
10
|
+
<!-- TODO: gravar e adicionar docs/assets/streaming.gif, depois descomentar:
|
|
11
|
+

|
|
12
|
+
-->
|
|
13
|
+
|
|
10
14
|
Minimal high-performance chart engine. **Canvas 2D only. Zero runtime dependencies. Framework-agnostic.** Inspired by [uPlot](https://github.com/leeoniya/uPlot) — small, fast, and covers only what you need.
|
|
11
15
|
|
|
12
16
|
- **LineChart** — batched polyline with per-pixel-column min/max decimation
|
|
@@ -59,6 +63,7 @@ chart.appendBatch(1, [1, 2, 3], [39, 40, 39]);
|
|
|
59
63
|
Every chart holds one or more series. Each series owns its visual identity:
|
|
60
64
|
|
|
61
65
|
```ts
|
|
66
|
+
// signature
|
|
62
67
|
import type { SeriesConfig } from 'goro-charts';
|
|
63
68
|
|
|
64
69
|
interface SeriesConfig {
|
|
@@ -94,6 +99,7 @@ When `series` is omitted from `ChartOpts` a single default series is created aut
|
|
|
94
99
|
### `LineChart`
|
|
95
100
|
|
|
96
101
|
```ts
|
|
102
|
+
// signature
|
|
97
103
|
new LineChart(canvas, opts?: ChartOpts)
|
|
98
104
|
```
|
|
99
105
|
|
|
@@ -102,6 +108,7 @@ Each series is drawn as a single batched polyline. When the dataset is dense (mo
|
|
|
102
108
|
### `AreaChart`
|
|
103
109
|
|
|
104
110
|
```ts
|
|
111
|
+
// signature
|
|
105
112
|
new AreaChart(canvas, opts?: ChartOpts)
|
|
106
113
|
```
|
|
107
114
|
|
|
@@ -123,6 +130,7 @@ const chart = new AreaChart(canvas, {
|
|
|
123
130
|
### `ScatterChart`
|
|
124
131
|
|
|
125
132
|
```ts
|
|
133
|
+
// signature
|
|
126
134
|
new ScatterChart(canvas, opts?: ChartOpts)
|
|
127
135
|
```
|
|
128
136
|
|
|
@@ -131,9 +139,10 @@ Each series is drawn as filled circles, one per sampled point. When the dataset
|
|
|
131
139
|
```ts
|
|
132
140
|
const chart = new ScatterChart(canvas, {
|
|
133
141
|
series: [
|
|
134
|
-
{ name: 'Packets', color: '#f07167'
|
|
142
|
+
{ name: 'Packets', color: '#f07167' },
|
|
135
143
|
{ name: 'Errors', color: '#ffb454', dash: [6, 3] },
|
|
136
144
|
],
|
|
145
|
+
pointRadius: 3.5,
|
|
137
146
|
maxPoints: 5000,
|
|
138
147
|
autoDraw: true,
|
|
139
148
|
});
|
|
@@ -145,18 +154,33 @@ const chart = new ScatterChart(canvas, {
|
|
|
145
154
|
|
|
146
155
|
Every data method takes a **series index** as the first argument. `setMaxPoints()`, `clear()`, and `draw()` operate on all series.
|
|
147
156
|
|
|
148
|
-
| Method | Signature
|
|
149
|
-
| -------------- |
|
|
150
|
-
| `setData` | `(seriesIndex, x: Float64Array, y: Float64Array)`
|
|
151
|
-
| `append` | `(seriesIndex, x: number, y: number)`
|
|
152
|
-
| `appendBatch` | `(seriesIndex, xs: ArrayLike<number>, ys: ArrayLike<number>)`
|
|
153
|
-
| `setMaxPoints` | `(maxPoints: number)`
|
|
154
|
-
| `clear` | `()`
|
|
155
|
-
| `draw` | `()`
|
|
156
|
-
| `suspendDraw` | `()`
|
|
157
|
-
| `resumeDraw` | `()`
|
|
158
|
-
| `toImage` | `()`
|
|
159
|
-
| `destroy` | `()`
|
|
157
|
+
| Method | Signature | Description |
|
|
158
|
+
| -------------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
159
|
+
| `setData` | `(seriesIndex, x: Float64Array, y: Float64Array, ownership?: 'copy' \| 'borrowed')` | Snapshot: replace a series. O(n) extent. Ownership: `'copy'` (default, safe) copies arrays; `'borrowed'` keeps caller's reference (must be treated as immutable). |
|
|
160
|
+
| `append` | `(seriesIndex, x: number, y: number)` | Ring: append one point. O(1) amortized. |
|
|
161
|
+
| `appendBatch` | `(seriesIndex, xs: ArrayLike<number>, ys: ArrayLike<number>)` | Ring: append a batch. O(k). |
|
|
162
|
+
| `setMaxPoints` | `(maxPoints: number)` | Resize the streaming window for all series. |
|
|
163
|
+
| `clear` | `()` | Empty all series and reset the grid domain. |
|
|
164
|
+
| `draw` | `()` | Manual paint. No-op when clean and no crosshair. |
|
|
165
|
+
| `suspendDraw` | `()` | Pause rAF-coalesced drawing. Nestable — pair with `resumeDraw()`. |
|
|
166
|
+
| `resumeDraw` | `()` | Resume after matching `suspendDraw()`. Draws immediately if dirty. |
|
|
167
|
+
| `toImage` | `()` | Export the canvas as a PNG data URL. |
|
|
168
|
+
| `destroy` | `()` | Detach observers, release buffers. |
|
|
169
|
+
|
|
170
|
+
### Ownership (`copy` vs `borrowed`)
|
|
171
|
+
|
|
172
|
+
`setData` accepts an optional fourth argument to control data ownership:
|
|
173
|
+
|
|
174
|
+
- **`'copy'`** (default) — the chart copies your arrays into fresh buffers. You may reuse or mutate the originals freely after the call. This is the safe default.
|
|
175
|
+
- **`'borrowed'`** — the chart keeps your arrays by reference to avoid allocation. The caller **must** treat the arrays as immutable for as long as the chart holds them; mutating them externally leads to undefined behaviour.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// Safe default — caller can mutate the originals later
|
|
179
|
+
chart.setData(0, x, y);
|
|
180
|
+
|
|
181
|
+
// Zero-copy — caller must not mutate x or y after this call
|
|
182
|
+
chart.setData(0, x, y, 'borrowed');
|
|
183
|
+
```
|
|
160
184
|
|
|
161
185
|
### Read-only properties
|
|
162
186
|
|
|
@@ -335,13 +359,13 @@ flat regardless of window size.
|
|
|
335
359
|
Pre-built `DARK` and `LIGHT` colour presets ready to spread over constructor options.
|
|
336
360
|
|
|
337
361
|
```ts
|
|
338
|
-
import { LineChart, DARK, LIGHT } from 'goro-charts'
|
|
362
|
+
import { LineChart, DARK, LIGHT } from 'goro-charts';
|
|
339
363
|
|
|
340
364
|
// Dark (default) — explicit
|
|
341
|
-
new LineChart(canvas, { ...DARK, series: [...] })
|
|
365
|
+
new LineChart(canvas, { ...DARK, series: [/* ... */] });
|
|
342
366
|
|
|
343
367
|
// Light theme
|
|
344
|
-
new LineChart(canvas, { ...LIGHT, series: [...] })
|
|
368
|
+
new LineChart(canvas, { ...LIGHT, series: [/* ... */] });
|
|
345
369
|
```
|
|
346
370
|
|
|
347
371
|
---
|
|
@@ -402,9 +426,7 @@ tooltips, update framework state, or pipe values into external widgets.
|
|
|
402
426
|
|
|
403
427
|
```ts
|
|
404
428
|
chart.onHover = (hits) => {
|
|
405
|
-
myTooltipEl.innerHTML = hits
|
|
406
|
-
.map((h) => `${h.label}: ${h.yVal.toFixed(1)}`)
|
|
407
|
-
.join('<br>');
|
|
429
|
+
myTooltipEl.innerHTML = hits.map((h) => `${h.label}: ${h.yVal.toFixed(1)}`).join('<br>');
|
|
408
430
|
};
|
|
409
431
|
```
|
|
410
432
|
|
|
@@ -454,6 +476,7 @@ outside the canvas.
|
|
|
454
476
|
## Troubleshooting
|
|
455
477
|
|
|
456
478
|
### Canvas is blank / black
|
|
479
|
+
|
|
457
480
|
- Ensure the canvas element has non-zero CSS width and height.
|
|
458
481
|
- Check that `chart.draw()` is being called after `setData()` (or enable
|
|
459
482
|
`autoDraw` for streaming mode).
|
|
@@ -462,23 +485,27 @@ outside the canvas.
|
|
|
462
485
|
visible.
|
|
463
486
|
|
|
464
487
|
### "Canvas 2D context not available"
|
|
488
|
+
|
|
465
489
|
- This error means `canvas.getContext('2d')` returned `null`. Common causes:
|
|
466
490
|
- The canvas element does not exist in the DOM at construction time.
|
|
467
491
|
- The canvas was already claimed by a WebGL context.
|
|
468
492
|
- You are running in a server-side environment (Node.js without `node-canvas`).
|
|
469
493
|
|
|
470
494
|
### "append() requires the chart to be created with { maxPoints }"
|
|
495
|
+
|
|
471
496
|
- Streaming methods (`append`, `appendBatch`) require ring mode, which is
|
|
472
497
|
activated by passing `maxPoints` (a positive number) to the constructor.
|
|
473
498
|
- Use `setData()` for snapshot mode (full replacement).
|
|
474
499
|
|
|
475
500
|
### Crosshair does not appear
|
|
501
|
+
|
|
476
502
|
- The crosshair only shows when the mouse is inside the plot area (the inner
|
|
477
503
|
rectangle after padding is applied).
|
|
478
504
|
- Check that `onHover` or mouse events are not being consumed by an overlay
|
|
479
505
|
element above the canvas.
|
|
480
506
|
|
|
481
507
|
### Performance is slow with many points
|
|
508
|
+
|
|
482
509
|
- Verify that decimation is working: the line/area renderers auto-switch to
|
|
483
510
|
per-pixel-column decimation when `count > 2 × plotWidth`.
|
|
484
511
|
- For scatter charts, reduce `maxDots` (default 2000) or set it to a lower
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { SeriesStore } from '../data/series-store.js';
|
|
22
22
|
import { Surface } from '../render/surface.js';
|
|
23
|
-
import type { ChartOpts, ResolvedOpts, SeriesConfig, SeriesView, PlotRect } from '../types.js';
|
|
23
|
+
import type { ChartOpts, ResolvedOpts, SeriesConfig, SeriesView, PlotRect, DataOwnership } from '../types.js';
|
|
24
24
|
import type { SeriesHit } from '../render/crosshair.js';
|
|
25
25
|
/** Abstract base for all chart types. */
|
|
26
26
|
export declare abstract class ChartBase {
|
|
@@ -39,10 +39,17 @@ export declare abstract class ChartBase {
|
|
|
39
39
|
*/
|
|
40
40
|
private stackGroupsAll;
|
|
41
41
|
private stackGroupsByAxis;
|
|
42
|
+
/**
|
|
43
|
+
* Tracks stack-misalignment warnings already emitted, so a misaligned group
|
|
44
|
+
* warns once instead of on every frame (accumulateStackGroup runs per draw).
|
|
45
|
+
*/
|
|
46
|
+
private stackWarned;
|
|
42
47
|
private dirty;
|
|
43
48
|
private cursorX;
|
|
44
49
|
private cursorY;
|
|
45
50
|
private showCrosshair;
|
|
51
|
+
/** Logical index of the keyboard-cursor point in the reference series. */
|
|
52
|
+
private cursorLogical;
|
|
46
53
|
private autoDraw;
|
|
47
54
|
private rafScheduled;
|
|
48
55
|
private suspendCount;
|
|
@@ -50,6 +57,13 @@ export declare abstract class ChartBase {
|
|
|
50
57
|
private resizeObserver;
|
|
51
58
|
protected destroyed: boolean;
|
|
52
59
|
private liveRegion;
|
|
60
|
+
/**
|
|
61
|
+
* Reference to the `prefers-reduced-motion` MQL plus its change listener.
|
|
62
|
+
* Check `reducedMotionMql.matches` to test the preference; the listener
|
|
63
|
+
* triggers a re-draw when the preference changes at runtime.
|
|
64
|
+
*/
|
|
65
|
+
private reducedMotionMql;
|
|
66
|
+
private readonly handleReducedMotionChange;
|
|
53
67
|
private readonly handleResize;
|
|
54
68
|
private readonly handleMouseMove;
|
|
55
69
|
private readonly handleMouseLeave;
|
|
@@ -62,9 +76,15 @@ export declare abstract class ChartBase {
|
|
|
62
76
|
private validateOpts;
|
|
63
77
|
/**
|
|
64
78
|
* Detect system accessibility preferences and adjust visual styles.
|
|
65
|
-
* - prefers-reduced-motion →
|
|
79
|
+
* - prefers-reduced-motion → tracked via `reducedMotionMql.matches`
|
|
80
|
+
* (streaming/rAF continue normally; read the flag to suppress future
|
|
81
|
+
* transitions/animations)
|
|
66
82
|
* - prefers-contrast: more → increase colour opacity
|
|
67
83
|
* - forced-colors: active → use system CSS system colours
|
|
84
|
+
*
|
|
85
|
+
* Also registers a `change` listener on the reduced-motion MQL so the
|
|
86
|
+
* preference is re-evaluated at runtime. The listener is removed in
|
|
87
|
+
* {@link destroy}.
|
|
68
88
|
*/
|
|
69
89
|
private applySystemTheme;
|
|
70
90
|
/**
|
|
@@ -77,10 +97,21 @@ export declare abstract class ChartBase {
|
|
|
77
97
|
* Called once per static redraw.
|
|
78
98
|
*/
|
|
79
99
|
private updateAriaLabel;
|
|
100
|
+
/**
|
|
101
|
+
* Return the first non-empty series index, or -1 when all stores are empty.
|
|
102
|
+
* Used as the reference for keyboard navigation — the cursor advances by
|
|
103
|
+
* logical point indices of this series and the crosshair position is derived
|
|
104
|
+
* from its X value at the current logical index.
|
|
105
|
+
*/
|
|
106
|
+
private referenceSeriesIndex;
|
|
80
107
|
/**
|
|
81
108
|
* Handle keyboard navigation for the crosshair.
|
|
82
109
|
* - ArrowLeft / ArrowRight: move crosshair by 1 point (Shift: 10 points)
|
|
83
110
|
* - Escape: hide crosshair
|
|
111
|
+
*
|
|
112
|
+
* Navigation is anchored to the logical index of the first non-empty series
|
|
113
|
+
* (see {@link referenceSeriesIndex}). The pixel position is derived from the
|
|
114
|
+
* point's X value via the grid domain so the cursor tracks data, not pixels.
|
|
84
115
|
*/
|
|
85
116
|
private onKeyDown;
|
|
86
117
|
/** Reusable crosshair-sync helpers used by both mouse and keyboard handlers. */
|
|
@@ -91,27 +122,28 @@ export declare abstract class ChartBase {
|
|
|
91
122
|
/**
|
|
92
123
|
* Snapshot mode: replace the series at `index` (O(n) extent).
|
|
93
124
|
* @param index - Series index (0-based)
|
|
94
|
-
* @param x - X values, must be monotonically increasing
|
|
95
|
-
* @param y - Y values,
|
|
96
|
-
* @
|
|
125
|
+
* @param x - X values, must be finite and monotonically increasing
|
|
126
|
+
* @param y - Y values, may contain NaN (reserved for gaps v1.6.0); non-finite other than NaN is rejected
|
|
127
|
+
* @param ownership - `'copy'` (default): store copies the arrays; `'borrowed'`: store keeps caller's arrays by reference (must be treated as immutable)
|
|
128
|
+
* @throws {Error} if `index` is out of range, length mismatch, empty, non-finite X, or non-monotonic X
|
|
97
129
|
*/
|
|
98
|
-
setData(index: number, x: Float64Array<ArrayBufferLike>, y: Float64Array<ArrayBufferLike
|
|
130
|
+
setData(index: number, x: Float64Array<ArrayBufferLike>, y: Float64Array<ArrayBufferLike>, ownership?: DataOwnership): void;
|
|
99
131
|
/**
|
|
100
132
|
* Ring mode: append one sample to series `index`.
|
|
101
133
|
* @param index - Series index (0-based)
|
|
102
|
-
* @param x - X value (must be monotonically increasing)
|
|
103
|
-
* @param y - Y value
|
|
134
|
+
* @param x - X value (must be finite and monotonically increasing)
|
|
135
|
+
* @param y - Y value (NaN is allowed — reserved for gaps v1.6.0)
|
|
104
136
|
* @throws {Error} if ring mode is not active (maxPoints not set)
|
|
105
|
-
* @throws {Error} if `index` is out of range
|
|
137
|
+
* @throws {Error} if `index` is out of range, x is not finite, x is non-monotonic, or y is non-finite (NaN allowed)
|
|
106
138
|
*/
|
|
107
139
|
append(index: number, x: number, y: number): void;
|
|
108
140
|
/**
|
|
109
141
|
* Ring mode: append a batch of samples to series `index`.
|
|
110
142
|
* @param index - Series index (0-based)
|
|
111
|
-
* @param xs - X values (must be monotonically increasing)
|
|
112
|
-
* @param ys - Y values
|
|
143
|
+
* @param xs - X values (must be finite and monotonically increasing)
|
|
144
|
+
* @param ys - Y values (NaN is allowed — reserved for gaps v1.6.0)
|
|
113
145
|
* @throws {Error} if ring mode is not active
|
|
114
|
-
* @throws {Error} if `index` is out of range or
|
|
146
|
+
* @throws {Error} if `index` is out of range, length mismatch, non-finite X, non-monotonic X, or non-finite Y (NaN allowed)
|
|
115
147
|
*/
|
|
116
148
|
appendBatch(index: number, xs: ArrayLike<number>, ys: ArrayLike<number>): void;
|
|
117
149
|
/**
|
|
@@ -125,10 +157,20 @@ export declare abstract class ChartBase {
|
|
|
125
157
|
/** Number of series configured. */
|
|
126
158
|
get seriesCount(): number;
|
|
127
159
|
/**
|
|
128
|
-
* Total points
|
|
129
|
-
* Useful
|
|
160
|
+
* Total points currently in the window across all series (before decimation).
|
|
161
|
+
* Useful as a high-level data-volume indicator.
|
|
130
162
|
*/
|
|
131
|
-
get
|
|
163
|
+
get windowPointCount(): number;
|
|
164
|
+
/**
|
|
165
|
+
* Estimated number of line segments actually drawn in the last render.
|
|
166
|
+
* When a series has more than 2×plotW points, the renderer decimates to
|
|
167
|
+
* ~2·plotW per-pixel-column segments (the `dense` regime). This property
|
|
168
|
+
* mirrors that rule so you can verify decimation is active.
|
|
169
|
+
*
|
|
170
|
+
* Returns an upper bound (the real hardware draw count may be slightly
|
|
171
|
+
* lower due to degenerate columns) — sufficient for debug/monitoring.
|
|
172
|
+
*/
|
|
173
|
+
get drawnPointCount(): number;
|
|
132
174
|
/**
|
|
133
175
|
* Number of points currently in the window for series `index`.
|
|
134
176
|
* @param index - Series index (0-based)
|
|
@@ -169,6 +211,12 @@ export declare abstract class ChartBase {
|
|
|
169
211
|
* @param other - Another chart instance to sync with
|
|
170
212
|
*/
|
|
171
213
|
sync(other: ChartBase): void;
|
|
214
|
+
/**
|
|
215
|
+
* Remove bidirectional crosshair sync previously established with `other`.
|
|
216
|
+
* No-op if the two charts were not synced.
|
|
217
|
+
* @param other - Another chart instance to unsync from
|
|
218
|
+
*/
|
|
219
|
+
unsync(other: ChartBase): void;
|
|
172
220
|
/**
|
|
173
221
|
* External callback for hover events. Called on `mousemove` with the
|
|
174
222
|
* interpolated data for every visible series. Use to build custom DOM
|
|
@@ -200,8 +248,23 @@ export declare abstract class ChartBase {
|
|
|
200
248
|
*/
|
|
201
249
|
private computeAllStackGroups;
|
|
202
250
|
/**
|
|
203
|
-
*
|
|
204
|
-
*
|
|
251
|
+
* Validate that all series within each stack group share the same axis.
|
|
252
|
+
* Runs once in the constructor — axis assignment is immutable after that.
|
|
253
|
+
* Data-length alignment is validated separately at draw time in
|
|
254
|
+
* {@link accumulateStackGroup}, since counts change as data arrives.
|
|
255
|
+
* Warns in development — mixed-axis stacking produces incorrect output.
|
|
256
|
+
*/
|
|
257
|
+
private validateStackGroups;
|
|
258
|
+
/**
|
|
259
|
+
* Compute accumulated Y values across a stack group, separating positive
|
|
260
|
+
* and negative contributions.
|
|
261
|
+
*
|
|
262
|
+
* Positive values accumulate upward from 0 (`posCum`); negative values
|
|
263
|
+
* accumulate downward from 0 (`negCum`). This prevents positive and negative
|
|
264
|
+
* series from cancelling each other in the same accumulation track.
|
|
265
|
+
*
|
|
266
|
+
* Returns `{ posCum, negCum }` where each is `null` when no value of that
|
|
267
|
+
* sign exists, or the cumulative `Float64Array` (length = n).
|
|
205
268
|
*/
|
|
206
269
|
private accumulateStackGroup;
|
|
207
270
|
/**
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*
|
|
10
10
|
* The store is purely about data: it never touches the canvas or scheduling.
|
|
11
11
|
*/
|
|
12
|
-
import type { SeriesView } from '../types.js';
|
|
12
|
+
import type { SeriesView, DataOwnership } from '../types.js';
|
|
13
13
|
/** Owns the series data and computes/caches its extents. */
|
|
14
14
|
export declare class SeriesStore implements SeriesView {
|
|
15
15
|
xArr: Float64Array<ArrayBufferLike>;
|
|
@@ -32,19 +32,36 @@ export declare class SeriesStore implements SeriesView {
|
|
|
32
32
|
/**
|
|
33
33
|
* Snapshot mode: replace the whole series. Extents computed once in O(n).
|
|
34
34
|
* Disables any active ring mode.
|
|
35
|
+
*
|
|
36
|
+
* By default (`ownership: 'copy'`) the store copies the caller's arrays into
|
|
37
|
+
* fresh buffers — the caller may mutate the originals freely after the call.
|
|
38
|
+
* Pass `'borrowed'` to keep the caller's arrays by reference (must be treated
|
|
39
|
+
* as immutable for as long as the chart holds them).
|
|
40
|
+
*
|
|
35
41
|
* @throws {Error} if x and y have different lengths
|
|
36
42
|
* @throws {Error} if x is empty
|
|
43
|
+
* @throws {Error} if any x value is not finite, or x is not monotonically increasing
|
|
44
|
+
* @throws {Error} if any y value is not finite (NaN in Y is allowed — reserved for gaps v1.6.0)
|
|
37
45
|
*/
|
|
38
|
-
setData(x: Float64Array<ArrayBufferLike>, y: Float64Array<ArrayBufferLike
|
|
46
|
+
setData(x: Float64Array<ArrayBufferLike>, y: Float64Array<ArrayBufferLike>, ownership?: DataOwnership): void;
|
|
39
47
|
/**
|
|
40
48
|
* Ring mode: append one sample (x must be monotonically increasing).
|
|
41
49
|
* @throws {Error} if ring mode is not active (maxPoints not set)
|
|
50
|
+
* @throws {Error} if x is not finite
|
|
51
|
+
* @throws {Error} if x is < last x (not monotonically increasing)
|
|
52
|
+
* @throws {Error} if y is not finite (NaN in Y is allowed — reserved for gaps v1.6.0)
|
|
42
53
|
*/
|
|
43
54
|
append(x: number, y: number): void;
|
|
44
55
|
/**
|
|
45
56
|
* Ring mode: append a batch of parallel samples. O(k).
|
|
57
|
+
*
|
|
58
|
+
* The entire batch is validated before any sample is pushed, so a partial
|
|
59
|
+
* batch never corrupts the ring.
|
|
60
|
+
*
|
|
46
61
|
* @throws {Error} if ring mode is not active
|
|
47
62
|
* @throws {Error} if xs and ys have different lengths
|
|
63
|
+
* @throws {Error} if any x is not finite, or xs are not monotonically increasing
|
|
64
|
+
* @throws {Error} if any y is not finite (NaN in Y is allowed — reserved for gaps v1.6.0)
|
|
48
65
|
*/
|
|
49
66
|
appendBatch(xs: ArrayLike<number>, ys: ArrayLike<number>): void;
|
|
50
67
|
/** Resize the streaming window, keeping the most recent samples. */
|
|
@@ -55,6 +72,12 @@ export declare class SeriesStore implements SeriesView {
|
|
|
55
72
|
get lastValue(): number;
|
|
56
73
|
physOf(logical: number): number;
|
|
57
74
|
bracketLogical(target: number): number;
|
|
75
|
+
/**
|
|
76
|
+
* Validate snapshot data before accepting it into the store.
|
|
77
|
+
* Checks length, non-empty, finite + monotonic X, and finite Y.
|
|
78
|
+
* @throws {Error} with position-aware message on any violation.
|
|
79
|
+
*/
|
|
80
|
+
private validateSnapshot;
|
|
58
81
|
private requireRing;
|
|
59
82
|
/** Point the store's logical window at the ring's physical storage. */
|
|
60
83
|
private bindRing;
|
package/dist/defaults.d.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* is a sentinel meaning "snapshot mode" (no ring); the constructor activates
|
|
7
7
|
* ring mode only when the user passes a positive value.
|
|
8
8
|
*
|
|
9
|
-
* `yMin:
|
|
10
|
-
*
|
|
9
|
+
* `yMin: undefined / yMax: undefined` — the grid domain expands from data
|
|
10
|
+
* automatically. Set a number to pin the bound; `0` is a legitimate bound.
|
|
11
11
|
*/
|
|
12
12
|
import type { ResolvedOpts } from './types.js';
|
|
13
13
|
export declare const CHART_DEFAULTS: ResolvedOpts;
|