@pond-ts/charts 0.55.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/dist/yticks.d.ts CHANGED
@@ -17,4 +17,48 @@
17
17
  * nice 1-2-5 values near it, so a larger count on a tall row is exactly right.
18
18
  */
19
19
  export declare function resolveYTickCount(height: number, explicit?: number | undefined): number;
20
+ /** The slice of a scale {@link yTickValues} reads. */
21
+ interface TickableScale {
22
+ ticks(count?: number): number[];
23
+ domain(): number[];
24
+ /** Present on d3's `scaleLog` and on no other continuous scale. */
25
+ base?: () => number;
26
+ }
27
+ /**
28
+ * The y tick **values** a `<YAxis>`'s labels and the row's gridlines draw —
29
+ * the one list, so a label and its gridline stay on the same instants.
30
+ *
31
+ * On a linear scale this is just `scale.ticks(count)`, whose 1-2-5 selection
32
+ * treats the count as a target. **On a log scale it cannot be**, because d3's
33
+ * `scaleLog.ticks(count)` is not a target at all — it is nearly a step
34
+ * function, and the jump is catastrophic. Measured against a real seven-decade
35
+ * domain (ESnet's traffic history, 1.9e10 → 2.6e17 bytes):
36
+ *
37
+ * | `count` | ticks returned |
38
+ * | ------- | -------------- |
39
+ * | 4 | 3 (every *other* decade — 1e12, 1e14, 1e16) |
40
+ * | 6 | 7 (every decade — the one right answer) |
41
+ * | 8 | **64** (every 2,3,…9 × decade) |
42
+ *
43
+ * Since the count is height-derived (`height / 48`), that means a 260px row
44
+ * silently labels 3 of 7 decades and a 400px row draws 64 gridlines and 64
45
+ * labels — a 40px resize flipping between them. Neither is a rendering nicety;
46
+ * both are unreadable.
47
+ *
48
+ * So for a log scale we pick the decades ourselves: every `k`th power of ten,
49
+ * with `k` the smallest step whose tick count fits the budget. That is what a
50
+ * log plot is conventionally gridded on, it degrades predictably as the row
51
+ * shrinks, and it never explodes.
52
+ *
53
+ * Below two decades of span there aren't enough powers of ten to grid with, and
54
+ * d3's within-decade selection (2,3,…9 × 10ⁿ) is the right answer and is well
55
+ * behaved — so that case defers to the scale.
56
+ *
57
+ * Log detection is structural: `base()` exists on `scaleLog` and on no other
58
+ * continuous scale. The alternative is threading the axis kind down to the
59
+ * gridline site, which has no `AxisSpec` in scope — the same localized-shape
60
+ * approach `resolveBarBaseline` takes to read `.domain()`.
61
+ */
62
+ export declare function yTickValues(scale: TickableScale, count: number): number[];
63
+ export {};
20
64
  //# sourceMappingURL=yticks.d.ts.map
package/dist/yticks.js CHANGED
@@ -25,4 +25,59 @@ export function resolveYTickCount(height, explicit) {
25
25
  return Math.max(1, Math.floor(explicit));
26
26
  return Math.max(2, Math.floor(height / Y_TICK_PX));
27
27
  }
28
+ /**
29
+ * The y tick **values** a `<YAxis>`'s labels and the row's gridlines draw —
30
+ * the one list, so a label and its gridline stay on the same instants.
31
+ *
32
+ * On a linear scale this is just `scale.ticks(count)`, whose 1-2-5 selection
33
+ * treats the count as a target. **On a log scale it cannot be**, because d3's
34
+ * `scaleLog.ticks(count)` is not a target at all — it is nearly a step
35
+ * function, and the jump is catastrophic. Measured against a real seven-decade
36
+ * domain (ESnet's traffic history, 1.9e10 → 2.6e17 bytes):
37
+ *
38
+ * | `count` | ticks returned |
39
+ * | ------- | -------------- |
40
+ * | 4 | 3 (every *other* decade — 1e12, 1e14, 1e16) |
41
+ * | 6 | 7 (every decade — the one right answer) |
42
+ * | 8 | **64** (every 2,3,…9 × decade) |
43
+ *
44
+ * Since the count is height-derived (`height / 48`), that means a 260px row
45
+ * silently labels 3 of 7 decades and a 400px row draws 64 gridlines and 64
46
+ * labels — a 40px resize flipping between them. Neither is a rendering nicety;
47
+ * both are unreadable.
48
+ *
49
+ * So for a log scale we pick the decades ourselves: every `k`th power of ten,
50
+ * with `k` the smallest step whose tick count fits the budget. That is what a
51
+ * log plot is conventionally gridded on, it degrades predictably as the row
52
+ * shrinks, and it never explodes.
53
+ *
54
+ * Below two decades of span there aren't enough powers of ten to grid with, and
55
+ * d3's within-decade selection (2,3,…9 × 10ⁿ) is the right answer and is well
56
+ * behaved — so that case defers to the scale.
57
+ *
58
+ * Log detection is structural: `base()` exists on `scaleLog` and on no other
59
+ * continuous scale. The alternative is threading the axis kind down to the
60
+ * gridline site, which has no `AxisSpec` in scope — the same localized-shape
61
+ * approach `resolveBarBaseline` takes to read `.domain()`.
62
+ */
63
+ export function yTickValues(scale, count) {
64
+ if (typeof scale.base !== 'function')
65
+ return scale.ticks(count);
66
+ const domain = scale.domain();
67
+ const lo = Math.min(domain[0], domain[domain.length - 1]);
68
+ const hi = Math.max(domain[0], domain[domain.length - 1]);
69
+ if (!(lo > 0) || !(hi > lo))
70
+ return scale.ticks(count);
71
+ const first = Math.ceil(Math.log10(lo));
72
+ const last = Math.floor(Math.log10(hi));
73
+ const decades = last - first + 1;
74
+ if (decades < 2)
75
+ return scale.ticks(count);
76
+ const budget = Math.max(2, count);
77
+ const step = Math.max(1, Math.ceil(decades / budget));
78
+ const out = [];
79
+ for (let e = first; e <= last; e += step)
80
+ out.push(10 ** e);
81
+ return out;
82
+ }
28
83
  //# sourceMappingURL=yticks.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/charts",
3
- "version": "0.55.0",
3
+ "version": "0.56.2",
4
4
  "private": false,
5
5
  "description": "Canvas-rendered, streaming-first time-series charts for pond-ts",
6
6
  "license": "MIT",
@@ -38,8 +38,8 @@
38
38
  "perf": "PERF_BENCH=1 playwright test perf.spec.ts --workers=1"
39
39
  },
40
40
  "peerDependencies": {
41
- "@pond-ts/react": "^0.55.0",
42
- "pond-ts": "^0.55.0",
41
+ "@pond-ts/react": "^0.56.2",
42
+ "pond-ts": "^0.56.2",
43
43
  "react": "^18.0.0 || ^19.0.0"
44
44
  },
45
45
  "devDependencies": {