@tetrascience-npm/tetrascience-react-ui 0.6.0-beta.98.1 → 0.6.0-beta.99.1

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.
Files changed (36) hide show
  1. package/dist/components/charts/AreaGraph/AreaGraph.cjs +1 -1
  2. package/dist/components/charts/AreaGraph/AreaGraph.cjs.map +1 -1
  3. package/dist/components/charts/AreaGraph/AreaGraph.js +132 -103
  4. package/dist/components/charts/AreaGraph/AreaGraph.js.map +1 -1
  5. package/dist/components/charts/BarGraph/BarGraph.cjs +1 -1
  6. package/dist/components/charts/BarGraph/BarGraph.cjs.map +1 -1
  7. package/dist/components/charts/BarGraph/BarGraph.js +124 -95
  8. package/dist/components/charts/BarGraph/BarGraph.js.map +1 -1
  9. package/dist/components/charts/Boxplot/Boxplot.cjs +1 -1
  10. package/dist/components/charts/Boxplot/Boxplot.cjs.map +1 -1
  11. package/dist/components/charts/Boxplot/Boxplot.js +116 -87
  12. package/dist/components/charts/Boxplot/Boxplot.js.map +1 -1
  13. package/dist/components/charts/DotPlot/DotPlot.cjs +1 -1
  14. package/dist/components/charts/DotPlot/DotPlot.cjs.map +1 -1
  15. package/dist/components/charts/DotPlot/DotPlot.js +113 -83
  16. package/dist/components/charts/DotPlot/DotPlot.js.map +1 -1
  17. package/dist/components/charts/Histogram/Histogram.cjs +1 -1
  18. package/dist/components/charts/Histogram/Histogram.cjs.map +1 -1
  19. package/dist/components/charts/Histogram/Histogram.js +128 -105
  20. package/dist/components/charts/Histogram/Histogram.js.map +1 -1
  21. package/dist/components/charts/LineGraph/LineGraph.cjs +1 -1
  22. package/dist/components/charts/LineGraph/LineGraph.cjs.map +1 -1
  23. package/dist/components/charts/LineGraph/LineGraph.js +109 -87
  24. package/dist/components/charts/LineGraph/LineGraph.js.map +1 -1
  25. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs +1 -1
  26. package/dist/components/charts/ScatterGraph/ScatterGraph.cjs.map +1 -1
  27. package/dist/components/charts/ScatterGraph/ScatterGraph.js +114 -90
  28. package/dist/components/charts/ScatterGraph/ScatterGraph.js.map +1 -1
  29. package/dist/hooks/use-element-size.cjs +2 -0
  30. package/dist/hooks/use-element-size.cjs.map +1 -0
  31. package/dist/hooks/use-element-size.js +21 -0
  32. package/dist/hooks/use-element-size.js.map +1 -0
  33. package/dist/index.css +1 -1
  34. package/dist/index.d.ts +56 -0
  35. package/dist/index.tailwind.css +1 -1
  36. package/package.json +1 -1
@@ -1,158 +1,172 @@
1
- import { jsxs as A, jsx as P } from "react/jsx-runtime";
2
- import x from "plotly.js-dist";
3
- import { useRef as X, useMemo as c, useEffect as U } from "react";
4
- import { useChartTooltip as V } from "../ChartTooltip/ChartTooltip.js";
5
- import { usePlotlyTheme as B } from "../../../hooks/use-plotly-theme.js";
6
- import { seriesColor as Y } from "../../../utils/colors.js";
7
- const q = ({
8
- dataSeries: u,
9
- width: w = 1e3,
10
- height: v = 600,
11
- xRange: f,
12
- yRange: m,
13
- xTitle: d = "Columns",
14
- yTitle: g = "Rows",
15
- title: b = "Scatter Plot"
1
+ import { jsxs as G, jsx as O } from "react/jsx-runtime";
2
+ import g from "plotly.js-dist";
3
+ import { useRef as k, useMemo as m, useEffect as Y } from "react";
4
+ import { useChartTooltip as T } from "../ChartTooltip/ChartTooltip.js";
5
+ import { useElementSize as q } from "../../../hooks/use-element-size.js";
6
+ import { usePlotlyTheme as F } from "../../../hooks/use-plotly-theme.js";
7
+ import { cn as J } from "../../../lib/utils.js";
8
+ import { seriesColor as K } from "../../../utils/colors.js";
9
+ const it = ({
10
+ dataSeries: x,
11
+ width: I,
12
+ height: _,
13
+ xRange: u,
14
+ yRange: p,
15
+ xTitle: v,
16
+ yTitle: b,
17
+ title: L = "Scatter Plot"
16
18
  }) => {
17
- const p = X(null), e = B(), { bindTooltip: C, tooltipElement: N } = V({ xLabel: d, yLabel: g }), { xMin: E, xMax: z, yMin: I, yMax: _ } = c(() => {
18
- let r = Number.MAX_VALUE, t = Number.MIN_VALUE, n = Number.MAX_VALUE, o = Number.MIN_VALUE;
19
- u.forEach((l) => {
19
+ const a = k(null), r = F(), { bindTooltip: N, tooltipElement: j } = T({ xLabel: v, yLabel: b }), [H, A] = q(), s = I ?? A.width, c = _ ?? A.height, P = s > 0 && c > 0, W = I === void 0, D = _ === void 0, w = k({ width: s, height: c });
20
+ w.current = { width: s, height: c };
21
+ const E = k(!1), M = k({ width: 0, height: 0 }), { xMin: S, xMax: X, yMin: U, yMax: V } = m(() => {
22
+ let o = Number.MAX_VALUE, t = Number.MIN_VALUE, n = Number.MAX_VALUE, e = Number.MIN_VALUE;
23
+ x.forEach((l) => {
20
24
  l.x.forEach((i) => {
21
- r = Math.min(r, i), t = Math.max(t, i);
25
+ o = Math.min(o, i), t = Math.max(t, i);
22
26
  }), l.y.forEach((i) => {
23
- n = Math.min(n, i), o = Math.max(o, i);
27
+ n = Math.min(n, i), e = Math.max(e, i);
24
28
  });
25
29
  });
26
- const h = (t - r) * 0.1, y = (o - n) * 0.1;
30
+ const d = (t - o) * 0.1, y = (e - n) * 0.1;
27
31
  return {
28
- xMin: r - h,
29
- xMax: t + h,
32
+ xMin: o - d,
33
+ xMax: t + d,
30
34
  yMin: n - y,
31
- yMax: o + y
35
+ yMax: e + y
32
36
  };
33
- }, [u]), s = c(
34
- () => f || [E, z],
35
- [f, E, z]
36
- ), a = c(
37
- () => m || [I, _],
38
- [m, I, _]
39
- ), M = c(() => {
40
- const r = s[1] - s[0];
41
- let t = Math.pow(10, Math.floor(Math.log10(r)));
42
- r / t > 10 && (t = t * 2), r / t < 4 && (t = t / 2);
37
+ }, [x]), h = m(
38
+ () => u || [S, X],
39
+ [u, S, X]
40
+ ), f = m(
41
+ () => p || [U, V],
42
+ [p, U, V]
43
+ ), z = m(() => {
44
+ const o = h[1] - h[0];
45
+ let t = Math.pow(10, Math.floor(Math.log10(o)));
46
+ o / t > 10 && (t = t * 2), o / t < 4 && (t = t / 2);
43
47
  const n = [];
44
- let o = Math.ceil(s[0] / t) * t;
45
- for (; o <= s[1]; )
46
- n.push(o), o += t;
48
+ let e = Math.ceil(h[0] / t) * t;
49
+ for (; e <= h[1]; )
50
+ n.push(e), e += t;
47
51
  return n;
48
- }, [s]), L = c(() => {
49
- const r = a[1] - a[0];
50
- let t = Math.pow(10, Math.floor(Math.log10(r)));
51
- r / t > 10 && (t = t * 2), r / t < 4 && (t = t / 2);
52
+ }, [h]), B = m(() => {
53
+ const o = f[1] - f[0];
54
+ let t = Math.pow(10, Math.floor(Math.log10(o)));
55
+ o / t > 10 && (t = t * 2), o / t < 4 && (t = t / 2);
52
56
  const n = [];
53
- let o = Math.ceil(a[0] / t) * t;
54
- for (; o <= a[1]; )
55
- n.push(o), o += t;
57
+ let e = Math.ceil(f[0] / t) * t;
58
+ for (; e <= f[1]; )
59
+ n.push(e), e += t;
56
60
  return n;
57
- }, [a]), k = c(
61
+ }, [f]), C = m(
58
62
  () => ({
59
- tickcolor: e.tickColor,
63
+ tickcolor: r.tickColor,
60
64
  ticklen: 12,
61
65
  tickwidth: 1,
62
66
  ticks: "outside",
63
67
  tickfont: {
64
68
  size: 16,
65
- color: e.textColor,
69
+ color: r.textColor,
66
70
  family: "Inter, sans-serif",
67
71
  weight: 400
68
72
  },
69
- linecolor: e.lineColor,
73
+ linecolor: r.lineColor,
70
74
  linewidth: 1,
71
75
  position: 0,
72
76
  zeroline: !1
73
77
  }),
74
- [e]
78
+ [r]
75
79
  );
76
- return U(() => {
77
- if (!p.current) return;
78
- const r = u.map((l, i) => ({
80
+ return Y(() => {
81
+ if (!a.current || !P) return;
82
+ const o = x.map((l, i) => ({
79
83
  x: l.x,
80
84
  y: l.y,
81
85
  type: "scatter",
82
86
  mode: "markers",
83
87
  name: l.name,
84
88
  marker: {
85
- color: Y(i, l.color),
89
+ color: K(i, l.color),
86
90
  size: 10,
87
91
  symbol: "circle"
88
92
  },
89
93
  hoverinfo: "none"
90
94
  })), t = {
91
95
  title: {
92
- text: b,
96
+ text: L,
93
97
  font: {
94
98
  size: 32,
95
99
  family: "Inter, sans-serif",
96
- color: e.textColor
100
+ color: r.textColor
97
101
  }
98
102
  },
99
- width: w,
100
- height: v,
101
- margin: { l: 80, r: 30, b: 80, t: 60, pad: 10 },
102
- paper_bgcolor: e.paperBg,
103
- plot_bgcolor: e.plotBg,
103
+ width: w.current.width,
104
+ height: w.current.height,
105
+ // Bottom margin reserves room for tick labels, the x-axis title, and the
106
+ // container-anchored bottom legend stacked beneath them.
107
+ margin: { l: 80, r: 30, b: 96, t: 60, pad: 10 },
108
+ paper_bgcolor: r.paperBg,
109
+ plot_bgcolor: r.plotBg,
104
110
  font: {
105
111
  family: "Inter, sans-serif"
106
112
  },
107
113
  dragmode: !1,
108
114
  xaxis: {
109
115
  title: {
110
- text: d,
116
+ text: v,
111
117
  font: {
112
118
  size: 16,
113
- color: e.textSecondary,
119
+ color: r.textSecondary,
114
120
  family: "Inter, sans-serif",
115
121
  weight: 400
116
122
  },
117
123
  standoff: 32
118
124
  },
119
- gridcolor: e.gridColor,
120
- range: f,
121
- autorange: !f,
125
+ gridcolor: r.gridColor,
126
+ range: u,
127
+ autorange: !u,
122
128
  tickmode: "array",
123
- tickvals: M,
124
- ticktext: M.map(String),
129
+ tickvals: z,
130
+ ticktext: z.map(String),
125
131
  showgrid: !0,
126
- ...k
132
+ // Reserve space for tick labels + the axis title so the bottom legend
133
+ // can't overlap them at small sizes (SW-2157).
134
+ automargin: !0,
135
+ ...C
127
136
  },
128
137
  yaxis: {
129
138
  title: {
130
- text: g,
139
+ text: b,
131
140
  font: {
132
141
  size: 16,
133
- color: e.textSecondary,
142
+ color: r.textSecondary,
134
143
  family: "Inter, sans-serif",
135
144
  weight: 400
136
145
  },
137
146
  standoff: 30
138
147
  },
139
- gridcolor: e.gridColor,
140
- range: m,
141
- autorange: !m,
148
+ gridcolor: r.gridColor,
149
+ range: p,
150
+ autorange: !p,
142
151
  tickmode: "array",
143
- tickvals: L,
152
+ tickvals: B,
144
153
  showgrid: !0,
145
- ...k
154
+ automargin: !0,
155
+ ...C
146
156
  },
147
157
  legend: {
158
+ // Anchor to the bottom of the container (not the plot area) so the
159
+ // legend always clears the x-axis tick labels + title — a paper-relative
160
+ // fractional offset collapses into the ticks at small heights (SW-2157).
148
161
  x: 0.5,
149
- y: -0.2,
162
+ y: 0,
150
163
  xanchor: "center",
151
- yanchor: "top",
164
+ yanchor: "bottom",
165
+ yref: "container",
152
166
  orientation: "h",
153
167
  font: {
154
168
  size: 16,
155
- color: e.legendColor,
169
+ color: r.legendColor,
156
170
  family: "Inter, sans-serif",
157
171
  weight: 500
158
172
  }
@@ -160,15 +174,19 @@ const q = ({
160
174
  showlegend: !0,
161
175
  hovermode: "closest"
162
176
  }, n = {
163
- responsive: !0,
177
+ // Sizing is driven from the measured container; disable Plotly's own
178
+ // window-resize responsiveness (it can't see container resizes).
179
+ responsive: !1,
164
180
  displayModeBar: !1,
165
181
  displaylogo: !1
166
182
  };
167
- x.newPlot(p.current, r, t, n), C(p.current);
168
- const o = p.current, h = o, y = { color: e.spikeColor, width: 2 };
169
- return h.on("plotly_hover", (l) => {
183
+ g.newPlot(a.current, o, t, n), N(a.current);
184
+ const e = a.current;
185
+ E.current = !0, M.current = { ...w.current };
186
+ const d = e, y = { color: r.spikeColor, width: 2 };
187
+ return d.on("plotly_hover", (l) => {
170
188
  const i = l.points[0];
171
- i && x.relayout(o, {
189
+ i && g.relayout(e, {
172
190
  shapes: [
173
191
  {
174
192
  type: "line",
@@ -194,17 +212,23 @@ const q = ({
194
212
  }
195
213
  ]
196
214
  });
197
- }), h.on("plotly_unhover", () => {
198
- x.relayout(o, { shapes: [] });
215
+ }), d.on("plotly_unhover", () => {
216
+ g.relayout(e, { shapes: [] });
199
217
  }), () => {
200
- o && x.purge(o);
218
+ e && (g.purge(e), E.current = !1);
201
219
  };
202
- }, [u, w, v, f, m, d, g, b, s, a, M, L, k, e, C]), /* @__PURE__ */ A("div", { className: "relative size-full", children: [
203
- /* @__PURE__ */ P("div", { ref: p, style: { width: "100%", height: "100%" } }),
204
- N
220
+ }, [x, P, u, p, v, b, L, h, f, z, B, C, r, N]), Y(() => {
221
+ const o = a.current;
222
+ !o || !E.current || s <= 0 || c <= 0 || M.current.width === s && M.current.height === c || (M.current = { width: s, height: c }, g.relayout(o, { width: s, height: c }).catch(
223
+ () => {
224
+ }
225
+ ));
226
+ }, [s, c]), /* @__PURE__ */ G("div", { ref: H, className: J("relative", W && "w-full", D && "h-full"), children: [
227
+ /* @__PURE__ */ O("div", { ref: a, style: { width: "100%", height: "100%" } }),
228
+ j
205
229
  ] });
206
230
  };
207
231
  export {
208
- q as ScatterGraph
232
+ it as ScatterGraph
209
233
  };
210
234
  //# sourceMappingURL=ScatterGraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ScatterGraph.js","sources":["../../../../src/components/charts/ScatterGraph/ScatterGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface ScatterDataPoint {\n x: number;\n y: number;\n additionalInfo?: Record<string, string | number>;\n}\n\ninterface ScatterDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n}\n\ninterface ScatterGraphProps {\n dataSeries: ScatterDataSeries[];\n width?: number;\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n xTitle?: string;\n yTitle?: string;\n title?: string;\n}\n\nconst ScatterGraph: React.FC<ScatterGraphProps> = ({\n dataSeries,\n width = 1000,\n height = 600,\n xRange,\n yRange,\n xTitle = \"Columns\",\n yTitle = \"Rows\",\n title = \"Scatter Plot\",\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current) return;\n\n const plotData = dataSeries.map((series, index) => ({\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: \"markers\" as const,\n name: series.name,\n marker: {\n color: seriesColor(index, series.color),\n size: 10,\n symbol: \"circle\" as const,\n },\n hoverinfo: \"none\" as const,\n }));\n\n const layout = {\n title: {\n text: title,\n font: {\n size: 32,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n },\n width,\n height,\n margin: { l: 80, r: 30, b: 80, t: 60, pad: 10 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n ticktext: xTicks.map(String),\n showgrid: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n ...tickOptions,\n },\n legend: {\n x: 0.5,\n y: -0.2,\n xanchor: \"center\" as const,\n yanchor: \"top\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n },\n },\n showlegend: true,\n hovermode: \"closest\" as const,\n };\n\n const config = {\n responsive: true,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n\n // Crosshair guide lines through the hovered point. Drawn as layout shapes\n // with `layer: \"below\"` so they sit behind the markers — native Plotly\n // spikelines always render on top and can't be moved behind.\n const emitter = plotElement as unknown as Plotly.PlotlyHTMLElement;\n const crosshairLine = { color: theme.spikeColor, width: 2 };\n emitter.on(\"plotly_hover\", (eventData) => {\n const point = eventData.points[0];\n if (!point) return;\n void Plotly.relayout(plotElement, {\n shapes: [\n {\n type: \"line\",\n xref: \"x\",\n yref: \"paper\",\n x0: point.x,\n x1: point.x,\n y0: 0,\n y1: 1,\n line: crosshairLine,\n layer: \"below\",\n },\n {\n type: \"line\",\n xref: \"paper\",\n yref: \"y\",\n x0: 0,\n x1: 1,\n y0: point.y,\n y1: point.y,\n line: crosshairLine,\n layer: \"below\",\n },\n ],\n });\n });\n emitter.on(\"plotly_unhover\", () => {\n void Plotly.relayout(plotElement, { shapes: [] });\n });\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n }\n };\n }, [dataSeries, width, height, xRange, yRange, xTitle, yTitle, title, effectiveXRange, effectiveYRange, xTicks, yTicks, tickOptions, theme, bindTooltip]);\n\n return (\n <div className=\"relative size-full\">\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { ScatterGraph };\nexport type { ScatterDataPoint, ScatterDataSeries, ScatterGraphProps };\n"],"names":["ScatterGraph","dataSeries","width","height","xRange","yRange","xTitle","yTitle","title","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","useEffect","plotData","index","seriesColor","layout","config","Plotly","plotElement","emitter","crosshairLine","eventData","point","jsxs","jsx"],"mappings":"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"}
1
+ {"version":3,"file":"ScatterGraph.js","sources":["../../../../src/components/charts/ScatterGraph/ScatterGraph.tsx"],"sourcesContent":["import Plotly from \"plotly.js-dist\";\nimport React, { useEffect, useRef, useMemo } from \"react\";\n\nimport { useChartTooltip } from \"../ChartTooltip\";\n\nimport { useElementSize } from \"@/hooks/use-element-size\";\nimport { usePlotlyTheme } from \"@/hooks/use-plotly-theme\";\nimport { cn } from \"@/lib/utils\";\nimport { seriesColor } from \"@/utils/colors\";\n\ninterface ScatterDataPoint {\n x: number;\n y: number;\n additionalInfo?: Record<string, string | number>;\n}\n\ninterface ScatterDataSeries {\n x: number[];\n y: number[];\n name: string;\n /** Optional color override (auto-assigned from CHART_COLORS if not provided) */\n color?: string;\n}\n\ninterface ScatterGraphProps {\n dataSeries: ScatterDataSeries[];\n /**\n * Fixed width in pixels. When omitted, the chart fills its container and\n * tracks the container's width via a `ResizeObserver`.\n */\n width?: number;\n /**\n * Fixed height in pixels. When omitted, the chart fills its container and\n * tracks the container's height via a `ResizeObserver`.\n */\n height?: number;\n xRange?: [number, number];\n yRange?: [number, number];\n xTitle?: string;\n yTitle?: string;\n title?: string;\n}\n\nconst ScatterGraph: React.FC<ScatterGraphProps> = ({\n dataSeries,\n width,\n height,\n xRange,\n yRange,\n xTitle,\n yTitle,\n title = \"Scatter Plot\",\n}) => {\n const plotRef = useRef<HTMLDivElement>(null);\n const theme = usePlotlyTheme();\n const { bindTooltip, tooltipElement } = useChartTooltip({ xLabel: xTitle, yLabel: yTitle });\n\n // Omitted width/height → fill the container and track its measured size;\n // explicit pixel values override. See AreaGraph for the reference pattern.\n const [containerRef, measured] = useElementSize<HTMLDivElement>();\n const resolvedWidth = width ?? measured.width;\n const resolvedHeight = height ?? measured.height;\n const hasSize = resolvedWidth > 0 && resolvedHeight > 0;\n // Fill is per-dimension: omit width to fill the container width, omit height\n // to fill its height (so e.g. a fixed width with a container-driven height works).\n const fillWidth = width === undefined;\n const fillHeight = height === undefined;\n const sizeRef = useRef({ width: resolvedWidth, height: resolvedHeight });\n sizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n const plotInitedRef = useRef(false);\n // Size last applied to the plot, so the resize effect can skip a redundant\n // relayout right after newPlot already drew at that size.\n const appliedSizeRef = useRef({ width: 0, height: 0 });\n\n const { xMin, xMax, yMin, yMax } = useMemo(() => {\n let minX = Number.MAX_VALUE;\n let maxX = Number.MIN_VALUE;\n let minY = Number.MAX_VALUE;\n let maxY = Number.MIN_VALUE;\n\n dataSeries.forEach((series) => {\n series.x.forEach((x) => {\n minX = Math.min(minX, x);\n maxX = Math.max(maxX, x);\n });\n series.y.forEach((y) => {\n minY = Math.min(minY, y);\n maxY = Math.max(maxY, y);\n });\n });\n\n const xPadding = (maxX - minX) * 0.1;\n const yPadding = (maxY - minY) * 0.1;\n\n return {\n xMin: minX - xPadding,\n xMax: maxX + xPadding,\n yMin: minY - yPadding,\n yMax: maxY + yPadding,\n };\n }, [dataSeries]);\n\n const effectiveXRange = useMemo(\n () => xRange || [xMin, xMax],\n [xRange, xMin, xMax],\n );\n\n const effectiveYRange = useMemo(\n () => yRange || [yMin, yMax],\n [yRange, yMin, yMax],\n );\n\n const xTicks = useMemo(() => {\n const range = effectiveXRange[1] - effectiveXRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveXRange[0] / step) * step;\n while (current <= effectiveXRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveXRange]);\n\n const yTicks = useMemo(() => {\n const range = effectiveYRange[1] - effectiveYRange[0];\n let step = Math.pow(10, Math.floor(Math.log10(range)));\n\n if (range / step > 10) step = step * 2;\n if (range / step < 4) step = step / 2;\n\n const ticks = [];\n let current = Math.ceil(effectiveYRange[0] / step) * step;\n while (current <= effectiveYRange[1]) {\n ticks.push(current);\n current += step;\n }\n return ticks;\n }, [effectiveYRange]);\n\n const tickOptions = useMemo(\n () => ({\n tickcolor: theme.tickColor,\n ticklen: 12,\n tickwidth: 1,\n ticks: \"outside\" as const,\n tickfont: {\n size: 16,\n color: theme.textColor,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n linecolor: theme.lineColor,\n linewidth: 1,\n position: 0,\n zeroline: false,\n }),\n [theme],\n );\n\n useEffect(() => {\n if (!plotRef.current || !hasSize) return;\n\n const plotData = dataSeries.map((series, index) => ({\n x: series.x,\n y: series.y,\n type: \"scatter\" as const,\n mode: \"markers\" as const,\n name: series.name,\n marker: {\n color: seriesColor(index, series.color),\n size: 10,\n symbol: \"circle\" as const,\n },\n hoverinfo: \"none\" as const,\n }));\n\n const layout = {\n title: {\n text: title,\n font: {\n size: 32,\n family: \"Inter, sans-serif\",\n color: theme.textColor,\n },\n },\n width: sizeRef.current.width,\n height: sizeRef.current.height,\n // Bottom margin reserves room for tick labels, the x-axis title, and the\n // container-anchored bottom legend stacked beneath them.\n margin: { l: 80, r: 30, b: 96, t: 60, pad: 10 },\n paper_bgcolor: theme.paperBg,\n plot_bgcolor: theme.plotBg,\n font: {\n family: \"Inter, sans-serif\",\n },\n dragmode: false as const,\n xaxis: {\n title: {\n text: xTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 32,\n },\n gridcolor: theme.gridColor,\n range: xRange,\n autorange: !xRange,\n tickmode: \"array\" as const,\n tickvals: xTicks,\n ticktext: xTicks.map(String),\n showgrid: true,\n // Reserve space for tick labels + the axis title so the bottom legend\n // can't overlap them at small sizes (SW-2157).\n automargin: true,\n ...tickOptions,\n },\n yaxis: {\n title: {\n text: yTitle,\n font: {\n size: 16,\n color: theme.textSecondary,\n family: \"Inter, sans-serif\",\n weight: 400,\n },\n standoff: 30,\n },\n gridcolor: theme.gridColor,\n range: yRange,\n autorange: !yRange,\n tickmode: \"array\" as const,\n tickvals: yTicks,\n showgrid: true,\n automargin: true,\n ...tickOptions,\n },\n legend: {\n // Anchor to the bottom of the container (not the plot area) so the\n // legend always clears the x-axis tick labels + title — a paper-relative\n // fractional offset collapses into the ticks at small heights (SW-2157).\n x: 0.5,\n y: 0,\n xanchor: \"center\" as const,\n yanchor: \"bottom\" as const,\n yref: \"container\" as const,\n orientation: \"h\" as const,\n font: {\n size: 16,\n color: theme.legendColor,\n family: \"Inter, sans-serif\",\n weight: 500,\n },\n },\n showlegend: true,\n hovermode: \"closest\" as const,\n };\n\n const config = {\n // Sizing is driven from the measured container; disable Plotly's own\n // window-resize responsiveness (it can't see container resizes).\n responsive: false,\n displayModeBar: false,\n displaylogo: false,\n };\n\n Plotly.newPlot(plotRef.current, plotData, layout, config);\n bindTooltip(plotRef.current);\n\n // Capture ref value for cleanup\n const plotElement = plotRef.current;\n plotInitedRef.current = true;\n appliedSizeRef.current = { ...sizeRef.current };\n\n // Crosshair guide lines through the hovered point. Drawn as layout shapes\n // with `layer: \"below\"` so they sit behind the markers — native Plotly\n // spikelines always render on top and can't be moved behind.\n const emitter = plotElement as unknown as Plotly.PlotlyHTMLElement;\n const crosshairLine = { color: theme.spikeColor, width: 2 };\n emitter.on(\"plotly_hover\", (eventData) => {\n const point = eventData.points[0];\n if (!point) return;\n void Plotly.relayout(plotElement, {\n shapes: [\n {\n type: \"line\",\n xref: \"x\",\n yref: \"paper\",\n x0: point.x,\n x1: point.x,\n y0: 0,\n y1: 1,\n line: crosshairLine,\n layer: \"below\",\n },\n {\n type: \"line\",\n xref: \"paper\",\n yref: \"y\",\n x0: 0,\n x1: 1,\n y0: point.y,\n y1: point.y,\n line: crosshairLine,\n layer: \"below\",\n },\n ],\n });\n });\n emitter.on(\"plotly_unhover\", () => {\n void Plotly.relayout(plotElement, { shapes: [] });\n });\n\n return () => {\n if (plotElement) {\n Plotly.purge(plotElement);\n plotInitedRef.current = false;\n }\n };\n }, [dataSeries, hasSize, xRange, yRange, xTitle, yTitle, title, effectiveXRange, effectiveYRange, xTicks, yTicks, tickOptions, theme, bindTooltip]);\n\n // Resize in place when the measured/overridden size changes — cheaper than\n // recreating the plot, and it preserves the hover/crosshair event bindings.\n useEffect(() => {\n const plotElement = plotRef.current;\n if (!plotElement || !plotInitedRef.current || resolvedWidth <= 0 || resolvedHeight <= 0) {\n return;\n }\n // newPlot already drew at the current size; skip the redundant relayout\n // (it would queue an automargin redraw that can reject if we unmount first).\n if (\n appliedSizeRef.current.width === resolvedWidth &&\n appliedSizeRef.current.height === resolvedHeight\n ) {\n return;\n }\n appliedSizeRef.current = { width: resolvedWidth, height: resolvedHeight };\n // Swallow rejections from a relayout that races an unmount/purge.\n void Plotly.relayout(plotElement, { width: resolvedWidth, height: resolvedHeight }).catch(\n () => {},\n );\n }, [resolvedWidth, resolvedHeight]);\n\n return (\n <div ref={containerRef} className={cn(\"relative\", fillWidth && \"w-full\", fillHeight && \"h-full\")}>\n <div ref={plotRef} style={{ width: \"100%\", height: \"100%\" }} />\n {tooltipElement}\n </div>\n );\n};\n\nexport { ScatterGraph };\nexport type { ScatterDataPoint, ScatterDataSeries, ScatterGraphProps };\n"],"names":["ScatterGraph","dataSeries","width","height","xRange","yRange","xTitle","yTitle","title","plotRef","useRef","theme","usePlotlyTheme","bindTooltip","tooltipElement","useChartTooltip","containerRef","measured","useElementSize","resolvedWidth","resolvedHeight","hasSize","fillWidth","fillHeight","sizeRef","plotInitedRef","appliedSizeRef","xMin","xMax","yMin","yMax","useMemo","minX","maxX","minY","maxY","series","x","y","xPadding","yPadding","effectiveXRange","effectiveYRange","xTicks","range","step","ticks","current","yTicks","tickOptions","useEffect","plotData","index","seriesColor","layout","config","Plotly","plotElement","emitter","crosshairLine","eventData","point","jsxs","cn","jsx"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const n=require("react");function f(){const r=n.useRef(null),[u,h]=n.useState({width:0,height:0});return n.useEffect(()=>{const s=r.current;if(!s||typeof ResizeObserver>"u")return;const i=new ResizeObserver(d=>{const e=d[0];if(!e)return;const o=Math.round(e.contentRect.width),c=Math.round(e.contentRect.height);h(t=>t.width===o&&t.height===c?t:{width:o,height:c})});return i.observe(s),()=>i.disconnect()},[]),[r,u]}exports.useElementSize=f;
2
+ //# sourceMappingURL=use-element-size.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-element-size.cjs","sources":["../../src/hooks/use-element-size.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/** Element dimensions in CSS pixels, rounded to whole numbers. */\nexport interface ElementSize {\n width: number;\n height: number;\n}\n\n/**\n * Observe an element's content-box size with a `ResizeObserver` and return the\n * latest rounded `{ width, height }`.\n *\n * Attach the returned `ref` to the element whose size should drive layout\n * (e.g. the flex/grid cell a chart needs to fill). The size is `{ 0, 0 }` until\n * the first measurement, and stays `{ 0, 0 }` in environments without a\n * `ResizeObserver` (e.g. SSR), so callers should treat a zero dimension as\n * \"not yet measured\" and skip work that needs real pixels.\n *\n * @example\n * ```tsx\n * const [containerRef, { width, height }] = useElementSize<HTMLDivElement>();\n * return <div ref={containerRef} className=\"size-full\">…</div>;\n * ```\n */\nexport function useElementSize<T extends HTMLElement = HTMLDivElement>(): [\n React.RefObject<T | null>,\n ElementSize,\n] {\n const ref = useRef<T>(null);\n const [size, setSize] = useState<ElementSize>({ width: 0, height: 0 });\n\n useEffect(() => {\n const element = ref.current;\n if (!element || typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry) return;\n const width = Math.round(entry.contentRect.width);\n const height = Math.round(entry.contentRect.height);\n // Bail on identical measurements so consumers driving Plotly layout off\n // this size don't trigger a redundant relayout (and a feedback loop).\n setSize((prev) =>\n prev.width === width && prev.height === height ? prev : { width, height },\n );\n });\n\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n return [ref, size];\n}\n"],"names":["useElementSize","ref","useRef","size","setSize","useState","useEffect","element","observer","entries","entry","width","height","prev"],"mappings":"yGAwBO,SAASA,GAGd,CACA,MAAMC,EAAMC,EAAAA,OAAU,IAAI,EACpB,CAACC,EAAMC,CAAO,EAAIC,EAAAA,SAAsB,CAAE,MAAO,EAAG,OAAQ,EAAG,EAErEC,OAAAA,EAAAA,UAAU,IAAM,CACd,MAAMC,EAAUN,EAAI,QACpB,GAAI,CAACM,GAAW,OAAO,eAAmB,IAAa,OAEvD,MAAMC,EAAW,IAAI,eAAgBC,GAAY,CAC/C,MAAMC,EAAQD,EAAQ,CAAC,EACvB,GAAI,CAACC,EAAO,OACZ,MAAMC,EAAQ,KAAK,MAAMD,EAAM,YAAY,KAAK,EAC1CE,EAAS,KAAK,MAAMF,EAAM,YAAY,MAAM,EAGlDN,EAASS,GACPA,EAAK,QAAUF,GAASE,EAAK,SAAWD,EAASC,EAAO,CAAE,MAAAF,EAAO,OAAAC,CAAA,CAAO,CAE5E,CAAC,EAED,OAAAJ,EAAS,QAAQD,CAAO,EACjB,IAAMC,EAAS,WAAA,CACxB,EAAG,CAAA,CAAE,EAEE,CAACP,EAAKE,CAAI,CACnB"}
@@ -0,0 +1,21 @@
1
+ import { useRef as f, useState as d, useEffect as w } from "react";
2
+ function R() {
3
+ const n = f(null), [c, h] = d({ width: 0, height: 0 });
4
+ return w(() => {
5
+ const r = n.current;
6
+ if (!r || typeof ResizeObserver > "u") return;
7
+ const s = new ResizeObserver((u) => {
8
+ const e = u[0];
9
+ if (!e) return;
10
+ const i = Math.round(e.contentRect.width), o = Math.round(e.contentRect.height);
11
+ h(
12
+ (t) => t.width === i && t.height === o ? t : { width: i, height: o }
13
+ );
14
+ });
15
+ return s.observe(r), () => s.disconnect();
16
+ }, []), [n, c];
17
+ }
18
+ export {
19
+ R as useElementSize
20
+ };
21
+ //# sourceMappingURL=use-element-size.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-element-size.js","sources":["../../src/hooks/use-element-size.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\n\n/** Element dimensions in CSS pixels, rounded to whole numbers. */\nexport interface ElementSize {\n width: number;\n height: number;\n}\n\n/**\n * Observe an element's content-box size with a `ResizeObserver` and return the\n * latest rounded `{ width, height }`.\n *\n * Attach the returned `ref` to the element whose size should drive layout\n * (e.g. the flex/grid cell a chart needs to fill). The size is `{ 0, 0 }` until\n * the first measurement, and stays `{ 0, 0 }` in environments without a\n * `ResizeObserver` (e.g. SSR), so callers should treat a zero dimension as\n * \"not yet measured\" and skip work that needs real pixels.\n *\n * @example\n * ```tsx\n * const [containerRef, { width, height }] = useElementSize<HTMLDivElement>();\n * return <div ref={containerRef} className=\"size-full\">…</div>;\n * ```\n */\nexport function useElementSize<T extends HTMLElement = HTMLDivElement>(): [\n React.RefObject<T | null>,\n ElementSize,\n] {\n const ref = useRef<T>(null);\n const [size, setSize] = useState<ElementSize>({ width: 0, height: 0 });\n\n useEffect(() => {\n const element = ref.current;\n if (!element || typeof ResizeObserver === \"undefined\") return;\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0];\n if (!entry) return;\n const width = Math.round(entry.contentRect.width);\n const height = Math.round(entry.contentRect.height);\n // Bail on identical measurements so consumers driving Plotly layout off\n // this size don't trigger a redundant relayout (and a feedback loop).\n setSize((prev) =>\n prev.width === width && prev.height === height ? prev : { width, height },\n );\n });\n\n observer.observe(element);\n return () => observer.disconnect();\n }, []);\n\n return [ref, size];\n}\n"],"names":["useElementSize","ref","useRef","size","setSize","useState","useEffect","element","observer","entries","entry","width","height","prev"],"mappings":";AAwBO,SAASA,IAGd;AACA,QAAMC,IAAMC,EAAU,IAAI,GACpB,CAACC,GAAMC,CAAO,IAAIC,EAAsB,EAAE,OAAO,GAAG,QAAQ,GAAG;AAErE,SAAAC,EAAU,MAAM;AACd,UAAMC,IAAUN,EAAI;AACpB,QAAI,CAACM,KAAW,OAAO,iBAAmB,IAAa;AAEvD,UAAMC,IAAW,IAAI,eAAe,CAACC,MAAY;AAC/C,YAAMC,IAAQD,EAAQ,CAAC;AACvB,UAAI,CAACC,EAAO;AACZ,YAAMC,IAAQ,KAAK,MAAMD,EAAM,YAAY,KAAK,GAC1CE,IAAS,KAAK,MAAMF,EAAM,YAAY,MAAM;AAGlD,MAAAN;AAAA,QAAQ,CAACS,MACPA,EAAK,UAAUF,KAASE,EAAK,WAAWD,IAASC,IAAO,EAAE,OAAAF,GAAO,QAAAC,EAAA;AAAA,MAAO;AAAA,IAE5E,CAAC;AAED,WAAAJ,EAAS,QAAQD,CAAO,GACjB,MAAMC,EAAS,WAAA;AAAA,EACxB,GAAG,CAAA,CAAE,GAEE,CAACP,GAAKE,CAAI;AACnB;"}