@pond-ts/charts 0.57.0 → 0.59.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/API.md +576 -0
- package/CHANGELOG.md +1213 -1
- package/dist/AreaChart.d.ts +12 -1
- package/dist/AreaChart.js +131 -13
- package/dist/BarChart.d.ts +56 -7
- package/dist/BarChart.js +263 -39
- package/dist/BarList.d.ts +85 -5
- package/dist/BarList.js +25 -4
- package/dist/BoxList.d.ts +70 -3
- package/dist/BoxList.js +21 -7
- package/dist/BoxPlot.d.ts +2 -1
- package/dist/BoxPlot.js +101 -9
- package/dist/Candlestick.d.ts +13 -1
- package/dist/Candlestick.js +89 -3
- package/dist/ChartContainer.d.ts +36 -48
- package/dist/ChartContainer.js +465 -59
- package/dist/ChartRow.d.ts +9 -2
- package/dist/ChartRow.js +176 -14
- package/dist/HeatMap.d.ts +176 -0
- package/dist/HeatMap.js +344 -0
- package/dist/Layers.d.ts +5 -1
- package/dist/Layers.js +1014 -253
- package/dist/Legend.js +8 -4
- package/dist/LineChart.d.ts +18 -1
- package/dist/LineChart.js +165 -4
- package/dist/ListTable.d.ts +30 -3
- package/dist/ListTable.js +381 -23
- package/dist/ScatterChart.d.ts +3 -2
- package/dist/ScatterChart.js +68 -4
- package/dist/XAxis.js +40 -22
- package/dist/YAxis.d.ts +58 -2
- package/dist/YAxis.js +3 -1
- package/dist/area.d.ts +34 -1
- package/dist/area.js +88 -1
- package/dist/bars.d.ts +67 -6
- package/dist/bars.js +250 -35
- package/dist/box.d.ts +2 -2
- package/dist/box.js +158 -40
- package/dist/brush.d.ts +142 -0
- package/dist/brush.js +179 -0
- package/dist/child-index.d.ts +27 -0
- package/dist/child-index.js +57 -0
- package/dist/context.d.ts +870 -39
- package/dist/cursors.d.ts +161 -0
- package/dist/cursors.js +503 -0
- package/dist/data.d.ts +38 -0
- package/dist/data.js +43 -0
- package/dist/decimate.d.ts +78 -1
- package/dist/decimate.js +157 -0
- package/dist/format.d.ts +15 -0
- package/dist/format.js +16 -1
- package/dist/heat.d.ts +163 -0
- package/dist/heat.js +659 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.js +27 -0
- package/dist/line.d.ts +137 -0
- package/dist/line.js +328 -0
- package/dist/ohlc.d.ts +16 -1
- package/dist/ohlc.js +93 -4
- package/dist/range.d.ts +14 -1
- package/dist/range.js +24 -3
- package/dist/scatter.d.ts +17 -9
- package/dist/scatter.js +221 -33
- package/dist/select.d.ts +13 -5
- package/dist/select.js +14 -6
- package/dist/selection-fixtures.d.ts +174 -0
- package/dist/selection-fixtures.js +569 -0
- package/dist/selection-stories.d.ts +73 -0
- package/dist/selection-stories.js +301 -0
- package/dist/selectors.d.ts +316 -0
- package/dist/selectors.js +391 -0
- package/dist/span.d.ts +122 -0
- package/dist/span.js +203 -0
- package/dist/sweep.d.ts +154 -0
- package/dist/sweep.js +282 -0
- package/dist/theme.d.ts +510 -5
- package/dist/theme.js +217 -41
- package/dist/tracker.d.ts +6 -0
- package/dist/tracker.js +6 -0
- package/dist/tradingAxis.fixture.d.ts +78 -0
- package/dist/tradingAxis.fixture.js +215 -0
- package/dist/useChartLegend.js +18 -3
- package/dist/yticks.d.ts +3 -0
- package/dist/yticks.js +104 -0
- package/package.json +6 -5
package/dist/useChartLegend.js
CHANGED
|
@@ -48,8 +48,10 @@ export function buildChartLegend(container, cursor, rowKey) {
|
|
|
48
48
|
label: spec.label,
|
|
49
49
|
swatch: spec.swatch,
|
|
50
50
|
...(spec.id !== undefined ? { id: spec.id } : {}),
|
|
51
|
-
selected: spec.id !== undefined &&
|
|
52
|
-
|
|
51
|
+
selected: spec.id !== undefined &&
|
|
52
|
+
container.selected.some((m) => m.id === spec.id),
|
|
53
|
+
hovered: spec.id !== undefined &&
|
|
54
|
+
container.hovered.some((m) => m.id === spec.id),
|
|
53
55
|
};
|
|
54
56
|
const last = rows[rows.length - 1];
|
|
55
57
|
if (last !== undefined && last.rowKey === spec.rowKey) {
|
|
@@ -79,7 +81,20 @@ export function buildChartLegend(container, cursor, rowKey) {
|
|
|
79
81
|
select: (row) => {
|
|
80
82
|
if (row.id === undefined)
|
|
81
83
|
return;
|
|
82
|
-
|
|
84
|
+
// Toggle: clicking an already-selected row reports `null`, which a
|
|
85
|
+
// consumer reads as "clear".
|
|
86
|
+
//
|
|
87
|
+
// **Known limitation ([PND-MULTISEL]).** With a multi-member set that
|
|
88
|
+
// clears *everything*, not just this row — the callback's vocabulary is
|
|
89
|
+
// one hit, and "remove this one member" has no representation in it. A
|
|
90
|
+
// legend click also carries no modifiers (see below), so ⌘-click-adds
|
|
91
|
+
// can't be driven from a legend either. Both want the legend row to hand
|
|
92
|
+
// over its own event + identity; that is a legend-surface change rather
|
|
93
|
+
// than part of this wave, and is recorded in the plan. Single-selection
|
|
94
|
+
// behaviour — the only shipped behaviour before this — is unchanged.
|
|
95
|
+
container.select(container.selected.some((m) => m.id === row.id)
|
|
96
|
+
? null
|
|
97
|
+
: seriesSelectInfo(row));
|
|
83
98
|
},
|
|
84
99
|
};
|
|
85
100
|
}
|
package/dist/yticks.d.ts
CHANGED
|
@@ -23,6 +23,9 @@ interface TickableScale {
|
|
|
23
23
|
domain(): number[];
|
|
24
24
|
/** Present on d3's `scaleLog` and on no other continuous scale. */
|
|
25
25
|
base?: () => number;
|
|
26
|
+
/** Present on d3's `scaleSymlog` and on no other continuous scale — the
|
|
27
|
+
* linear window's half-width, i.e. the knee ([PND-SYMLOG]). */
|
|
28
|
+
constant?: () => number;
|
|
26
29
|
}
|
|
27
30
|
/**
|
|
28
31
|
* The y tick **values** a `<YAxis>`'s labels and the row's gridlines draw —
|
package/dist/yticks.js
CHANGED
|
@@ -61,6 +61,8 @@ export function resolveYTickCount(height, explicit) {
|
|
|
61
61
|
* approach `resolveBarBaseline` takes to read `.domain()`.
|
|
62
62
|
*/
|
|
63
63
|
export function yTickValues(scale, count) {
|
|
64
|
+
if (typeof scale.constant === 'function')
|
|
65
|
+
return symlogTickValues(scale, count);
|
|
64
66
|
if (typeof scale.base !== 'function')
|
|
65
67
|
return scale.ticks(count);
|
|
66
68
|
const domain = scale.domain();
|
|
@@ -80,4 +82,106 @@ export function yTickValues(scale, count) {
|
|
|
80
82
|
out.push(10 ** e);
|
|
81
83
|
return out;
|
|
82
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Tick values for a **symlog** axis — linear through zero, logarithmic beyond
|
|
87
|
+
* ([PND-SYMLOG]).
|
|
88
|
+
*
|
|
89
|
+
* **This is the feature, not a refinement of it.** d3's `scaleSymlog` supplies
|
|
90
|
+
* the transform but its `ticks()` is `linearish` — evenly spaced in *value*. On
|
|
91
|
+
* a ±1M domain with a 20k knee that yields `-1M, -500k, 0, 500k, 1M`: **nothing
|
|
92
|
+
* at all below the knee**, which is the region a symlog axis exists to reveal.
|
|
93
|
+
* The mapping does spread that region generously (0→250px, 20k→294px,
|
|
94
|
+
* 100k→364px on a 500px range), so such a chart is readable-but-unlabelled —
|
|
95
|
+
* confidently gridded on the one part of the scale that isn't the point. Owning
|
|
96
|
+
* the ladder is therefore inseparable from owning the transform.
|
|
97
|
+
*
|
|
98
|
+
* The ladder, and why each piece is there:
|
|
99
|
+
*
|
|
100
|
+
* - **Zero, always.** It is the axis's centre of symmetry and the one value a
|
|
101
|
+
* symlog scale is chosen to keep visible.
|
|
102
|
+
* - **The knee, ±`constant`.** Where the reading changes from linear to
|
|
103
|
+
* logarithmic. Unlabelled, a reader has no way to know which régime a given
|
|
104
|
+
* gap belongs to, and the same pixel distance means different things either
|
|
105
|
+
* side of it.
|
|
106
|
+
* - **Decades beyond the knee, mirrored.** What a log plot is conventionally
|
|
107
|
+
* gridded on, thinned by the same "every `k`th power of ten" rule the log path
|
|
108
|
+
* above uses, so it degrades predictably as the row shrinks instead of
|
|
109
|
+
* exploding.
|
|
110
|
+
* - **Bounds are NOT labelled.** A data-derived bound is rarely round, so
|
|
111
|
+
* printing it puts an arbitrary number next to a decade — the noise a log grid
|
|
112
|
+
* exists to avoid.
|
|
113
|
+
*
|
|
114
|
+
* Below one decade of span past the knee there is nothing to grid
|
|
115
|
+
* logarithmically, so it defers to `scale.ticks(count)` — which is linear, and
|
|
116
|
+
* correct, because inside the knee symlog *is* linear.
|
|
117
|
+
*
|
|
118
|
+
* **Clip first, then thin — never the other way round.** A pan/zoom (or explicit
|
|
119
|
+
* bounds) can leave a window that contains *none* of the ideal ladder:
|
|
120
|
+
* `[510_000, 990_000]` with a 19_800 knee excludes zero, both knees, and its one
|
|
121
|
+
* candidate decade, so an order that thinned a symmetric ladder and clipped
|
|
122
|
+
* afterwards handed **`[]`** to the labels and the gridlines — an axis with no
|
|
123
|
+
* ticks at all, which reads as a rendering failure rather than as a scale. The
|
|
124
|
+
* budget is likewise spent on what *survives* the domain, not on an ideal
|
|
125
|
+
* two-sided ladder, so an asymmetric window is not thinned as if it were twice
|
|
126
|
+
* its size. If nothing survives, the linear ticks are the honest answer.
|
|
127
|
+
*
|
|
128
|
+
* Detection is structural, matching the log path's use of `base()`: `constant()`
|
|
129
|
+
* exists on `scaleSymlog` and on no other continuous scale.
|
|
130
|
+
*/
|
|
131
|
+
function symlogTickValues(scale, count) {
|
|
132
|
+
const domain = scale.domain();
|
|
133
|
+
const lo = Math.min(domain[0], domain[domain.length - 1]);
|
|
134
|
+
const hi = Math.max(domain[0], domain[domain.length - 1]);
|
|
135
|
+
const knee = Math.abs(scale.constant?.() ?? 1);
|
|
136
|
+
const maxAbs = Math.max(Math.abs(lo), Math.abs(hi));
|
|
137
|
+
// Finiteness is checked, not assumed: an explicit `max={Infinity}` reaches here
|
|
138
|
+
// intact, and `floor(log10(Infinity))` is `Infinity` — which made the decade
|
|
139
|
+
// loop's `e += step` a no-op and hung the render in a `for` that could never
|
|
140
|
+
// end. d3's own linear ticks return `[]` on such a domain, so deferring is both
|
|
141
|
+
// safe and the truthful answer for a domain with no finite extent.
|
|
142
|
+
if (!Number.isFinite(lo) || !Number.isFinite(hi) || !Number.isFinite(knee))
|
|
143
|
+
return scale.ticks(count);
|
|
144
|
+
if (!(knee > 0) || !(maxAbs > knee) || !(hi > lo))
|
|
145
|
+
return scale.ticks(count);
|
|
146
|
+
// The ladder starts at the first decade **at least half a decade above the
|
|
147
|
+
// knee** (`× √10`), not merely above it. `ceil(log10(knee))` alone puts a
|
|
148
|
+
// decade arbitrarily close to the knee tick whenever the knee lands just under
|
|
149
|
+
// a power of ten — a data-derived `maxAbs` of 4.95e6 gives a 99k knee and a
|
|
150
|
+
// 100k decade, two ticks a few pixels apart whose labels round to the *same
|
|
151
|
+
// string*. Since the knee itself is always drawn, dropping that decade loses
|
|
152
|
+
// no information; a chart that prints one number twice at two positions is
|
|
153
|
+
// reporting something false about the scale.
|
|
154
|
+
const firstExp = Math.ceil(Math.log10(knee) + 0.5);
|
|
155
|
+
const lastExp = Math.floor(Math.log10(maxAbs));
|
|
156
|
+
const inDomain = (v) => v >= lo && v <= hi;
|
|
157
|
+
// Zero and ±knee are the fixed part of the ladder — kept whole, never thinned,
|
|
158
|
+
// because they are what distinguishes a symlog axis from a log one.
|
|
159
|
+
const fixed = [0, knee, -knee].filter(inDomain);
|
|
160
|
+
// Every decade past the knee that the domain actually contains, in ascending
|
|
161
|
+
// magnitude, each carrying whichever of ±10^e survived.
|
|
162
|
+
const rungs = [];
|
|
163
|
+
for (let e = firstExp; e <= lastExp; e += 1) {
|
|
164
|
+
const pair = [10 ** e, -(10 ** e)].filter(inDomain);
|
|
165
|
+
if (pair.length > 0)
|
|
166
|
+
rungs.push(pair);
|
|
167
|
+
}
|
|
168
|
+
// No rung survives ⇒ there is no logarithmic region to grid, so the linear
|
|
169
|
+
// ticks are the answer — the same reasoning as the knee-swallows-the-domain
|
|
170
|
+
// guard above, and the case that used to produce an empty axis. Note this also
|
|
171
|
+
// covers a window sitting *between* the knee and the first decade.
|
|
172
|
+
if (rungs.length === 0)
|
|
173
|
+
return scale.ticks(count);
|
|
174
|
+
// Thin the SURVIVING rungs to what is left of the budget after the fixed
|
|
175
|
+
// ticks. Stepping by magnitude keeps a rung's ± pair together, so the grid
|
|
176
|
+
// stays symmetric wherever the domain is.
|
|
177
|
+
const budget = Math.max(2, count);
|
|
178
|
+
const total = rungs.reduce((n, pair) => n + pair.length, 0);
|
|
179
|
+
const room = Math.max(1, budget - fixed.length);
|
|
180
|
+
const step = Math.max(1, Math.ceil(total / room));
|
|
181
|
+
const out = new Set(fixed);
|
|
182
|
+
for (let i = 0; i < rungs.length; i += step)
|
|
183
|
+
for (const v of rungs[i])
|
|
184
|
+
out.add(v);
|
|
185
|
+
return [...out].sort((a, b) => a - b);
|
|
186
|
+
}
|
|
83
187
|
//# sourceMappingURL=yticks.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pond-ts/charts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Canvas-rendered, streaming-first time-series charts for pond-ts",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,11 +24,12 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"dist",
|
|
27
|
-
"CHANGELOG.md"
|
|
27
|
+
"CHANGELOG.md",
|
|
28
|
+
"API.md"
|
|
28
29
|
],
|
|
29
30
|
"scripts": {
|
|
30
31
|
"build": "tsc -p tsconfig.json",
|
|
31
|
-
"prepack": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md && npm run build && cp cjs-fallback.cjs dist/cjs-fallback.cjs && find dist -name '*.map' -delete",
|
|
32
|
+
"prepack": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md && cp ../../API.md ./API.md && npm run build && cp cjs-fallback.cjs dist/cjs-fallback.cjs && find dist -name '*.map' -delete",
|
|
32
33
|
"test": "npm run test:type && npm run test:runtime",
|
|
33
34
|
"test:type": "tsc -p tsconfig.types.json",
|
|
34
35
|
"test:runtime": "vitest run",
|
|
@@ -38,8 +39,8 @@
|
|
|
38
39
|
"perf": "PERF_BENCH=1 playwright test perf.spec.ts --workers=1"
|
|
39
40
|
},
|
|
40
41
|
"peerDependencies": {
|
|
41
|
-
"@pond-ts/react": "^0.
|
|
42
|
-
"pond-ts": "^0.
|
|
42
|
+
"@pond-ts/react": "^0.59.0",
|
|
43
|
+
"pond-ts": "^0.59.0",
|
|
43
44
|
"react": "^18.0.0 || ^19.0.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|