@fundar/data-chart-telling 0.0.43 → 0.0.44
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.
|
@@ -32,20 +32,53 @@
|
|
|
32
32
|
const xValues = $derived(data.map(getX));
|
|
33
33
|
const yValues = $derived(data.map(getY));
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
function naturalTickCount(span: number, spacing: number, min: number): number {
|
|
36
|
+
return Math.max(min, Math.round(span / spacing));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** `[min, max]` of a pinned `scale.domain` (if numeric), else the extent of `values`. */
|
|
40
|
+
function axisExtent(scale: AxisBasedScalesConfig<TData>['x'], values: AxisValue[]): [number, number] | undefined {
|
|
41
|
+
const domainNumbers = scale?.domain?.filter((d): d is number => typeof d === 'number');
|
|
42
|
+
const source = domainNumbers && domainNumbers.length >= 2 ? domainNumbers : values.filter((v): v is number => typeof v === 'number');
|
|
43
|
+
if (source.length < 2) return undefined;
|
|
44
|
+
const lo = Math.min(...source);
|
|
45
|
+
const hi = Math.max(...source);
|
|
46
|
+
return hi > lo ? [lo, hi] : undefined;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Caps tick count to the axis's distinct value count, never above what fits the pixel span. Skipped once the caller sets tick density directly, or pins the domain. */
|
|
36
50
|
function autoTickCount(scale: AxisBasedScalesConfig<TData>['x'], values: AxisValue[], span: number, spacing: number, min: number): number | undefined {
|
|
37
|
-
if (scale?.ticks != null || scale?.tickSpacing != null || scale?.interval != null) return undefined;
|
|
51
|
+
if (scale?.ticks != null || scale?.tickSpacing != null || scale?.interval != null || scale?.domain != null) return undefined;
|
|
38
52
|
const uniqueCount = new Set(values.map(String)).size;
|
|
39
|
-
const natural =
|
|
53
|
+
const natural = naturalTickCount(span, spacing, min);
|
|
40
54
|
return uniqueCount >= 2 && uniqueCount < natural ? uniqueCount : undefined;
|
|
41
55
|
}
|
|
42
56
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
57
|
+
/** Forces a whole-unit tick interval on an integer domain that spans fewer integers than the pixel span would naturally want ticks for. */
|
|
58
|
+
function integerTickInterval(
|
|
59
|
+
scale: AxisBasedScalesConfig<TData>['x'],
|
|
60
|
+
values: AxisValue[],
|
|
61
|
+
span: number,
|
|
62
|
+
spacing: number,
|
|
63
|
+
min: number
|
|
64
|
+
): number | undefined {
|
|
65
|
+
if (scale?.ticks != null || scale?.tickSpacing != null || scale?.interval != null) return undefined;
|
|
66
|
+
if (scale?.type != null && scale.type !== 'linear' && scale.type !== 'auto') return undefined;
|
|
67
|
+
const extent = axisExtent(scale, values);
|
|
68
|
+
if (!extent) return undefined;
|
|
69
|
+
const [lo, hi] = extent;
|
|
70
|
+
if (!Number.isInteger(lo) || !Number.isInteger(hi)) return undefined;
|
|
71
|
+
return hi - lo < naturalTickCount(span, spacing, min) ? 1 : undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const xSpan = $derived(Math.max(0, width - numericMargins.left - numericMargins.right));
|
|
75
|
+
const ySpan = $derived(Math.max(0, height - numericMargins.top - numericMargins.bottom));
|
|
76
|
+
|
|
77
|
+
const xTickCount = $derived(autoTickCount(scales?.x, xValues, xSpan, 80, 3));
|
|
78
|
+
const yTickCount = $derived(autoTickCount(scales?.y, yValues, ySpan, 50, 2));
|
|
79
|
+
|
|
80
|
+
const xTickInterval = $derived(integerTickInterval(scales?.x, xValues, xSpan, 80, 3));
|
|
81
|
+
const yTickInterval = $derived(integerTickInterval(scales?.y, yValues, ySpan, 50, 2));
|
|
49
82
|
|
|
50
83
|
/** Vertical Y-axis title placement, when `scales.y.labelOrientation === 'vertical'`. */
|
|
51
84
|
const verticalYLabel = $derived.by(() => {
|
|
@@ -61,6 +94,7 @@
|
|
|
61
94
|
|
|
62
95
|
<AxisX
|
|
63
96
|
tickCount={xTickCount}
|
|
97
|
+
interval={xTickInterval}
|
|
64
98
|
tickSize={scales?.x?.tickSize ?? cfg.axis.xTickSize}
|
|
65
99
|
tickPadding={scales?.x?.tickPadding ?? cfg.axis.xTickPadding}
|
|
66
100
|
tickFontSize={cfg.axis.fontSize}
|
|
@@ -68,6 +102,7 @@
|
|
|
68
102
|
/>
|
|
69
103
|
<AxisY
|
|
70
104
|
tickCount={yTickCount}
|
|
105
|
+
interval={yTickInterval}
|
|
71
106
|
tickSize={scales?.y?.tickSize ?? cfg.axis.yTickSize}
|
|
72
107
|
tickPadding={scales?.y?.tickPadding ?? cfg.axis.yTickPadding}
|
|
73
108
|
tickFontSize={cfg.axis.fontSize}
|