exploreda 0.0.6 → 0.1.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/README.md +144 -0
- package/dist/ExplorEda.cjs +4608 -11288
- package/dist/ExplorEda.cjs.map +1 -1
- package/dist/ExplorEda.css +2282 -1689
- package/dist/ExplorEda.css.map +1 -1
- package/dist/ExplorEda.d.cts +124 -278
- package/dist/ExplorEda.d.ts +124 -278
- package/dist/ExplorEda.js +4479 -11166
- package/dist/ExplorEda.js.map +1 -1
- package/dist/calculations.cjs +18 -0
- package/dist/calculations.cjs.map +1 -0
- package/dist/calculations.d.cts +63 -0
- package/dist/calculations.d.ts +63 -0
- package/dist/calculations.js +3 -0
- package/dist/calculations.js.map +1 -0
- package/dist/charts/bar.cjs +27 -0
- package/dist/charts/bar.cjs.map +1 -0
- package/dist/charts/bar.d.cts +2 -0
- package/dist/charts/bar.d.ts +2 -0
- package/dist/charts/bar.js +18 -0
- package/dist/charts/bar.js.map +1 -0
- package/dist/charts/box-plot.cjs +26 -0
- package/dist/charts/box-plot.cjs.map +1 -0
- package/dist/charts/box-plot.d.cts +2 -0
- package/dist/charts/box-plot.d.ts +2 -0
- package/dist/charts/box-plot.js +17 -0
- package/dist/charts/box-plot.js.map +1 -0
- package/dist/charts/color-legend.cjs +22 -0
- package/dist/charts/color-legend.cjs.map +1 -0
- package/dist/charts/color-legend.d.cts +2 -0
- package/dist/charts/color-legend.d.ts +2 -0
- package/dist/charts/color-legend.js +13 -0
- package/dist/charts/color-legend.js.map +1 -0
- package/dist/charts/data-table.cjs +22 -0
- package/dist/charts/data-table.cjs.map +1 -0
- package/dist/charts/data-table.d.cts +2 -0
- package/dist/charts/data-table.d.ts +2 -0
- package/dist/charts/data-table.js +13 -0
- package/dist/charts/data-table.js.map +1 -0
- package/dist/charts/line.cjs +30 -0
- package/dist/charts/line.cjs.map +1 -0
- package/dist/charts/line.d.cts +2 -0
- package/dist/charts/line.d.ts +2 -0
- package/dist/charts/line.js +17 -0
- package/dist/charts/line.js.map +1 -0
- package/dist/charts/markdown.cjs +16 -0
- package/dist/charts/markdown.cjs.map +1 -0
- package/dist/charts/markdown.css +77 -0
- package/dist/charts/markdown.css.map +1 -0
- package/dist/charts/markdown.d.cts +2 -0
- package/dist/charts/markdown.d.ts +2 -0
- package/dist/charts/markdown.js +7 -0
- package/dist/charts/markdown.js.map +1 -0
- package/dist/charts/pivot-table.cjs +23 -0
- package/dist/charts/pivot-table.cjs.map +1 -0
- package/dist/charts/pivot-table.d.cts +2 -0
- package/dist/charts/pivot-table.d.ts +2 -0
- package/dist/charts/pivot-table.js +14 -0
- package/dist/charts/pivot-table.js.map +1 -0
- package/dist/charts/row.cjs +27 -0
- package/dist/charts/row.cjs.map +1 -0
- package/dist/charts/row.d.cts +6 -0
- package/dist/charts/row.d.ts +6 -0
- package/dist/charts/row.js +18 -0
- package/dist/charts/row.js.map +1 -0
- package/dist/charts/scatter.cjs +24 -0
- package/dist/charts/scatter.cjs.map +1 -0
- package/dist/charts/scatter.d.cts +2 -0
- package/dist/charts/scatter.d.ts +2 -0
- package/dist/charts/scatter.js +15 -0
- package/dist/charts/scatter.js.map +1 -0
- package/dist/charts/summary-table.cjs +19 -0
- package/dist/charts/summary-table.cjs.map +1 -0
- package/dist/charts/summary-table.d.cts +2 -0
- package/dist/charts/summary-table.d.ts +2 -0
- package/dist/charts/summary-table.js +10 -0
- package/dist/charts/summary-table.js.map +1 -0
- package/dist/charts/three-d-scatter.cjs +24 -0
- package/dist/charts/three-d-scatter.cjs.map +1 -0
- package/dist/charts/three-d-scatter.d.cts +6 -0
- package/dist/charts/three-d-scatter.d.ts +6 -0
- package/dist/charts/three-d-scatter.js +15 -0
- package/dist/charts/three-d-scatter.js.map +1 -0
- package/dist/chunk-3PGYFLE3.cjs +499 -0
- package/dist/chunk-3PGYFLE3.cjs.map +1 -0
- package/dist/chunk-4HNDKMWF.js +167 -0
- package/dist/chunk-4HNDKMWF.js.map +1 -0
- package/dist/chunk-4QNENKTV.cjs +1214 -0
- package/dist/chunk-4QNENKTV.cjs.map +1 -0
- package/dist/chunk-54M32JJB.js +132 -0
- package/dist/chunk-54M32JJB.js.map +1 -0
- package/dist/chunk-5B23JVH3.cjs +2238 -0
- package/dist/chunk-5B23JVH3.cjs.map +1 -0
- package/dist/chunk-5LH6NSNL.js +456 -0
- package/dist/chunk-5LH6NSNL.js.map +1 -0
- package/dist/chunk-6DOKKCJ5.cjs +313 -0
- package/dist/chunk-6DOKKCJ5.cjs.map +1 -0
- package/dist/chunk-6HZX5CBT.cjs +1074 -0
- package/dist/chunk-6HZX5CBT.cjs.map +1 -0
- package/dist/chunk-6U5DOIQM.js +1071 -0
- package/dist/chunk-6U5DOIQM.js.map +1 -0
- package/dist/chunk-7GBZIK2R.cjs +80 -0
- package/dist/chunk-7GBZIK2R.cjs.map +1 -0
- package/dist/chunk-7PTJNIOD.js +520 -0
- package/dist/chunk-7PTJNIOD.js.map +1 -0
- package/dist/chunk-AHZYQ7FN.js +319 -0
- package/dist/chunk-AHZYQ7FN.js.map +1 -0
- package/dist/chunk-AOODAOL4.cjs +55 -0
- package/dist/chunk-AOODAOL4.cjs.map +1 -0
- package/dist/chunk-ASKFIRMC.cjs +165 -0
- package/dist/chunk-ASKFIRMC.cjs.map +1 -0
- package/dist/chunk-B7OQUBH4.cjs +171 -0
- package/dist/chunk-B7OQUBH4.cjs.map +1 -0
- package/dist/chunk-BIMEHDLB.js +72 -0
- package/dist/chunk-BIMEHDLB.js.map +1 -0
- package/dist/chunk-C62KHV7S.js +1225 -0
- package/dist/chunk-C62KHV7S.js.map +1 -0
- package/dist/chunk-C7GQT65O.cjs +1119 -0
- package/dist/chunk-C7GQT65O.cjs.map +1 -0
- package/dist/chunk-CGDWDV4Z.js +1211 -0
- package/dist/chunk-CGDWDV4Z.js.map +1 -0
- package/dist/chunk-CJQQFNEY.js +69 -0
- package/dist/chunk-CJQQFNEY.js.map +1 -0
- package/dist/chunk-DHYLSXNR.js +964 -0
- package/dist/chunk-DHYLSXNR.js.map +1 -0
- package/dist/chunk-DKFA4KOJ.cjs +87 -0
- package/dist/chunk-DKFA4KOJ.cjs.map +1 -0
- package/dist/chunk-DS5BS7PP.cjs +357 -0
- package/dist/chunk-DS5BS7PP.cjs.map +1 -0
- package/dist/chunk-EGMFQSGK.js +909 -0
- package/dist/chunk-EGMFQSGK.js.map +1 -0
- package/dist/chunk-EU5EFHO5.cjs +53 -0
- package/dist/chunk-EU5EFHO5.cjs.map +1 -0
- package/dist/chunk-FM46QSDM.js +837 -0
- package/dist/chunk-FM46QSDM.js.map +1 -0
- package/dist/chunk-GV2LRR32.cjs +843 -0
- package/dist/chunk-GV2LRR32.cjs.map +1 -0
- package/dist/chunk-H3XKFSA5.cjs +322 -0
- package/dist/chunk-H3XKFSA5.cjs.map +1 -0
- package/dist/chunk-H5AVMMCE.js +347 -0
- package/dist/chunk-H5AVMMCE.js.map +1 -0
- package/dist/chunk-JDMUN4VK.cjs +986 -0
- package/dist/chunk-JDMUN4VK.cjs.map +1 -0
- package/dist/chunk-JNO7OXCC.js +2171 -0
- package/dist/chunk-JNO7OXCC.js.map +1 -0
- package/dist/chunk-JQMG4ZR7.js +111 -0
- package/dist/chunk-JQMG4ZR7.js.map +1 -0
- package/dist/chunk-L2Q2R43U.cjs +118 -0
- package/dist/chunk-L2Q2R43U.cjs.map +1 -0
- package/dist/chunk-LBTZVERO.js +466 -0
- package/dist/chunk-LBTZVERO.js.map +1 -0
- package/dist/chunk-LUUGGTTK.cjs +1227 -0
- package/dist/chunk-LUUGGTTK.cjs.map +1 -0
- package/dist/chunk-MEEPH7ZC.cjs +911 -0
- package/dist/chunk-MEEPH7ZC.cjs.map +1 -0
- package/dist/chunk-MJPDJ5AS.js +184 -0
- package/dist/chunk-MJPDJ5AS.js.map +1 -0
- package/dist/chunk-MJROUIDZ.cjs +219 -0
- package/dist/chunk-MJROUIDZ.cjs.map +1 -0
- package/dist/chunk-MUWSBYJS.js +528 -0
- package/dist/chunk-MUWSBYJS.js.map +1 -0
- package/dist/chunk-NDF5LCST.js +1088 -0
- package/dist/chunk-NDF5LCST.js.map +1 -0
- package/dist/chunk-NGWTPED4.js +311 -0
- package/dist/chunk-NGWTPED4.js.map +1 -0
- package/dist/chunk-PP4VCONW.js +739 -0
- package/dist/chunk-PP4VCONW.js.map +1 -0
- package/dist/chunk-PRMC2A6P.cjs +488 -0
- package/dist/chunk-PRMC2A6P.cjs.map +1 -0
- package/dist/chunk-PST6UU6S.cjs +742 -0
- package/dist/chunk-PST6UU6S.cjs.map +1 -0
- package/dist/chunk-Q7LK2UWH.js +33 -0
- package/dist/chunk-Q7LK2UWH.js.map +1 -0
- package/dist/chunk-SFV5LZPD.js +162 -0
- package/dist/chunk-SFV5LZPD.js.map +1 -0
- package/dist/chunk-SKXGYJJG.cjs +370 -0
- package/dist/chunk-SKXGYJJG.cjs.map +1 -0
- package/dist/chunk-SWLNKY6R.js +477 -0
- package/dist/chunk-SWLNKY6R.js.map +1 -0
- package/dist/chunk-TGVLNHUB.cjs +483 -0
- package/dist/chunk-TGVLNHUB.cjs.map +1 -0
- package/dist/chunk-TLLRW6S3.js +74 -0
- package/dist/chunk-TLLRW6S3.js.map +1 -0
- package/dist/chunk-TRAIXZ6M.cjs +140 -0
- package/dist/chunk-TRAIXZ6M.cjs.map +1 -0
- package/dist/chunk-U74A5VK5.cjs +74 -0
- package/dist/chunk-U74A5VK5.cjs.map +1 -0
- package/dist/chunk-UAVDLBTA.cjs +74 -0
- package/dist/chunk-UAVDLBTA.cjs.map +1 -0
- package/dist/chunk-UJWS6TRV.js +354 -0
- package/dist/chunk-UJWS6TRV.js.map +1 -0
- package/dist/chunk-UUJMUPB3.cjs +531 -0
- package/dist/chunk-UUJMUPB3.cjs.map +1 -0
- package/dist/chunk-VTKHZIJB.cjs +549 -0
- package/dist/chunk-VTKHZIJB.cjs.map +1 -0
- package/dist/chunk-YXPAWUXO.js +51 -0
- package/dist/chunk-YXPAWUXO.js.map +1 -0
- package/dist/chunk-ZD64SCZB.js +80 -0
- package/dist/chunk-ZD64SCZB.js.map +1 -0
- package/dist/core.cjs +28 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.cts +22 -0
- package/dist/core.d.ts +22 -0
- package/dist/core.js +3 -0
- package/dist/core.js.map +1 -0
- package/dist/dataLayerState-B4XmQjQN.d.cts +258 -0
- package/dist/dataLayerState-B4XmQjQN.d.ts +258 -0
- package/package.json +30 -52
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { scaleSymlog, scaleLinear, scaleBand } from 'd3-scale';
|
|
2
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { useRef, useState } from 'react';
|
|
4
|
+
|
|
5
|
+
// src/components/charts/Axis/numericScale.ts
|
|
6
|
+
function numericScale(axis) {
|
|
7
|
+
return axis?.scaleType === "symlog" ? scaleSymlog() : scaleLinear();
|
|
8
|
+
}
|
|
9
|
+
function describeScale(scale, scaleType) {
|
|
10
|
+
if ("bandwidth" in scale) {
|
|
11
|
+
return {
|
|
12
|
+
type: "band",
|
|
13
|
+
domain: scale.domain(),
|
|
14
|
+
range: scale.range(),
|
|
15
|
+
padding: scale.padding()
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
type: scaleType === "symlog" ? "symlog" : "linear",
|
|
20
|
+
domain: scale.domain(),
|
|
21
|
+
range: scale.range()
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function buildScale(descriptor) {
|
|
25
|
+
if (descriptor.type === "band") {
|
|
26
|
+
return scaleBand().domain(descriptor.domain).range(descriptor.range).padding(descriptor.padding);
|
|
27
|
+
}
|
|
28
|
+
return numericScale({ scaleType: descriptor.type }).domain(descriptor.domain).range(descriptor.range);
|
|
29
|
+
}
|
|
30
|
+
var MIN_LABEL_GAP = 8;
|
|
31
|
+
var X_LABEL_CHAR_WIDTH = 6;
|
|
32
|
+
var Y_LABEL_HEIGHT = 12;
|
|
33
|
+
function truncate(text, max) {
|
|
34
|
+
return text.length > max ? `${text.slice(0, max - 1)}\u2026` : text;
|
|
35
|
+
}
|
|
36
|
+
function spacedTicks(ticks, position2, size) {
|
|
37
|
+
let edge = -Infinity;
|
|
38
|
+
return [...ticks].sort((a, b) => position2(a) - position2(b)).filter((tick) => {
|
|
39
|
+
const half = size(tick) / 2;
|
|
40
|
+
if (position2(tick) - half < edge + MIN_LABEL_GAP) return false;
|
|
41
|
+
edge = position2(tick) + half;
|
|
42
|
+
return true;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function position(scale, tick) {
|
|
46
|
+
return "bandwidth" in scale ? (scale(String(tick)) ?? 0) + scale.bandwidth() / 2 : scale(Number(tick));
|
|
47
|
+
}
|
|
48
|
+
var AXIS_WORD = { x: "Horizontal", y: "Vertical" };
|
|
49
|
+
function planAxis(axis, input, plotWidth, plotHeight, margin) {
|
|
50
|
+
const { scale, format } = input;
|
|
51
|
+
const band = "bandwidth" in scale;
|
|
52
|
+
const requested = Math.max(2, input.density ?? 5);
|
|
53
|
+
const candidates = band ? scale.domain() : scale.ticks(requested);
|
|
54
|
+
const shown = band ? candidates : spacedTicks(
|
|
55
|
+
candidates,
|
|
56
|
+
(tick) => position(scale, tick),
|
|
57
|
+
axis === "x" ? (tick) => format(tick).length * X_LABEL_CHAR_WIDTH : () => Y_LABEL_HEIGHT
|
|
58
|
+
);
|
|
59
|
+
const maxLabelChars = axis === "x" ? band ? Math.max(3, Math.floor(scale.step() / 7)) : 20 : Math.max(5, Math.floor((margin.left - 12 - 4) / 6));
|
|
60
|
+
const word = AXIS_WORD[axis];
|
|
61
|
+
const guides = [];
|
|
62
|
+
if (input.rule !== false) {
|
|
63
|
+
guides.push({
|
|
64
|
+
id: `${axis}:rule`,
|
|
65
|
+
axis,
|
|
66
|
+
role: "rule",
|
|
67
|
+
source: "scale",
|
|
68
|
+
ariaLabel: `${word} axis`,
|
|
69
|
+
line: axis === "x" ? { x1: 0, y1: plotHeight, x2: plotWidth, y2: plotHeight } : { x1: 0, y1: plotHeight, x2: 0, y2: 0 }
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
for (const tick of shown) {
|
|
73
|
+
const at = position(scale, tick);
|
|
74
|
+
const fullText = format(tick);
|
|
75
|
+
guides.push({
|
|
76
|
+
id: `${axis}:tick:${String(tick)}`,
|
|
77
|
+
axis,
|
|
78
|
+
role: "tick",
|
|
79
|
+
value: tick,
|
|
80
|
+
source: "scale",
|
|
81
|
+
ariaLabel: `${word} tick ${fullText}`,
|
|
82
|
+
line: axis === "x" ? { x1: at, y1: plotHeight, x2: at, y2: plotHeight + 4 } : void 0,
|
|
83
|
+
label: axis === "x" ? {
|
|
84
|
+
text: truncate(fullText, maxLabelChars),
|
|
85
|
+
fullText,
|
|
86
|
+
x: at,
|
|
87
|
+
y: plotHeight + 17,
|
|
88
|
+
anchor: "middle",
|
|
89
|
+
fontSize: 10
|
|
90
|
+
} : {
|
|
91
|
+
text: truncate(fullText, maxLabelChars),
|
|
92
|
+
fullText,
|
|
93
|
+
x: -9,
|
|
94
|
+
y: at,
|
|
95
|
+
anchor: "end",
|
|
96
|
+
fontSize: 10,
|
|
97
|
+
dy: ".32em"
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
if (input.label && !(axis === "y" && band)) {
|
|
102
|
+
guides.push({
|
|
103
|
+
id: `${axis}:label`,
|
|
104
|
+
axis,
|
|
105
|
+
role: "label",
|
|
106
|
+
source: input.labelSource ?? "chart-setting",
|
|
107
|
+
ariaLabel: `${word} axis label ${input.label}`,
|
|
108
|
+
label: axis === "x" ? {
|
|
109
|
+
text: input.label,
|
|
110
|
+
fullText: input.label,
|
|
111
|
+
x: plotWidth / 2,
|
|
112
|
+
y: plotHeight + Math.max(32, margin.bottom - 8),
|
|
113
|
+
anchor: "middle",
|
|
114
|
+
fontSize: 11
|
|
115
|
+
} : {
|
|
116
|
+
text: input.label,
|
|
117
|
+
fullText: input.label,
|
|
118
|
+
x: -plotHeight / 2,
|
|
119
|
+
y: -(margin.left - 12),
|
|
120
|
+
anchor: "middle",
|
|
121
|
+
fontSize: 11,
|
|
122
|
+
rotate: -90
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
if (input.zero && !band && Number.isFinite(scale(0))) {
|
|
127
|
+
const at = scale(0);
|
|
128
|
+
guides.push({
|
|
129
|
+
id: `${axis}:zero`,
|
|
130
|
+
axis,
|
|
131
|
+
role: "zero",
|
|
132
|
+
value: 0,
|
|
133
|
+
source: "scale",
|
|
134
|
+
ariaLabel: "Zero baseline",
|
|
135
|
+
line: axis === "y" ? { x1: 0, y1: at, x2: plotWidth, y2: at } : { x1: at, y1: 0, x2: at, y2: plotHeight }
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const gridRequested = input.density || 5;
|
|
139
|
+
const linear = band ? void 0 : scale;
|
|
140
|
+
const gridValues = input.grid && linear ? linear.ticks(gridRequested) : [];
|
|
141
|
+
const gridGuides = gridValues.map((tick) => {
|
|
142
|
+
const at = linear(tick);
|
|
143
|
+
return {
|
|
144
|
+
id: `grid:${axis}:${tick}`,
|
|
145
|
+
axis,
|
|
146
|
+
role: "grid",
|
|
147
|
+
value: tick,
|
|
148
|
+
source: "scale",
|
|
149
|
+
ariaLabel: `${axis === "x" ? "Horizontal" : "Vertical"} grid line ${tick}`,
|
|
150
|
+
line: axis === "x" ? { x1: at, y1: 0, x2: at, y2: plotHeight } : { x1: 0, y1: at, x2: plotWidth, y2: at }
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
return {
|
|
154
|
+
axis,
|
|
155
|
+
field: input.field,
|
|
156
|
+
fieldLabel: input.fieldLabel,
|
|
157
|
+
scale: describeScale(scale, input.scaleType),
|
|
158
|
+
labelText: input.label,
|
|
159
|
+
labelSource: input.labelSource,
|
|
160
|
+
ticks: {
|
|
161
|
+
requested,
|
|
162
|
+
candidates,
|
|
163
|
+
shown,
|
|
164
|
+
omitted: candidates.filter((tick) => !shown.includes(tick)),
|
|
165
|
+
minLabelGap: MIN_LABEL_GAP,
|
|
166
|
+
labelSpacing: axis === "x" ? `${X_LABEL_CHAR_WIDTH} px per character` : `${Y_LABEL_HEIGHT} px per label`,
|
|
167
|
+
maxLabelChars
|
|
168
|
+
},
|
|
169
|
+
grid: input.grid && !band ? { requested: gridRequested, values: gridValues } : void 0,
|
|
170
|
+
domainSource: input.domainSource,
|
|
171
|
+
guides,
|
|
172
|
+
gridGuides
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
function planAxes({
|
|
176
|
+
x,
|
|
177
|
+
y,
|
|
178
|
+
plotWidth,
|
|
179
|
+
plotHeight,
|
|
180
|
+
margin,
|
|
181
|
+
marginPolicy
|
|
182
|
+
}) {
|
|
183
|
+
return {
|
|
184
|
+
x: planAxis("x", x, plotWidth, plotHeight, margin),
|
|
185
|
+
y: planAxis("y", y, plotWidth, plotHeight, margin),
|
|
186
|
+
plotWidth,
|
|
187
|
+
plotHeight,
|
|
188
|
+
margin,
|
|
189
|
+
marginPolicy
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
function planChartMargin({
|
|
193
|
+
margin,
|
|
194
|
+
width,
|
|
195
|
+
yDomain,
|
|
196
|
+
hasXLabel,
|
|
197
|
+
hasYLabel
|
|
198
|
+
}) {
|
|
199
|
+
const labelLeftMargin = Math.max(
|
|
200
|
+
margin.left,
|
|
201
|
+
...scaleLinear().domain(yDomain).ticks(5).map((tick) => String(tick).length * 7 + (hasYLabel ? 38 : 18))
|
|
202
|
+
);
|
|
203
|
+
const minPlotWidth = Math.min(
|
|
204
|
+
80,
|
|
205
|
+
Math.max(0, width - margin.left - margin.right)
|
|
206
|
+
);
|
|
207
|
+
const maxLeftMargin = Math.max(0, width - margin.right - minPlotWidth);
|
|
208
|
+
const bottomMargin = Math.max(margin.bottom, hasXLabel ? 46 : 28);
|
|
209
|
+
return {
|
|
210
|
+
margin: {
|
|
211
|
+
...margin,
|
|
212
|
+
left: Math.min(labelLeftMargin, maxLeftMargin),
|
|
213
|
+
bottom: bottomMargin
|
|
214
|
+
},
|
|
215
|
+
policy: {
|
|
216
|
+
requestedLeftMargin: margin.left,
|
|
217
|
+
labelLeftMargin,
|
|
218
|
+
maxLeftMargin,
|
|
219
|
+
minPlotWidth,
|
|
220
|
+
bottomMargin
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
function findAxisGuide(plan, id) {
|
|
225
|
+
for (const axis of [plan.x, plan.y]) {
|
|
226
|
+
const guide = axis.guides.find((item) => item.id === id) ?? axis.gridGuides.find((item) => item.id === id);
|
|
227
|
+
if (guide) return { guide, axis };
|
|
228
|
+
}
|
|
229
|
+
return void 0;
|
|
230
|
+
}
|
|
231
|
+
var GUIDE_DESCRIPTION = "Alt+Enter to inspect";
|
|
232
|
+
var activeLine = { stroke: "var(--primary)", strokeWidth: 2.5 };
|
|
233
|
+
function interactiveProps(guide, interactive) {
|
|
234
|
+
return interactive ? {
|
|
235
|
+
tabIndex: 0,
|
|
236
|
+
role: "button",
|
|
237
|
+
"aria-label": guide.ariaLabel,
|
|
238
|
+
"aria-description": GUIDE_DESCRIPTION
|
|
239
|
+
} : { "aria-label": guide.ariaLabel };
|
|
240
|
+
}
|
|
241
|
+
function GuideShape({
|
|
242
|
+
guide,
|
|
243
|
+
active
|
|
244
|
+
}) {
|
|
245
|
+
const { line, label } = guide;
|
|
246
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
247
|
+
line && /* @__PURE__ */ jsx(
|
|
248
|
+
"line",
|
|
249
|
+
{
|
|
250
|
+
...line,
|
|
251
|
+
className: "stroke-border",
|
|
252
|
+
style: active ? activeLine : void 0
|
|
253
|
+
}
|
|
254
|
+
),
|
|
255
|
+
label && /* @__PURE__ */ jsx(
|
|
256
|
+
"text",
|
|
257
|
+
{
|
|
258
|
+
x: label.x,
|
|
259
|
+
y: label.y,
|
|
260
|
+
dy: label.dy,
|
|
261
|
+
transform: label.rotate ? `rotate(${label.rotate})` : void 0,
|
|
262
|
+
textAnchor: label.anchor,
|
|
263
|
+
fontSize: label.fontSize,
|
|
264
|
+
fill: active ? "var(--primary)" : void 0,
|
|
265
|
+
textDecoration: active ? "underline" : void 0,
|
|
266
|
+
"aria-label": label.fullText,
|
|
267
|
+
children: label.text
|
|
268
|
+
}
|
|
269
|
+
)
|
|
270
|
+
] });
|
|
271
|
+
}
|
|
272
|
+
function PlannedGrid({
|
|
273
|
+
plan,
|
|
274
|
+
interactive = false,
|
|
275
|
+
activeId
|
|
276
|
+
}) {
|
|
277
|
+
const guides = [...plan.x.gridGuides, ...plan.y.gridGuides];
|
|
278
|
+
if (!guides.length) return null;
|
|
279
|
+
return /* @__PURE__ */ jsx(
|
|
280
|
+
"g",
|
|
281
|
+
{
|
|
282
|
+
className: "stroke-border",
|
|
283
|
+
opacity: 0.55,
|
|
284
|
+
pointerEvents: interactive ? void 0 : "none",
|
|
285
|
+
children: guides.map((guide) => /* @__PURE__ */ jsxs("g", { children: [
|
|
286
|
+
/* @__PURE__ */ jsx(
|
|
287
|
+
"line",
|
|
288
|
+
{
|
|
289
|
+
...guide.line,
|
|
290
|
+
pointerEvents: "none",
|
|
291
|
+
style: guide.id === activeId ? activeLine : void 0
|
|
292
|
+
}
|
|
293
|
+
),
|
|
294
|
+
interactive && /* @__PURE__ */ jsx(
|
|
295
|
+
"line",
|
|
296
|
+
{
|
|
297
|
+
...guide.line,
|
|
298
|
+
"data-plan-id": guide.id,
|
|
299
|
+
className: "chart-guide-hit",
|
|
300
|
+
stroke: "transparent",
|
|
301
|
+
strokeWidth: 10,
|
|
302
|
+
pointerEvents: "stroke",
|
|
303
|
+
...interactiveProps(guide, true)
|
|
304
|
+
}
|
|
305
|
+
)
|
|
306
|
+
] }, guide.id))
|
|
307
|
+
}
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
function PlannedAxes({
|
|
311
|
+
plan,
|
|
312
|
+
interactive = false,
|
|
313
|
+
activeId
|
|
314
|
+
}) {
|
|
315
|
+
return /* @__PURE__ */ jsx(
|
|
316
|
+
"g",
|
|
317
|
+
{
|
|
318
|
+
className: "fill-muted-foreground",
|
|
319
|
+
pointerEvents: interactive ? "auto" : "none",
|
|
320
|
+
children: [...plan.x.guides, ...plan.y.guides].map((guide) => /* @__PURE__ */ jsx(
|
|
321
|
+
"g",
|
|
322
|
+
{
|
|
323
|
+
"data-plan-id": guide.id,
|
|
324
|
+
className: "chart-guide",
|
|
325
|
+
...interactiveProps(guide, interactive),
|
|
326
|
+
children: /* @__PURE__ */ jsx(GuideShape, { guide, active: guide.id === activeId })
|
|
327
|
+
},
|
|
328
|
+
guide.id
|
|
329
|
+
))
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
var clamp = (value, max) => Math.max(0, Math.min(value, max));
|
|
334
|
+
function useBrush({
|
|
335
|
+
svgRef,
|
|
336
|
+
marginLeft,
|
|
337
|
+
marginTop,
|
|
338
|
+
innerWidth,
|
|
339
|
+
innerHeight,
|
|
340
|
+
mode,
|
|
341
|
+
onBrushChange,
|
|
342
|
+
onPlotClick,
|
|
343
|
+
defaultExtent
|
|
344
|
+
}) {
|
|
345
|
+
const gesture = useRef(null);
|
|
346
|
+
const wasDrag = useRef(false);
|
|
347
|
+
const draftRef = useRef(null);
|
|
348
|
+
const [draft, setDraft] = useState(null);
|
|
349
|
+
const extent = draft ?? defaultExtent;
|
|
350
|
+
const position2 = (event) => {
|
|
351
|
+
const rect = svgRef.current.getBoundingClientRect();
|
|
352
|
+
return [
|
|
353
|
+
event.clientX - rect.left - marginLeft,
|
|
354
|
+
event.clientY - rect.top - marginTop
|
|
355
|
+
];
|
|
356
|
+
};
|
|
357
|
+
const cancel = () => {
|
|
358
|
+
gesture.current = null;
|
|
359
|
+
draftRef.current = null;
|
|
360
|
+
setDraft(null);
|
|
361
|
+
};
|
|
362
|
+
const clear = () => {
|
|
363
|
+
cancel();
|
|
364
|
+
onBrushChange?.(null);
|
|
365
|
+
};
|
|
366
|
+
const handlePointerDown = (event) => {
|
|
367
|
+
wasDrag.current = false;
|
|
368
|
+
if (mode === "none" || event.button !== 0 || !svgRef.current) return;
|
|
369
|
+
const [x, y] = position2(event);
|
|
370
|
+
if (x < 0 || x > innerWidth || y < 0 || y > innerHeight) return;
|
|
371
|
+
event.stopPropagation();
|
|
372
|
+
event.currentTarget.focus({ preventScroll: true });
|
|
373
|
+
let edges = "";
|
|
374
|
+
let inside = false;
|
|
375
|
+
if (extent) {
|
|
376
|
+
const [[x0, y0], [x1, y1]] = extent;
|
|
377
|
+
inside = x >= x0 - 6 && x <= x1 + 6 && y >= y0 - 6 && y <= y1 + 6;
|
|
378
|
+
if (inside) {
|
|
379
|
+
if (Math.abs(x - x0) < 6) edges += "l";
|
|
380
|
+
else if (Math.abs(x - x1) < 6) edges += "r";
|
|
381
|
+
if (mode === "2d") {
|
|
382
|
+
if (Math.abs(y - y0) < 6) edges += "t";
|
|
383
|
+
else if (Math.abs(y - y1) < 6) edges += "b";
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
gesture.current = {
|
|
388
|
+
start: [x, y],
|
|
389
|
+
original: extent ?? null,
|
|
390
|
+
kind: edges ? "resize" : inside ? "move" : "draw",
|
|
391
|
+
edges,
|
|
392
|
+
moved: false
|
|
393
|
+
};
|
|
394
|
+
};
|
|
395
|
+
const handlePointerMove = (event) => {
|
|
396
|
+
const active = gesture.current;
|
|
397
|
+
if (!active || !svgRef.current) return;
|
|
398
|
+
const raw = position2(event);
|
|
399
|
+
if (!active.moved && Math.hypot(raw[0] - active.start[0], raw[1] - active.start[1]) < 3)
|
|
400
|
+
return;
|
|
401
|
+
if (!active.moved) event.currentTarget.setPointerCapture?.(event.pointerId);
|
|
402
|
+
active.moved = true;
|
|
403
|
+
wasDrag.current = true;
|
|
404
|
+
event.preventDefault();
|
|
405
|
+
const x = clamp(raw[0], innerWidth), y = clamp(raw[1], innerHeight);
|
|
406
|
+
let next;
|
|
407
|
+
if (active.kind === "move" && active.original) {
|
|
408
|
+
const [[x0, y0], [x1, y1]] = active.original;
|
|
409
|
+
const left = clamp(x0 + x - active.start[0], innerWidth - (x1 - x0));
|
|
410
|
+
const top = mode === "horizontal" ? 0 : clamp(y0 + y - active.start[1], innerHeight - (y1 - y0));
|
|
411
|
+
next = [
|
|
412
|
+
[left, top],
|
|
413
|
+
[left + x1 - x0, top + y1 - y0]
|
|
414
|
+
];
|
|
415
|
+
} else if (active.kind === "resize" && active.original) {
|
|
416
|
+
const [[x0, y0], [x1, y1]] = active.original;
|
|
417
|
+
const left = active.edges.includes("l") ? x : x0;
|
|
418
|
+
const right = active.edges.includes("r") ? x : x1;
|
|
419
|
+
const top = active.edges.includes("t") ? y : y0;
|
|
420
|
+
const bottom = active.edges.includes("b") ? y : y1;
|
|
421
|
+
next = [
|
|
422
|
+
[Math.min(left, right), Math.min(top, bottom)],
|
|
423
|
+
[Math.max(left, right), Math.max(top, bottom)]
|
|
424
|
+
];
|
|
425
|
+
} else {
|
|
426
|
+
next = [
|
|
427
|
+
[
|
|
428
|
+
Math.min(x, active.start[0]),
|
|
429
|
+
mode === "horizontal" ? 0 : Math.min(y, active.start[1])
|
|
430
|
+
],
|
|
431
|
+
[
|
|
432
|
+
Math.max(x, active.start[0]),
|
|
433
|
+
mode === "horizontal" ? innerHeight : Math.max(y, active.start[1])
|
|
434
|
+
]
|
|
435
|
+
];
|
|
436
|
+
}
|
|
437
|
+
draftRef.current = next;
|
|
438
|
+
setDraft(next);
|
|
439
|
+
};
|
|
440
|
+
const handlePointerUp = (event) => {
|
|
441
|
+
const active = gesture.current;
|
|
442
|
+
if (!active) return;
|
|
443
|
+
const next = draftRef.current;
|
|
444
|
+
if (event.currentTarget.hasPointerCapture?.(event.pointerId))
|
|
445
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
446
|
+
cancel();
|
|
447
|
+
if (!active.moved) {
|
|
448
|
+
if (active.kind === "draw" && !onPlotClick?.(active.start, event))
|
|
449
|
+
onBrushChange?.(null);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (next && next[1][0] - next[0][0] >= 3 && (mode === "horizontal" || next[1][1] - next[0][1] >= 3))
|
|
453
|
+
onBrushChange?.(next);
|
|
454
|
+
else onBrushChange?.(null);
|
|
455
|
+
};
|
|
456
|
+
const renderBrush = extent && mode !== "none" ? /* @__PURE__ */ jsxs("g", { className: "eda-brush", children: [
|
|
457
|
+
/* @__PURE__ */ jsx(
|
|
458
|
+
"rect",
|
|
459
|
+
{
|
|
460
|
+
x: extent[0][0],
|
|
461
|
+
y: extent[0][1],
|
|
462
|
+
width: Math.max(0, extent[1][0] - extent[0][0]),
|
|
463
|
+
height: Math.max(0, extent[1][1] - extent[0][1]),
|
|
464
|
+
fill: "var(--primary)",
|
|
465
|
+
fillOpacity: 0.09,
|
|
466
|
+
stroke: "var(--primary)",
|
|
467
|
+
strokeWidth: 1.25,
|
|
468
|
+
style: { cursor: "move" }
|
|
469
|
+
}
|
|
470
|
+
),
|
|
471
|
+
[extent[0][0], extent[1][0]].map((x, index) => /* @__PURE__ */ jsx(
|
|
472
|
+
"rect",
|
|
473
|
+
{
|
|
474
|
+
x: x - 2,
|
|
475
|
+
y: (extent[0][1] + extent[1][1]) / 2 - 8,
|
|
476
|
+
width: 4,
|
|
477
|
+
height: 16,
|
|
478
|
+
rx: 2,
|
|
479
|
+
fill: "var(--primary)",
|
|
480
|
+
style: { cursor: "ew-resize" }
|
|
481
|
+
},
|
|
482
|
+
index
|
|
483
|
+
)),
|
|
484
|
+
mode === "2d" && [extent[0][1], extent[1][1]].map((y, index) => /* @__PURE__ */ jsx(
|
|
485
|
+
"rect",
|
|
486
|
+
{
|
|
487
|
+
x: (extent[0][0] + extent[1][0]) / 2 - 8,
|
|
488
|
+
y: y - 2,
|
|
489
|
+
width: 16,
|
|
490
|
+
height: 4,
|
|
491
|
+
rx: 2,
|
|
492
|
+
fill: "var(--primary)",
|
|
493
|
+
style: { cursor: "ns-resize" }
|
|
494
|
+
},
|
|
495
|
+
index
|
|
496
|
+
))
|
|
497
|
+
] }) : null;
|
|
498
|
+
return {
|
|
499
|
+
extent,
|
|
500
|
+
handlePointerDown,
|
|
501
|
+
handlePointerMove,
|
|
502
|
+
handlePointerUp,
|
|
503
|
+
cancel,
|
|
504
|
+
clear,
|
|
505
|
+
wasDrag,
|
|
506
|
+
renderBrush,
|
|
507
|
+
getCursor: () => mode === "none" ? "default" : "crosshair"
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// src/hooks/getAxisFilter.ts
|
|
512
|
+
function getRangeFilterForField(filters, field) {
|
|
513
|
+
return filters.find(
|
|
514
|
+
(f) => f.type === "range" && f.field === field
|
|
515
|
+
);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
export { PlannedAxes, PlannedGrid, buildScale, describeScale, findAxisGuide, getRangeFilterForField, numericScale, planAxes, planChartMargin, useBrush };
|
|
519
|
+
//# sourceMappingURL=chunk-7PTJNIOD.js.map
|
|
520
|
+
//# sourceMappingURL=chunk-7PTJNIOD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/charts/Axis/numericScale.ts","../src/components/charts/Axis/axisPlan.ts","../src/components/charts/Axis/AxisLayer.tsx","../src/hooks/useBrush.tsx","../src/hooks/getAxisFilter.ts"],"names":["position","scaleLinear","jsxs","jsx"],"mappings":"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","file":"chunk-7PTJNIOD.js","sourcesContent":["import { scaleLinear, scaleSymlog, type ScaleLinear } from \"d3-scale\";\nimport type { AxisSettings } from \"@/types/ChartTypes\";\n\nexport function numericScale(axis?: AxisSettings): ScaleLinear<number, number> {\n return (\n axis?.scaleType === \"symlog\" ? scaleSymlog() : scaleLinear()\n ) as ScaleLinear<number, number>;\n}\n","import {\n scaleBand,\n scaleLinear,\n type ScaleBand,\n type ScaleLinear,\n} from \"d3-scale\";\nimport type { MarginSettings } from \"@/types/ChartTypes\";\nimport { numericScale } from \"./numericScale\";\n\nexport type AxisName = \"x\" | \"y\";\nexport type ChartScale = ScaleLinear<number, number> | ScaleBand<string>;\n\nexport type ScaleDescriptor =\n | {\n type: \"band\";\n domain: string[];\n range: [number, number];\n padding: number;\n }\n | {\n type: \"linear\" | \"symlog\";\n domain: [number, number];\n range: [number, number];\n };\n\n/** Records a D3 scale so a trace can show it and a renderer can rebuild it. */\nexport function describeScale(\n scale: ChartScale,\n scaleType?: string\n): ScaleDescriptor {\n if (\"bandwidth\" in scale) {\n return {\n type: \"band\",\n domain: scale.domain(),\n range: scale.range() as [number, number],\n padding: scale.padding(),\n };\n }\n return {\n type: scaleType === \"symlog\" ? \"symlog\" : \"linear\",\n domain: scale.domain() as [number, number],\n range: scale.range() as [number, number],\n };\n}\n\nexport function buildScale(descriptor: ScaleDescriptor): ChartScale {\n if (descriptor.type === \"band\") {\n return scaleBand<string>()\n .domain(descriptor.domain)\n .range(descriptor.range)\n .padding(descriptor.padding);\n }\n return numericScale({ scaleType: descriptor.type })\n .domain(descriptor.domain)\n .range(descriptor.range);\n}\n\nexport type GuideRole = \"rule\" | \"tick\" | \"grid\" | \"label\" | \"zero\";\nexport type GuideSource = \"scale\" | \"chart-setting\" | \"field-label\";\n\nexport interface GuideLine {\n x1: number;\n y1: number;\n x2: number;\n y2: number;\n}\n\nexport interface GuideText {\n text: string;\n fullText: string;\n x: number;\n y: number;\n anchor: \"start\" | \"middle\" | \"end\";\n fontSize: number;\n dy?: string;\n rotate?: number;\n}\n\n/** One selectable axis object in plot coordinates. */\nexport interface AxisGuide {\n id: string;\n axis: AxisName;\n role: GuideRole;\n value?: number | string;\n source: GuideSource;\n ariaLabel: string;\n line?: GuideLine;\n label?: GuideText;\n}\n\nexport interface AxisDomainSource {\n /** Which rows set the domain, in words a reader can check. */\n population: string;\n rows: number;\n bounds: [number, number];\n padding: string;\n lower?: { label: string; value: number };\n upper?: { label: string; value: number };\n}\n\nexport interface AxisPlan {\n axis: AxisName;\n field?: string;\n fieldLabel?: string;\n scale: ScaleDescriptor;\n labelText?: string;\n labelSource?: GuideSource;\n ticks: {\n requested: number;\n candidates: (number | string)[];\n shown: (number | string)[];\n omitted: (number | string)[];\n minLabelGap: number;\n labelSpacing: string;\n maxLabelChars: number;\n };\n grid?: { requested: number; values: number[] };\n domainSource?: AxisDomainSource;\n guides: AxisGuide[];\n gridGuides: AxisGuide[];\n}\n\nexport interface MarginPolicy {\n requestedLeftMargin: number;\n labelLeftMargin: number;\n maxLeftMargin: number;\n minPlotWidth: number;\n bottomMargin: number;\n}\n\nexport interface ChartAxesPlan {\n x: AxisPlan;\n y: AxisPlan;\n plotWidth: number;\n plotHeight: number;\n margin: MarginSettings;\n marginPolicy?: MarginPolicy;\n}\n\nexport interface AxisInput {\n scale: ChartScale;\n scaleType?: string;\n field?: string;\n fieldLabel?: string;\n /** Tick density from the chart setting. Undefined uses 5. */\n density?: number;\n grid?: boolean;\n format: (value: string | number) => string;\n label?: string;\n labelSource?: GuideSource;\n rule?: boolean;\n zero?: boolean;\n domainSource?: AxisDomainSource;\n}\n\nconst MIN_LABEL_GAP = 8;\nconst X_LABEL_CHAR_WIDTH = 6;\nconst Y_LABEL_HEIGHT = 12;\n\nfunction truncate(text: string, max: number) {\n return text.length > max ? `${text.slice(0, max - 1)}…` : text;\n}\n\n/** Keeps label order by position and drops a label that would overlap the last kept one. */\nfunction spacedTicks<T extends number | string>(\n ticks: T[],\n position: (tick: T) => number,\n size: (tick: T) => number\n) {\n let edge = -Infinity;\n return [...ticks]\n .sort((a, b) => position(a) - position(b))\n .filter((tick) => {\n const half = size(tick) / 2;\n if (position(tick) - half < edge + MIN_LABEL_GAP) return false;\n edge = position(tick) + half;\n return true;\n });\n}\n\nfunction position(scale: ChartScale, tick: number | string) {\n return \"bandwidth\" in scale\n ? (scale(String(tick)) ?? 0) + scale.bandwidth() / 2\n : scale(Number(tick));\n}\n\nconst AXIS_WORD = { x: \"Horizontal\", y: \"Vertical\" } as const;\n\nfunction planAxis(\n axis: AxisName,\n input: AxisInput,\n plotWidth: number,\n plotHeight: number,\n margin: MarginSettings\n): AxisPlan {\n const { scale, format } = input;\n const band = \"bandwidth\" in scale;\n // Density sets the D3 candidate target. Spacing then drops overlapping labels.\n const requested = Math.max(2, input.density ?? 5);\n const candidates: (number | string)[] = band\n ? scale.domain()\n : scale.ticks(requested);\n const shown = band\n ? candidates\n : spacedTicks(\n candidates,\n (tick) => position(scale, tick),\n axis === \"x\"\n ? (tick) => format(tick).length * X_LABEL_CHAR_WIDTH\n : () => Y_LABEL_HEIGHT\n );\n const maxLabelChars =\n axis === \"x\"\n ? band\n ? Math.max(3, Math.floor(scale.step() / 7))\n : 20\n : Math.max(5, Math.floor((margin.left - 12 - 4) / 6));\n const word = AXIS_WORD[axis];\n const guides: AxisGuide[] = [];\n if (input.rule !== false) {\n guides.push({\n id: `${axis}:rule`,\n axis,\n role: \"rule\",\n source: \"scale\",\n ariaLabel: `${word} axis`,\n line:\n axis === \"x\"\n ? { x1: 0, y1: plotHeight, x2: plotWidth, y2: plotHeight }\n : { x1: 0, y1: plotHeight, x2: 0, y2: 0 },\n });\n }\n for (const tick of shown) {\n const at = position(scale, tick);\n const fullText = format(tick);\n guides.push({\n id: `${axis}:tick:${String(tick)}`,\n axis,\n role: \"tick\",\n value: tick,\n source: \"scale\",\n ariaLabel: `${word} tick ${fullText}`,\n line:\n axis === \"x\"\n ? { x1: at, y1: plotHeight, x2: at, y2: plotHeight + 4 }\n : undefined,\n label:\n axis === \"x\"\n ? {\n text: truncate(fullText, maxLabelChars),\n fullText,\n x: at,\n y: plotHeight + 17,\n anchor: \"middle\",\n fontSize: 10,\n }\n : {\n text: truncate(fullText, maxLabelChars),\n fullText,\n x: -9,\n y: at,\n anchor: \"end\",\n fontSize: 10,\n dy: \".32em\",\n },\n });\n }\n // A band Y axis names its categories in the tick labels, so it has no title.\n if (input.label && !(axis === \"y\" && band)) {\n guides.push({\n id: `${axis}:label`,\n axis,\n role: \"label\",\n source: input.labelSource ?? \"chart-setting\",\n ariaLabel: `${word} axis label ${input.label}`,\n label:\n axis === \"x\"\n ? {\n text: input.label,\n fullText: input.label,\n x: plotWidth / 2,\n y: plotHeight + Math.max(32, margin.bottom - 8),\n anchor: \"middle\",\n fontSize: 11,\n }\n : {\n text: input.label,\n fullText: input.label,\n x: -plotHeight / 2,\n y: -(margin.left - 12),\n anchor: \"middle\",\n fontSize: 11,\n rotate: -90,\n },\n });\n }\n if (input.zero && !band && Number.isFinite(scale(0))) {\n const at = scale(0);\n guides.push({\n id: `${axis}:zero`,\n axis,\n role: \"zero\",\n value: 0,\n source: \"scale\",\n ariaLabel: \"Zero baseline\",\n line:\n axis === \"y\"\n ? { x1: 0, y1: at, x2: plotWidth, y2: at }\n : { x1: at, y1: 0, x2: at, y2: plotHeight },\n });\n }\n const gridRequested = input.density || 5;\n const linear = band ? undefined : scale;\n const gridValues = input.grid && linear ? linear.ticks(gridRequested) : [];\n const gridGuides = gridValues.map((tick): AxisGuide => {\n const at = linear!(tick);\n return {\n id: `grid:${axis}:${tick}`,\n axis,\n role: \"grid\",\n value: tick,\n source: \"scale\",\n ariaLabel: `${axis === \"x\" ? \"Horizontal\" : \"Vertical\"} grid line ${tick}`,\n line:\n axis === \"x\"\n ? { x1: at, y1: 0, x2: at, y2: plotHeight }\n : { x1: 0, y1: at, x2: plotWidth, y2: at },\n };\n });\n return {\n axis,\n field: input.field,\n fieldLabel: input.fieldLabel,\n scale: describeScale(scale, input.scaleType),\n labelText: input.label,\n labelSource: input.labelSource,\n ticks: {\n requested,\n candidates,\n shown,\n omitted: candidates.filter((tick) => !shown.includes(tick)),\n minLabelGap: MIN_LABEL_GAP,\n labelSpacing:\n axis === \"x\"\n ? `${X_LABEL_CHAR_WIDTH} px per character`\n : `${Y_LABEL_HEIGHT} px per label`,\n maxLabelChars,\n },\n grid: input.grid && !band ? { requested: gridRequested, values: gridValues } : undefined,\n domainSource: input.domainSource,\n guides,\n gridGuides,\n };\n}\n\n/** Plans both axes and their grid lines. Drawing and tracing read the same objects. */\nexport function planAxes({\n x,\n y,\n plotWidth,\n plotHeight,\n margin,\n marginPolicy,\n}: {\n x: AxisInput;\n y: AxisInput;\n plotWidth: number;\n plotHeight: number;\n margin: MarginSettings;\n marginPolicy?: MarginPolicy;\n}): ChartAxesPlan {\n return {\n x: planAxis(\"x\", x, plotWidth, plotHeight, margin),\n y: planAxis(\"y\", y, plotWidth, plotHeight, margin),\n plotWidth,\n plotHeight,\n margin,\n marginPolicy,\n };\n}\n\n/** Widens the left margin for Y labels while keeping a minimum plot width. */\nexport function planChartMargin({\n margin,\n width,\n yDomain,\n hasXLabel,\n hasYLabel,\n}: {\n margin: MarginSettings;\n width: number;\n yDomain: [number, number];\n hasXLabel: boolean;\n hasYLabel: boolean;\n}): { margin: MarginSettings; policy: MarginPolicy } {\n const labelLeftMargin = Math.max(\n margin.left,\n ...scaleLinear()\n .domain(yDomain)\n .ticks(5)\n .map((tick) => String(tick).length * 7 + (hasYLabel ? 38 : 18))\n );\n const minPlotWidth = Math.min(\n 80,\n Math.max(0, width - margin.left - margin.right)\n );\n const maxLeftMargin = Math.max(0, width - margin.right - minPlotWidth);\n const bottomMargin = Math.max(margin.bottom, hasXLabel ? 46 : 28);\n return {\n margin: {\n ...margin,\n left: Math.min(labelLeftMargin, maxLeftMargin),\n bottom: bottomMargin,\n },\n policy: {\n requestedLeftMargin: margin.left,\n labelLeftMargin,\n maxLeftMargin,\n minPlotWidth,\n bottomMargin,\n },\n };\n}\n\nexport function axisGuides(plan: ChartAxesPlan): AxisGuide[] {\n return [\n ...plan.x.gridGuides,\n ...plan.y.gridGuides,\n ...plan.x.guides,\n ...plan.y.guides,\n ];\n}\n\nexport function findAxisGuide(plan: ChartAxesPlan, id: string) {\n for (const axis of [plan.x, plan.y]) {\n const guide =\n axis.guides.find((item) => item.id === id) ??\n axis.gridGuides.find((item) => item.id === id);\n if (guide) return { guide, axis };\n }\n return undefined;\n}\n","import type { AxisGuide, ChartAxesPlan } from \"./axisPlan\";\n\nconst GUIDE_DESCRIPTION = \"Alt+Enter to inspect\";\n\nconst activeLine = { stroke: \"var(--primary)\", strokeWidth: 2.5 };\n\nfunction interactiveProps(guide: AxisGuide, interactive: boolean) {\n return interactive\n ? {\n tabIndex: 0,\n role: \"button\" as const,\n \"aria-label\": guide.ariaLabel,\n \"aria-description\": GUIDE_DESCRIPTION,\n }\n : { \"aria-label\": guide.ariaLabel };\n}\n\nfunction GuideShape({\n guide,\n active,\n}: {\n guide: AxisGuide;\n active: boolean;\n}) {\n const { line, label } = guide;\n return (\n <>\n {line && (\n <line\n {...line}\n className=\"stroke-border\"\n style={active ? activeLine : undefined}\n />\n )}\n {label && (\n <text\n x={label.x}\n y={label.y}\n dy={label.dy}\n transform={label.rotate ? `rotate(${label.rotate})` : undefined}\n textAnchor={label.anchor}\n fontSize={label.fontSize}\n fill={active ? \"var(--primary)\" : undefined}\n textDecoration={active ? \"underline\" : undefined}\n aria-label={label.fullText}\n >\n {label.text}\n </text>\n )}\n </>\n );\n}\n\n/** Draws planned grid lines. Place it inside the plot clip. */\nexport function PlannedGrid({\n plan,\n interactive = false,\n activeId,\n}: {\n plan: ChartAxesPlan;\n interactive?: boolean;\n activeId?: string | null;\n}) {\n const guides = [...plan.x.gridGuides, ...plan.y.gridGuides];\n if (!guides.length) return null;\n return (\n <g\n className=\"stroke-border\"\n opacity={0.55}\n pointerEvents={interactive ? undefined : \"none\"}\n >\n {guides.map((guide) => (\n <g key={guide.id}>\n <line\n {...guide.line}\n pointerEvents=\"none\"\n style={guide.id === activeId ? activeLine : undefined}\n />\n {interactive && (\n <line\n {...guide.line}\n data-plan-id={guide.id}\n className=\"chart-guide-hit\"\n stroke=\"transparent\"\n strokeWidth={10}\n pointerEvents=\"stroke\"\n {...interactiveProps(guide, true)}\n />\n )}\n </g>\n ))}\n </g>\n );\n}\n\n/** Draws planned axis rules, ticks, labels and the zero line. */\nexport function PlannedAxes({\n plan,\n interactive = false,\n activeId,\n}: {\n plan: ChartAxesPlan;\n interactive?: boolean;\n activeId?: string | null;\n}) {\n return (\n <g\n className=\"fill-muted-foreground\"\n pointerEvents={interactive ? \"auto\" : \"none\"}\n >\n {[...plan.x.guides, ...plan.y.guides].map((guide) => (\n <g\n key={guide.id}\n data-plan-id={guide.id}\n className=\"chart-guide\"\n {...interactiveProps(guide, interactive)}\n >\n <GuideShape guide={guide} active={guide.id === activeId} />\n </g>\n ))}\n </g>\n );\n}\n","import { PointerEvent, RefObject, useRef, useState } from \"react\";\n\ntype Extent = [[number, number], [number, number]];\ntype Point = [number, number];\ninterface Options {\n svgRef: RefObject<SVGSVGElement | null>;\n marginLeft: number;\n marginTop: number;\n innerWidth: number;\n innerHeight: number;\n mode: \"horizontal\" | \"2d\" | \"none\";\n onBrushChange?: (extent: Extent | null) => void;\n onPlotClick?: (point: Point, event: PointerEvent<SVGSVGElement>) => boolean;\n defaultExtent?: Extent | null;\n}\ninterface Gesture {\n start: Point;\n original: Extent | null;\n kind: \"draw\" | \"move\" | \"resize\";\n edges: string;\n moved: boolean;\n}\nconst clamp = (value: number, max: number) => Math.max(0, Math.min(value, max));\n\nexport function useBrush({\n svgRef,\n marginLeft,\n marginTop,\n innerWidth,\n innerHeight,\n mode,\n onBrushChange,\n onPlotClick,\n defaultExtent,\n}: Options) {\n const gesture = useRef<Gesture | null>(null);\n const wasDrag = useRef(false);\n const draftRef = useRef<Extent | null>(null);\n const [draft, setDraft] = useState<Extent | null>(null);\n // External selections only supply the resting state. They never interrupt a gesture.\n const extent = draft ?? defaultExtent;\n const position = (event: PointerEvent): Point => {\n const rect = svgRef.current!.getBoundingClientRect();\n return [\n event.clientX - rect.left - marginLeft,\n event.clientY - rect.top - marginTop,\n ];\n };\n const cancel = () => {\n gesture.current = null;\n draftRef.current = null;\n setDraft(null);\n };\n const clear = () => {\n cancel();\n onBrushChange?.(null);\n };\n\n const handlePointerDown = (event: PointerEvent<SVGSVGElement>) => {\n wasDrag.current = false;\n if (mode === \"none\" || event.button !== 0 || !svgRef.current) return;\n const [x, y] = position(event);\n if (x < 0 || x > innerWidth || y < 0 || y > innerHeight) return;\n event.stopPropagation();\n event.currentTarget.focus({ preventScroll: true });\n let edges = \"\";\n let inside = false;\n if (extent) {\n const [[x0, y0], [x1, y1]] = extent;\n inside = x >= x0 - 6 && x <= x1 + 6 && y >= y0 - 6 && y <= y1 + 6;\n if (inside) {\n if (Math.abs(x - x0) < 6) edges += \"l\";\n else if (Math.abs(x - x1) < 6) edges += \"r\";\n if (mode === \"2d\") {\n if (Math.abs(y - y0) < 6) edges += \"t\";\n else if (Math.abs(y - y1) < 6) edges += \"b\";\n }\n }\n }\n gesture.current = {\n start: [x, y],\n original: extent ?? null,\n kind: edges ? \"resize\" : inside ? \"move\" : \"draw\",\n edges,\n moved: false,\n };\n };\n\n const handlePointerMove = (event: PointerEvent<SVGSVGElement>) => {\n const active = gesture.current;\n if (!active || !svgRef.current) return;\n const raw = position(event);\n if (\n !active.moved &&\n Math.hypot(raw[0] - active.start[0], raw[1] - active.start[1]) < 3\n )\n return;\n // Capture only a confirmed drag so clicks on marks keep their original target.\n if (!active.moved) event.currentTarget.setPointerCapture?.(event.pointerId);\n active.moved = true;\n wasDrag.current = true;\n event.preventDefault();\n const x = clamp(raw[0], innerWidth),\n y = clamp(raw[1], innerHeight);\n let next: Extent;\n if (active.kind === \"move\" && active.original) {\n const [[x0, y0], [x1, y1]] = active.original;\n const left = clamp(x0 + x - active.start[0], innerWidth - (x1 - x0));\n const top =\n mode === \"horizontal\"\n ? 0\n : clamp(y0 + y - active.start[1], innerHeight - (y1 - y0));\n next = [\n [left, top],\n [left + x1 - x0, top + y1 - y0],\n ];\n } else if (active.kind === \"resize\" && active.original) {\n const [[x0, y0], [x1, y1]] = active.original;\n const left = active.edges.includes(\"l\") ? x : x0;\n const right = active.edges.includes(\"r\") ? x : x1;\n const top = active.edges.includes(\"t\") ? y : y0;\n const bottom = active.edges.includes(\"b\") ? y : y1;\n next = [\n [Math.min(left, right), Math.min(top, bottom)],\n [Math.max(left, right), Math.max(top, bottom)],\n ];\n } else {\n next = [\n [\n Math.min(x, active.start[0]),\n mode === \"horizontal\" ? 0 : Math.min(y, active.start[1]),\n ],\n [\n Math.max(x, active.start[0]),\n mode === \"horizontal\" ? innerHeight : Math.max(y, active.start[1]),\n ],\n ];\n }\n draftRef.current = next;\n setDraft(next);\n };\n\n const handlePointerUp = (event: PointerEvent<SVGSVGElement>) => {\n const active = gesture.current;\n if (!active) return;\n const next = draftRef.current;\n if (event.currentTarget.hasPointerCapture?.(event.pointerId))\n event.currentTarget.releasePointerCapture(event.pointerId);\n cancel();\n if (!active.moved) {\n if (active.kind === \"draw\" && !onPlotClick?.(active.start, event))\n onBrushChange?.(null);\n return;\n }\n if (\n next &&\n next[1][0] - next[0][0] >= 3 &&\n (mode === \"horizontal\" || next[1][1] - next[0][1] >= 3)\n )\n onBrushChange?.(next);\n else onBrushChange?.(null);\n };\n\n const renderBrush =\n extent && mode !== \"none\" ? (\n <g className=\"eda-brush\">\n <rect\n x={extent[0][0]}\n y={extent[0][1]}\n width={Math.max(0, extent[1][0] - extent[0][0])}\n height={Math.max(0, extent[1][1] - extent[0][1])}\n fill=\"var(--primary)\"\n fillOpacity={0.09}\n stroke=\"var(--primary)\"\n strokeWidth={1.25}\n style={{ cursor: \"move\" }}\n />\n {[extent[0][0], extent[1][0]].map((x, index) => (\n <rect\n key={index}\n x={x - 2}\n y={(extent[0][1] + extent[1][1]) / 2 - 8}\n width={4}\n height={16}\n rx={2}\n fill=\"var(--primary)\"\n style={{ cursor: \"ew-resize\" }}\n />\n ))}\n {mode === \"2d\" &&\n [extent[0][1], extent[1][1]].map((y, index) => (\n <rect\n key={index}\n x={(extent[0][0] + extent[1][0]) / 2 - 8}\n y={y - 2}\n width={16}\n height={4}\n rx={2}\n fill=\"var(--primary)\"\n style={{ cursor: \"ns-resize\" }}\n />\n ))}\n </g>\n ) : null;\n return {\n extent,\n handlePointerDown,\n handlePointerMove,\n handlePointerUp,\n cancel,\n clear,\n wasDrag,\n renderBrush,\n getCursor: () => (mode === \"none\" ? \"default\" : \"crosshair\"),\n };\n}\n","import { Filter, RangeFilter } from \"@/types/FilterTypes\";\n\nexport function getRangeFilterForField(\n filters: Filter[],\n field: string\n): RangeFilter | undefined {\n return filters.find(\n (f): f is RangeFilter => f.type === \"range\" && f.field === field\n );\n}\n"]}
|