@carto/ps-react-ui 4.25.0 → 4.27.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.
Files changed (91) hide show
  1. package/dist/actions-DON6fSCh.js +1289 -0
  2. package/dist/actions-DON6fSCh.js.map +1 -0
  3. package/dist/category-BoT5FHHp.js +950 -0
  4. package/dist/category-BoT5FHHp.js.map +1 -0
  5. package/dist/item-color-C1cu6EJd.js +20 -0
  6. package/dist/item-color-C1cu6EJd.js.map +1 -0
  7. package/dist/scale-0elCv3tk.js +29 -0
  8. package/dist/scale-0elCv3tk.js.map +1 -0
  9. package/dist/types/widgets-v2/actions/index.d.ts +1 -1
  10. package/dist/types/widgets-v2/actions/relative-data/index.d.ts +1 -0
  11. package/dist/types/widgets-v2/actions/relative-data/labels.d.ts +3 -0
  12. package/dist/types/widgets-v2/actions/relative-data/relative-data.d.ts +16 -2
  13. package/dist/types/widgets-v2/actions/relative-data/scale.d.ts +26 -0
  14. package/dist/types/widgets-v2/actions/relative-data/style.d.ts +12 -0
  15. package/dist/types/widgets-v2/bar/types.d.ts +6 -0
  16. package/dist/types/widgets-v2/category/category.d.ts +2 -1
  17. package/dist/types/widgets-v2/histogram/bins.d.ts +7 -0
  18. package/dist/types/widgets-v2/histogram/download.d.ts +2 -2
  19. package/dist/types/widgets-v2/histogram/index.d.ts +2 -1
  20. package/dist/types/widgets-v2/histogram/options.d.ts +1 -1
  21. package/dist/types/widgets-v2/histogram/transforms.d.ts +5 -4
  22. package/dist/types/widgets-v2/histogram/types.d.ts +22 -5
  23. package/dist/types/widgets-v2/index.d.ts +2 -2
  24. package/dist/types/widgets-v2/pie/types.d.ts +6 -0
  25. package/dist/types/widgets-v2/scatterplot/download.d.ts +2 -2
  26. package/dist/types/widgets-v2/scatterplot/index.d.ts +2 -1
  27. package/dist/types/widgets-v2/scatterplot/points.d.ts +7 -0
  28. package/dist/types/widgets-v2/scatterplot/transforms.d.ts +4 -3
  29. package/dist/types/widgets-v2/scatterplot/types.d.ts +21 -2
  30. package/dist/types/widgets-v2/timeseries/types.d.ts +6 -0
  31. package/dist/types/widgets-v2/utils/item-color.d.ts +26 -0
  32. package/dist/widgets-v2/actions.js +1 -1
  33. package/dist/widgets-v2/bar.js +91 -81
  34. package/dist/widgets-v2/bar.js.map +1 -1
  35. package/dist/widgets-v2/category.js +1 -1
  36. package/dist/widgets-v2/histogram.js +133 -100
  37. package/dist/widgets-v2/histogram.js.map +1 -1
  38. package/dist/widgets-v2/pie.js +98 -78
  39. package/dist/widgets-v2/pie.js.map +1 -1
  40. package/dist/widgets-v2/scatterplot.js +151 -110
  41. package/dist/widgets-v2/scatterplot.js.map +1 -1
  42. package/dist/widgets-v2/timeseries.js +96 -86
  43. package/dist/widgets-v2/timeseries.js.map +1 -1
  44. package/dist/widgets-v2.js +2 -2
  45. package/dist/widgets-v2.js.map +1 -1
  46. package/package.json +1 -1
  47. package/src/widgets-v2/actions/fullscreen/fullscreen-store.test.tsx +77 -13
  48. package/src/widgets-v2/actions/fullscreen/fullscreen.tsx +48 -5
  49. package/src/widgets-v2/actions/index.ts +1 -0
  50. package/src/widgets-v2/actions/relative-data/index.ts +1 -0
  51. package/src/widgets-v2/actions/relative-data/labels.ts +6 -0
  52. package/src/widgets-v2/actions/relative-data/relative-data.test.tsx +78 -1
  53. package/src/widgets-v2/actions/relative-data/relative-data.tsx +137 -20
  54. package/src/widgets-v2/actions/relative-data/scale.ts +48 -0
  55. package/src/widgets-v2/actions/relative-data/style.ts +10 -0
  56. package/src/widgets-v2/bar/options.test.ts +122 -0
  57. package/src/widgets-v2/bar/options.ts +31 -16
  58. package/src/widgets-v2/bar/types.ts +6 -0
  59. package/src/widgets-v2/category/category.relative-data.test.tsx +51 -63
  60. package/src/widgets-v2/category/category.tsx +25 -11
  61. package/src/widgets-v2/histogram/bins.ts +22 -0
  62. package/src/widgets-v2/histogram/download.test.ts +10 -0
  63. package/src/widgets-v2/histogram/download.ts +7 -3
  64. package/src/widgets-v2/histogram/index.ts +3 -0
  65. package/src/widgets-v2/histogram/options.test.ts +62 -0
  66. package/src/widgets-v2/histogram/options.ts +44 -19
  67. package/src/widgets-v2/histogram/transforms.test.ts +21 -7
  68. package/src/widgets-v2/histogram/transforms.ts +26 -12
  69. package/src/widgets-v2/histogram/types.ts +25 -5
  70. package/src/widgets-v2/index.ts +7 -1
  71. package/src/widgets-v2/pie/options.test.ts +91 -0
  72. package/src/widgets-v2/pie/options.ts +50 -20
  73. package/src/widgets-v2/pie/types.ts +6 -0
  74. package/src/widgets-v2/scatterplot/download.test.ts +9 -0
  75. package/src/widgets-v2/scatterplot/download.ts +5 -3
  76. package/src/widgets-v2/scatterplot/index.ts +3 -0
  77. package/src/widgets-v2/scatterplot/options.test.ts +90 -0
  78. package/src/widgets-v2/scatterplot/options.ts +53 -15
  79. package/src/widgets-v2/scatterplot/points.ts +35 -0
  80. package/src/widgets-v2/scatterplot/transforms.test.ts +19 -0
  81. package/src/widgets-v2/scatterplot/transforms.ts +23 -18
  82. package/src/widgets-v2/scatterplot/types.ts +25 -2
  83. package/src/widgets-v2/timeseries/options.test.ts +65 -0
  84. package/src/widgets-v2/timeseries/options.ts +38 -19
  85. package/src/widgets-v2/timeseries/types.ts +6 -0
  86. package/src/widgets-v2/utils/item-color.test.ts +74 -0
  87. package/src/widgets-v2/utils/item-color.ts +55 -0
  88. package/dist/actions-B1ss030_.js +0 -1167
  89. package/dist/actions-B1ss030_.js.map +0 -1
  90. package/dist/category-DuKx_CJX.js +0 -933
  91. package/dist/category-DuKx_CJX.js.map +0 -1
@@ -1,19 +1,45 @@
1
1
  import { r as e } from "../zoom-toggle-KA63b6-J.js";
2
- import { n as t, t as n } from "../download--wRRnf19.js";
3
- import { r, t as i } from "../utils-ClB6nn4w.js";
4
- import { a, d as o, f as s, i as c, s as l, u } from "../chart-config-BWxjodlt.js";
5
- import { c as d } from "react/compiler-runtime";
6
- import { Box as f, Skeleton as p } from "@mui/material";
7
- import { jsx as m, jsxs as h } from "react/jsx-runtime";
8
- import * as g from "echarts";
2
+ import { n as t } from "../scale-0elCv3tk.js";
3
+ import { n, t as r } from "../download--wRRnf19.js";
4
+ import { r as i, t as a } from "../utils-ClB6nn4w.js";
5
+ import { a as o, d as s, f as c, i as l, s as u, u as d } from "../chart-config-BWxjodlt.js";
6
+ import { t as f } from "../item-color-C1cu6EJd.js";
7
+ import { c as p } from "react/compiler-runtime";
8
+ import { Box as m, Skeleton as h } from "@mui/material";
9
+ import { jsx as g, jsxs as _ } from "react/jsx-runtime";
10
+ import * as v from "echarts";
11
+ //#region src/widgets-v2/scatterplot/points.ts
12
+ function y(e) {
13
+ return S(e) ? e : [e.x, e.y];
14
+ }
15
+ function b(e) {
16
+ if (Array.isArray(e)) return e.length === 2 && C(e[0]) && C(e[1]);
17
+ if (typeof e != "object" || !e) return !1;
18
+ let { x: t, y: n } = e;
19
+ return C(t) && C(n);
20
+ }
21
+ function x(e, t, n) {
22
+ return S(e) ? [t, n] : {
23
+ ...e,
24
+ x: t,
25
+ y: n
26
+ };
27
+ }
28
+ function S(e) {
29
+ return Array.isArray(e);
30
+ }
31
+ function C(e) {
32
+ return typeof e == "number" && Number.isFinite(e);
33
+ }
34
+ //#endregion
9
35
  //#region src/widgets-v2/scatterplot/options.ts
10
- function _({ theme: e, xFormatter: t, yFormatter: n }) {
36
+ function w({ theme: e, xFormatter: t, yFormatter: n }) {
11
37
  return {
12
38
  grid: {
13
39
  left: parseInt(e.spacing(1)),
14
40
  top: parseInt(e.spacing(3)),
15
41
  right: parseInt(e.spacing(1)),
16
- ...a(!1, e),
42
+ ...o(!1, e),
17
43
  containLabel: !0
18
44
  },
19
45
  tooltip: {
@@ -26,10 +52,10 @@ function _({ theme: e, xFormatter: t, yFormatter: n }) {
26
52
  fontSize: 11,
27
53
  fontFamily: e.typography.caption.fontFamily
28
54
  },
29
- position: o(e),
30
- formatter: x(t, n)
55
+ position: s(e),
56
+ formatter: O(t, n)
31
57
  },
32
- legend: { ...l({
58
+ legend: { ...u({
33
59
  hasLegend: !1,
34
60
  labelFormatter: void 0
35
61
  }) },
@@ -40,7 +66,7 @@ function _({ theme: e, xFormatter: t, yFormatter: n }) {
40
66
  axisLine: { show: !1 },
41
67
  axisTick: { show: !1 },
42
68
  axisLabel: {
43
- ...c(e),
69
+ ...l(e),
44
70
  margin: parseInt(e.spacing(1)),
45
71
  hideOverlap: !0,
46
72
  showMinLabel: !0,
@@ -57,7 +83,7 @@ function _({ theme: e, xFormatter: t, yFormatter: n }) {
57
83
  axisLine: { show: !1 },
58
84
  axisTick: { show: !1 },
59
85
  axisLabel: {
60
- ...c(e),
86
+ ...l(e),
61
87
  margin: parseInt(e.spacing(1)),
62
88
  hideOverlap: !0,
63
89
  showMinLabel: !0,
@@ -71,80 +97,88 @@ function _({ theme: e, xFormatter: t, yFormatter: n }) {
71
97
  }
72
98
  };
73
99
  }
74
- function v(t) {
75
- let { theme: n, xFormatter: a, yFormatter: o, optionsOverride: s } = t, c = t.series, l = t.symbolSize ?? 8, u = t.selection, d = u && u.length > 0 ? new Set(u) : null;
76
- return (t, u, f) => {
77
- if (t == null) {
78
- let e = _({
79
- theme: n,
80
- xFormatter: a,
81
- yFormatter: o
100
+ function T(n) {
101
+ let { theme: r, xFormatter: o, yFormatter: s, optionsOverride: c } = n, l = n.series, u = n.symbolSize ?? 8, d = n.selection, p = d && d.length > 0 ? new Set(d) : null;
102
+ return (n, d, m) => {
103
+ if (n == null) {
104
+ let e = w({
105
+ theme: r,
106
+ xFormatter: o,
107
+ yFormatter: s
82
108
  });
83
- return s ? r(e, s) : e;
109
+ return c ? i(e, c) : e;
84
110
  }
85
- let p = Array.isArray(u) ? u : [];
86
- if (p.length === 0) return {
87
- ...t,
111
+ let h = Array.isArray(d) ? d : [];
112
+ if (h.length === 0) return {
113
+ ...n,
88
114
  dataset: [],
89
115
  series: []
90
116
  };
91
- let m = p.length > 1, h = typeof t.legend == "object" && !Array.isArray(t.legend) ? t.legend : {}, v = typeof t.grid == "object" && !Array.isArray(t.grid) ? t.grid : {}, x = typeof t.tooltip == "object" && !Array.isArray(t.tooltip) ? t.tooltip : {}, C = typeof t.xAxis == "object" && !Array.isArray(t.xAxis) ? t.xAxis : {}, w = typeof t.yAxis == "object" && !Array.isArray(t.yAxis) ? t.yAxis : {}, T = f?.formatter, { niceMinX: E, niceMaxX: D, niceMinY: O, niceMaxY: k } = S(p), A = (e) => (t) => {
92
- let n = t.color;
93
- if (!d) return n;
94
- let r = `${e}:${t.dataIndex}`;
95
- return d.has(r) ? n : g.color.modifyAlpha(n, .15);
96
- }, j = y(t.dataZoom, m), M = j?.hasXSlider ?? !1, N = j?.hasYSlider ?? !1, P = typeof v.bottom == "number" ? v.bottom : 24, F = m ? 56 : P, I = M ? F + e.sliderHeight + e.sliderGap : F, L = typeof v.right == "number" ? v.right : 8, R = N ? L + e.sliderHeight + e.sliderGap : L;
117
+ let g = h.length > 1, _ = typeof n.legend == "object" && !Array.isArray(n.legend) ? n.legend : {}, b = typeof n.grid == "object" && !Array.isArray(n.grid) ? n.grid : {}, x = typeof n.tooltip == "object" && !Array.isArray(n.tooltip) ? n.tooltip : {}, S = typeof n.xAxis == "object" && !Array.isArray(n.xAxis) ? n.xAxis : {}, C = typeof n.yAxis == "object" && !Array.isArray(n.yAxis) ? n.yAxis : {}, T = m?.formatter, { niceMinX: O, niceMaxX: A, niceMinY: j, niceMaxY: M } = k(h, t(C)), N = Array.isArray(n.series) ? n.series : [], P = (e, t) => {
118
+ let n = f({
119
+ theme: r,
120
+ datums: t,
121
+ template: N[e] ?? N[0],
122
+ fallback: (e) => e.color
123
+ });
124
+ return (t) => {
125
+ let r = n(t);
126
+ if (!p) return r;
127
+ let i = `${e}:${t.dataIndex}`;
128
+ return p.has(i) ? r : v.color.modifyAlpha(r, .15);
129
+ };
130
+ }, F = E(n.dataZoom, g), I = F?.hasXSlider ?? !1, L = F?.hasYSlider ?? !1, R = typeof b.bottom == "number" ? b.bottom : 24, z = g ? 56 : R, B = I ? z + e.sliderHeight + e.sliderGap : z, V = typeof b.right == "number" ? b.right : 8, H = L ? V + e.sliderHeight + e.sliderGap : V;
97
131
  return {
98
- ...t,
99
- dataset: p.map((e) => ({ source: e })),
100
- series: p.map((e, t) => {
101
- let r = i(n, c?.[t]?.color);
132
+ ...n,
133
+ dataset: h.map((e) => ({ source: e.every(Array.isArray) ? e : e.map(y) })),
134
+ series: h.map((e, t) => {
135
+ let n = a(r, l?.[t]?.color);
102
136
  return {
103
137
  type: "scatter",
104
138
  datasetIndex: t,
105
- name: c?.[t]?.name ?? `Series ${t + 1}`,
139
+ name: l?.[t]?.name ?? `Series ${t + 1}`,
106
140
  encode: {
107
141
  x: 0,
108
142
  y: 1
109
143
  },
110
- symbolSize: l,
144
+ symbolSize: u,
111
145
  emphasis: { focus: "series" },
112
- itemStyle: { color: A(t) },
113
- ...r ? { color: r } : {}
146
+ itemStyle: { color: P(t, e) },
147
+ ...n ? { color: n } : {}
114
148
  };
115
149
  }),
116
150
  legend: {
117
- ...h,
118
- show: m
151
+ ..._,
152
+ show: g
119
153
  },
120
154
  grid: {
121
- ...v,
122
- bottom: I,
123
- right: R
155
+ ...b,
156
+ bottom: B,
157
+ right: H
124
158
  },
125
- ...j ? { dataZoom: j.entries } : {},
159
+ ...F ? { dataZoom: F.entries } : {},
126
160
  xAxis: {
127
- ...C,
128
- min: E,
129
- max: D
161
+ ...S,
162
+ min: O,
163
+ max: A
130
164
  },
131
165
  yAxis: {
132
- ...w,
133
- min: O,
134
- max: k,
166
+ ...C,
167
+ min: j,
168
+ max: M,
135
169
  axisLabel: {
136
- ...w.axisLabel ?? {},
170
+ ...C.axisLabel ?? {},
137
171
  ...T ? { formatter: T } : {}
138
172
  }
139
173
  },
140
174
  tooltip: {
141
175
  ...x,
142
- formatter: b(x.formatter, T, a)
176
+ formatter: D(x.formatter, T, o)
143
177
  }
144
178
  };
145
179
  };
146
180
  }
147
- function y(t, n) {
181
+ function E(t, n) {
148
182
  if (!Array.isArray(t) || t.length === 0) return null;
149
183
  let r = !1, i = !1;
150
184
  return {
@@ -160,8 +194,8 @@ function y(t, n) {
160
194
  hasYSlider: i
161
195
  };
162
196
  }
163
- function b(e, t, n) {
164
- return t ? u((e) => {
197
+ function D(e, t, n) {
198
+ return t ? d((e) => {
165
199
  let r = e.value, i = r?.[0], a = r?.[1], o = typeof i == "number" ? n ? n(i) : String(i) : "", s = typeof a == "number" ? t(a) : String(a ?? ""), c = typeof e.marker == "string" ? e.marker : "", l = e.seriesName ? `${e.seriesName}: ` : "";
166
200
  return {
167
201
  name: `(${o}, ${s})`,
@@ -171,8 +205,8 @@ function b(e, t, n) {
171
205
  };
172
206
  }) : e;
173
207
  }
174
- function x(e, t) {
175
- return u((n) => {
208
+ function O(e, t) {
209
+ return d((n) => {
176
210
  let r = n.value, i = r?.[0], a = r?.[1], o = typeof i == "number" ? e ? e(i) : String(i) : "", s = typeof a == "number" ? t ? t(a) : String(a) : "", c = typeof n.marker == "string" ? n.marker : "", l = n.seriesName ? `${n.seriesName}: ` : "";
177
211
  return {
178
212
  name: `(${o}, ${s})`,
@@ -182,23 +216,24 @@ function x(e, t) {
182
216
  };
183
217
  });
184
218
  }
185
- function S(e) {
186
- let t = Infinity, n = -Infinity, r = Infinity, i = -Infinity;
187
- for (let a of e) for (let e of a) {
188
- let a = e?.[0], o = e?.[1];
189
- typeof a == "number" && Number.isFinite(a) && (a < t && (t = a), a > n && (n = a)), typeof o == "number" && Number.isFinite(o) && (o < r && (r = o), o > i && (i = o));
219
+ function k(e, t = {}) {
220
+ let n = Infinity, r = -Infinity, i = Infinity, a = -Infinity;
221
+ for (let t of e) for (let e of t) {
222
+ if (e == null) continue;
223
+ let [t, o] = y(e);
224
+ typeof t == "number" && Number.isFinite(t) && (t < n && (n = t), t > r && (r = t)), typeof o == "number" && Number.isFinite(o) && (o < i && (i = o), o > a && (a = o));
190
225
  }
191
- let a = Number.isFinite(n) ? n <= 0 ? 1 : s(n) : 1, o = Number.isFinite(i) ? i <= 0 ? 1 : s(i) : 1;
226
+ let o = Number.isFinite(r) ? r <= 0 ? 1 : c(r) : 1, s = Number.isFinite(a) ? a <= 0 ? 1 : t.max ?? c(a) : 1;
192
227
  return {
193
- niceMinX: Number.isFinite(t) && t < 0 ? s(t) : 0,
194
- niceMaxX: a,
195
- niceMinY: Number.isFinite(r) && r < 0 ? s(r) : 0,
196
- niceMaxY: o
228
+ niceMinX: Number.isFinite(n) && n < 0 ? c(n) : 0,
229
+ niceMaxX: o,
230
+ niceMinY: Number.isFinite(i) && i < 0 ? t.min ?? c(i) : 0,
231
+ niceMaxY: s
197
232
  };
198
233
  }
199
234
  //#endregion
200
235
  //#region src/widgets-v2/scatterplot/skeleton.tsx
201
- var C = {
236
+ var A = {
202
237
  container: {
203
238
  display: "flex",
204
239
  alignItems: "center",
@@ -223,7 +258,7 @@ var C = {
223
258
  alignItems: "center",
224
259
  gap: ({ spacing: e }) => e(1.5)
225
260
  }
226
- }, w = (e, t, n) => ({
261
+ }, j = (e, t, n) => ({
227
262
  position: "absolute",
228
263
  top: e,
229
264
  left: t,
@@ -231,48 +266,48 @@ var C = {
231
266
  height: n,
232
267
  borderRadius: "50%"
233
268
  });
234
- function T(e) {
235
- let t = d(15), { count: n } = e, r = n === void 0 ? 24 : n, i, a, o, s, c;
269
+ function M(e) {
270
+ let t = p(15), { count: n } = e, r = n === void 0 ? 24 : n, i, a, o, s, c;
236
271
  if (t[0] !== r) {
237
- let e = Array.from({ length: r }, O);
238
- a = f, c = C.container, i = f, o = C.grid, s = e.map(D), t[0] = r, t[1] = i, t[2] = a, t[3] = o, t[4] = s, t[5] = c;
272
+ let e = Array.from({ length: r }, F);
273
+ a = m, c = A.container, i = m, o = A.grid, s = e.map(P), t[0] = r, t[1] = i, t[2] = a, t[3] = o, t[4] = s, t[5] = c;
239
274
  } else i = t[1], a = t[2], o = t[3], s = t[4], c = t[5];
240
275
  let l;
241
- t[6] !== i || t[7] !== o || t[8] !== s ? (l = /* @__PURE__ */ m(i, {
276
+ t[6] !== i || t[7] !== o || t[8] !== s ? (l = /* @__PURE__ */ g(i, {
242
277
  sx: o,
243
278
  children: s
244
279
  }), t[6] = i, t[7] = o, t[8] = s, t[9] = l) : l = t[9];
245
280
  let u;
246
- t[10] === Symbol.for("react.memo_cache_sentinel") ? (u = /* @__PURE__ */ m(f, {
247
- sx: C.legend,
248
- children: [0, 1].map(E)
281
+ t[10] === Symbol.for("react.memo_cache_sentinel") ? (u = /* @__PURE__ */ g(m, {
282
+ sx: A.legend,
283
+ children: [0, 1].map(N)
249
284
  }), t[10] = u) : u = t[10];
250
- let p;
251
- return t[11] !== a || t[12] !== c || t[13] !== l ? (p = /* @__PURE__ */ h(a, {
285
+ let d;
286
+ return t[11] !== a || t[12] !== c || t[13] !== l ? (d = /* @__PURE__ */ _(a, {
252
287
  sx: c,
253
288
  children: [l, u]
254
- }), t[11] = a, t[12] = c, t[13] = l, t[14] = p) : p = t[14], p;
289
+ }), t[11] = a, t[12] = c, t[13] = l, t[14] = d) : d = t[14], d;
255
290
  }
256
- function E(e) {
257
- return /* @__PURE__ */ h(f, {
258
- sx: C.legendItem,
259
- children: [/* @__PURE__ */ m(p, {
291
+ function N(e) {
292
+ return /* @__PURE__ */ _(m, {
293
+ sx: A.legendItem,
294
+ children: [/* @__PURE__ */ g(h, {
260
295
  variant: "circular",
261
296
  width: 8,
262
297
  height: 8
263
- }), /* @__PURE__ */ m(p, {
298
+ }), /* @__PURE__ */ g(h, {
264
299
  width: 48,
265
300
  height: 8
266
301
  })]
267
302
  }, `legend-${e}`);
268
303
  }
269
- function D(e, t) {
270
- return /* @__PURE__ */ m(p, {
304
+ function P(e, t) {
305
+ return /* @__PURE__ */ g(h, {
271
306
  variant: "circular",
272
- sx: w(e.top, e.left, e.size)
307
+ sx: j(e.top, e.left, e.size)
273
308
  }, `dot-${t}`);
274
309
  }
275
- function O(e, t) {
310
+ function F(e, t) {
276
311
  let n = 10 + t * 37 % 80, r = 5 + t * 53 % 90, i = 8 + t * 7 % 6;
277
312
  return {
278
313
  top: `${n}%`,
@@ -282,14 +317,14 @@ function O(e, t) {
282
317
  }
283
318
  //#endregion
284
319
  //#region src/widgets-v2/scatterplot/download.ts
285
- function k(e) {
286
- let r = [];
287
- return e.getCaptureEl && r.push(t({
320
+ function I(e) {
321
+ let t = [];
322
+ return e.getCaptureEl && t.push(n({
288
323
  filename: e.filename,
289
324
  getCaptureEl: e.getCaptureEl,
290
325
  pixelRatio: e.pngPixelRatio,
291
326
  backgroundColor: e.pngBackgroundColor
292
- })), r.push(n({
327
+ })), t.push(r({
293
328
  filename: e.filename,
294
329
  getRows: (t) => {
295
330
  let n = e.getData(t), r = [[
@@ -299,32 +334,38 @@ function k(e) {
299
334
  ]];
300
335
  for (let [t, i] of n.entries()) {
301
336
  let n = e.seriesNames?.[t] ?? `series_${t + 1}`;
302
- for (let [e, t] of i) r.push([
303
- n,
304
- e,
305
- t
306
- ]);
337
+ for (let e of i) {
338
+ let [t, i] = y(e);
339
+ r.push([
340
+ n,
341
+ t,
342
+ i
343
+ ]);
344
+ }
307
345
  }
308
346
  return r;
309
347
  }
310
- })), r;
348
+ })), t;
311
349
  }
312
350
  //#endregion
313
351
  //#region src/widgets-v2/scatterplot/transforms.ts
314
- var A = (e) => Array.isArray(e) ? e.map((e) => {
315
- if (!j(e)) return e;
316
- let t = e.reduce((e, [, t]) => e + Math.abs(t), 0);
317
- return t <= 0 ? e : e.map(([e, n]) => [e, n / t * 100]);
352
+ var L = (e) => Array.isArray(e) ? e.map((e) => {
353
+ if (!R(e)) return e;
354
+ let t = e.reduce((e, t) => e + Math.abs(y(t)[1]), 0);
355
+ return t <= 0 ? e : e.map((e) => {
356
+ let [n, r] = y(e);
357
+ return x(e, n, r / t * 100);
358
+ });
318
359
  }) : e;
319
- function j(e) {
320
- return Array.isArray(e) ? e.every((e) => Array.isArray(e) && e.length === 2 && typeof e[0] == "number" && Number.isFinite(e[0]) && typeof e[1] == "number" && Number.isFinite(e[1])) : !1;
360
+ function R(e) {
361
+ return Array.isArray(e) && e.every(b);
321
362
  }
322
- function M(e, t) {
363
+ function z(e, t) {
323
364
  if (t.length === 0 || !Array.isArray(e)) return e;
324
365
  let n = new Set(t.map(String));
325
- return e.map((e, t) => j(e) ? e.filter((e, r) => n.has(`${t}:${r}`)) : e);
366
+ return e.map((e, t) => R(e) ? e.filter((e, r) => n.has(`${t}:${r}`)) : e);
326
367
  }
327
368
  //#endregion
328
- export { T as ScatterplotSkeleton, k as createScatterplotDownloadConfig, v as createScatterplotOptionFactory, M as filterScatterplotByLockedPoints, _ as scatterplotOptions, A as toRelativeScatterplotData };
369
+ export { M as ScatterplotSkeleton, I as createScatterplotDownloadConfig, T as createScatterplotOptionFactory, z as filterScatterplotByLockedPoints, y as getScatterplotXY, w as scatterplotOptions, L as toRelativeScatterplotData };
329
370
 
330
371
  //# sourceMappingURL=scatterplot.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scatterplot.js","names":["EChartsOption","echarts","CallbackDataParams","buildAxisLabelStyle","buildGridConfig","buildLegendConfig","createTooltipFormatter","createTooltipPositioner","niceNum","ZOOM_LAYOUT","OptionFactory","mergeOptions","resolveThemeColor","ScatterplotEChartsOption","ScatterplotOptionFactoryInput","ScatterplotOptionsInput","ScatterplotWidgetData","scatterplotOptions","theme","xFormatter","yFormatter","grid","left","parseInt","spacing","top","right","containLabel","tooltip","trigger","backgroundColor","palette","grey","borderWidth","padding","textStyle","color","common","white","fontSize","fontFamily","typography","caption","position","formatter","buildScatterTooltipFormatter","legend","hasLegend","labelFormatter","undefined","axisPointer","lineStyle","secondary","main","Object","values","qualitative","bold","Record","xAxis","type","axisLine","show","axisTick","axisLabel","margin","hideOverlap","showMinLabel","showMaxLabel","splitLine","black","divider","yAxis","createScatterplotOptionFactory","options","optionsOverride","series","symbolSize","selection","selectionSet","length","Set","option","data","ctx","structural","Partial","seriesArr","Array","isArray","dataset","baseLegend","baseGrid","baseTooltip","baseXAxis","baseYAxis","reactiveFormatter","niceMinX","niceMaxX","niceMinY","niceMaxY","computeScatterBounds","makeDimColor","seriesIdx","params","base","key","dataIndex","has","modifyAlpha","dataZoomLayout","layoutDataZoomForScatter","dataZoom","hasXSlider","hasYSlider","fallbackBottom","bottom","baseBottom","gridBottom","sliderHeight","sliderGap","fallbackRight","gridRight","map","s","source","_","i","overrideColor","const","datasetIndex","name","encode","x","y","emphasis","focus","itemStyle","entries","min","max","buildReactiveScatterTooltipFormatter","entry","dz","xAxisIndex","yAxisIndex","targetsY","sliderBottomWithLegend","structuralFormatter","reactiveYFormatter","value","item","formattedX","String","formattedY","marker","seriesName","minX","Infinity","maxX","minY","maxY","point","Number","isFinite","Box","Skeleton","SxProps","Theme","styles","container","display","alignItems","justifyContent","flexDirection","gap","spacing","height","grid","position","flex","width","legend","legendItem","Record","dotSx","top","left","size","borderRadius","ScatterplotSkeletonProps","count","ScatterplotSkeleton","t0","$","_c","t1","undefined","T0","T1","t2","t3","t4","dots","Array","from","length","_temp","map","_temp2","t5","t6","Symbol","for","_temp3","t7","i_1","i","d","i_0","_","buildCsvDownloadItem","buildPngDownloadItem","DownloadContext","DownloadItem","ScatterplotWidgetData","createScatterplotDownloadConfig","args","filename","getData","ctx","seriesNames","getCaptureEl","HTMLElement","pngPixelRatio","pngBackgroundColor","items","push","pixelRatio","backgroundColor","getRows","data","rows","i","series","entries","seriesName","x","y","toRelativeScatterplotData","input","Array","isArray","map","series","isXyTupleArray","total","reduce","acc","y","Math","abs","x","v","every","item","length","Number","isFinite","filterScatterplotByLockedPoints","lockedItems","locked","Set","String","seriesIndex","filter","_","dataIndex","has"],"sources":["../../src/widgets-v2/scatterplot/options.ts","../../src/widgets-v2/scatterplot/skeleton.tsx","../../src/widgets-v2/scatterplot/download.ts","../../src/widgets-v2/scatterplot/transforms.ts"],"sourcesContent":["import type { EChartsOption } from 'echarts'\nimport * as echarts from 'echarts'\nimport type { CallbackDataParams } from 'echarts/types/dist/shared'\nimport {\n buildAxisLabelStyle,\n buildGridConfig,\n buildLegendConfig,\n createTooltipFormatter,\n createTooltipPositioner,\n niceNum,\n} from '../../widgets/utils/chart-config'\nimport { ZOOM_LAYOUT } from '../actions/zoom-toggle'\nimport type { OptionFactory } from '../echart'\nimport { mergeOptions, resolveThemeColor } from '../utils'\nimport type {\n ScatterplotEChartsOption,\n ScatterplotOptionFactoryInput,\n ScatterplotOptionsInput,\n ScatterplotWidgetData,\n} from './types'\n\n/**\n * Builds the **structural** ECharts option for a scatterplot widget — both\n * axes `type: 'value'` (not category, unlike Bar/Histogram), grid, tooltip\n * triggered per-item rather than per-axis. Intentionally data-agnostic: no\n * series, no dataset, no `legend.show` (those depend on data and are added\n * by {@link createScatterplotOptionFactory}).\n *\n * Styling parity with v1: dark themed tooltip via `createTooltipFormatter`\n * + `createTooltipPositioner`, `buildGridConfig`-based grid, polished\n * axisLine/Tick/splitLine, `overlineDelicate` axis labels, structural\n * legend wired via `buildLegendConfig` (toggled by the merger), and the\n * CARTO `qualitative.bold + secondary` palette — same pattern bar /\n * histogram / pie already use. {@link createScatterplotOptionFactory}\n * wraps this builder in its structural-phase branch.\n */\nexport function scatterplotOptions({\n theme,\n xFormatter,\n yFormatter,\n}: ScatterplotOptionsInput): ScatterplotEChartsOption {\n return {\n grid: {\n left: parseInt(theme.spacing(1)),\n top: parseInt(theme.spacing(3)),\n right: parseInt(theme.spacing(1)),\n // Default: no legend. Merger bumps `bottom` when there are >1 series.\n ...buildGridConfig(false, theme),\n containLabel: true,\n },\n tooltip: {\n // Per-point trigger — different from Bar's 'axis' trigger because\n // points don't share an x-coordinate.\n trigger: 'item',\n backgroundColor: theme.palette.grey[900],\n borderWidth: 0,\n padding: [parseInt(theme.spacing(1)), parseInt(theme.spacing(1))],\n textStyle: {\n color: theme.palette.common.white,\n fontSize: 11,\n fontFamily: theme.typography.caption.fontFamily,\n },\n position: createTooltipPositioner(theme),\n formatter: buildScatterTooltipFormatter(xFormatter, yFormatter),\n },\n // Legend styling baked here; `show` is toggled by the merger based on\n // series count.\n legend: {\n ...buildLegendConfig({ hasLegend: false, labelFormatter: undefined }),\n },\n axisPointer: { lineStyle: { color: theme.palette.grey[400] } },\n color: [\n theme.palette.secondary.main,\n ...Object.values(\n (theme.palette as { qualitative?: { bold?: Record<string, string> } })\n .qualitative?.bold ?? {},\n ),\n ],\n xAxis: {\n type: 'value',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n margin: parseInt(theme.spacing(1)),\n hideOverlap: true,\n showMinLabel: true,\n showMaxLabel: true,\n ...(xFormatter && { formatter: xFormatter }),\n },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n },\n yAxis: {\n type: 'value',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n margin: parseInt(theme.spacing(1)),\n hideOverlap: true,\n showMinLabel: true,\n showMaxLabel: true,\n ...(yFormatter && { formatter: yFormatter }),\n },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n },\n } as ScatterplotEChartsOption\n}\n\n/**\n * Returns the scatterplot widget's {@link OptionFactory} — one closure\n * that owns BOTH phases of option construction:\n *\n * - **Structural phase** (`option == null`) — builds the theme-aware\n * structural option via {@link scatterplotOptions}, optionally merging\n * the consumer-supplied `optionsOverride`. Called once by Provider to\n * seed `rawOptions` in the store.\n * - **Merge phase** (`option != null`) — fuses post-pipeline `state.data`\n * (`ScatterplotWidgetData`) into the option via the dataset API. Each\n * series's `[x, y]` tuples land in `dataset[i].source` as 2-column\n * rows; the series uses positional encoding (`encode: { x: 0, y: 1 }`)\n * and `type: 'scatter'`. niceMin/niceMax are computed over both axes\n * so the chart frames data on rounded extents and numeric jitters\n * don't shift gridlines per render. Reactive `ctx.formatter` (driven\n * by RelativeData) re-derives the y-axis label and tooltip at fusion\n * time; `xFormatter` stays baked at structural-build time (relative\n * is a values-axis concept; x is coordinate-space).\n *\n * When `ZoomToggle` installs a `dataZoom` slider, grid bottom is\n * extended and the slider is positioned above the legend row (if any) —\n * same layout dance bar / histogram / timeseries do.\n */\nexport function createScatterplotOptionFactory(\n options: ScatterplotOptionFactoryInput,\n): OptionFactory {\n const { theme, xFormatter, yFormatter, optionsOverride } = options\n const series = options.series\n const symbolSize = options.symbolSize ?? 8\n const selection = options.selection\n const selectionSet =\n selection && selection.length > 0 ? new Set<string>(selection) : null\n return (option, data, ctx) => {\n if (option == null) {\n const structural = scatterplotOptions({ theme, xFormatter, yFormatter })\n return optionsOverride\n ? (mergeOptions(\n structural as unknown as Record<string, unknown>,\n optionsOverride as Partial<Record<string, unknown>>,\n ) as EChartsOption)\n : structural\n }\n\n const seriesArr = Array.isArray(data) ? (data as ScatterplotWidgetData) : []\n if (seriesArr.length === 0) {\n return { ...option, dataset: [], series: [] }\n }\n const hasLegend = seriesArr.length > 1\n const baseLegend =\n typeof option.legend === 'object' && !Array.isArray(option.legend)\n ? option.legend\n : {}\n const baseGrid =\n typeof option.grid === 'object' && !Array.isArray(option.grid)\n ? option.grid\n : {}\n const baseTooltip =\n typeof option.tooltip === 'object' && !Array.isArray(option.tooltip)\n ? option.tooltip\n : {}\n const baseXAxis =\n typeof option.xAxis === 'object' && !Array.isArray(option.xAxis)\n ? option.xAxis\n : {}\n const baseYAxis =\n typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)\n ? option.yAxis\n : {}\n\n const reactiveFormatter = ctx?.formatter\n\n const { niceMinX, niceMaxX, niceMinY, niceMaxY } =\n computeScatterBounds(seriesArr)\n\n // Dim non-selected points via `series.itemStyle.color`. The selection\n // key is `${seriesIndex}:${dataIndex}`; we read those off the params\n // ECharts hands to the callback per-data.\n //\n // We *always* emit `itemStyle.color` (a passthrough when nothing is\n // selected), not conditionally — dropping the key between renders\n // would let ECharts' default merge keep the previous callback alive\n // and items would stay dimmed forever after an external clear.\n // Keeping the key always-present means a plain setOption merge swaps\n // the callback in place, no `replaceMerge` and no entry-animation\n // flash on selection on/off.\n const makeDimColor =\n (seriesIdx: number) => (params: CallbackDataParams) => {\n const base = params.color as string\n if (!selectionSet) return base\n const key = `${seriesIdx}:${params.dataIndex}`\n return selectionSet.has(key)\n ? base\n : echarts.color.modifyAlpha(base, 0.15)\n }\n\n // Zoom slider layout: when ZoomToggle has installed `dataZoom`,\n // reserve grid space and lift any x-slider above the legend (if\n // present). Scatter supports 2D zoom via `axes: ['x', 'y']` — in\n // that case there's also a vertical y-slider on the right edge, so\n // we reserve `grid.right` separately. Inside-only dataZoom entries\n // (no `type: 'slider'`) take no grid space.\n const dataZoomLayout = layoutDataZoomForScatter(option.dataZoom, hasLegend)\n const hasXSlider = dataZoomLayout?.hasXSlider ?? false\n const hasYSlider = dataZoomLayout?.hasYSlider ?? false\n const fallbackBottom =\n typeof baseGrid.bottom === 'number' ? baseGrid.bottom : 24\n const baseBottom = hasLegend ? 56 : fallbackBottom\n const gridBottom = hasXSlider\n ? baseBottom + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : baseBottom\n const fallbackRight =\n typeof baseGrid.right === 'number' ? baseGrid.right : 8\n const gridRight = hasYSlider\n ? fallbackRight + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : fallbackRight\n\n return {\n ...option,\n // ECharts dataset.source wants a mutable [number, number][] shape; we\n // hold readonly tuples internally, so cast at the boundary.\n dataset: seriesArr.map((s) => ({ source: s as unknown as number[][] })),\n series: seriesArr.map((_, i) => {\n const overrideColor = resolveThemeColor(theme, series?.[i]?.color)\n return {\n type: 'scatter' as const,\n datasetIndex: i,\n name: series?.[i]?.name ?? `Series ${i + 1}`,\n encode: { x: 0, y: 1 },\n symbolSize,\n emphasis: { focus: 'series' },\n itemStyle: { color: makeDimColor(i) },\n ...(overrideColor ? { color: overrideColor } : {}),\n }\n }),\n legend: { ...baseLegend, show: hasLegend },\n grid: { ...baseGrid, bottom: gridBottom, right: gridRight },\n ...(dataZoomLayout ? { dataZoom: dataZoomLayout.entries } : {}),\n xAxis: {\n ...baseXAxis,\n min: niceMinX,\n max: niceMaxX,\n } as EChartsOption['xAxis'],\n yAxis: {\n ...baseYAxis,\n min: niceMinY,\n max: niceMaxY,\n axisLabel: {\n ...((baseYAxis as { axisLabel?: object }).axisLabel ?? {}),\n // Re-derive the y-axis formatter at fusion time so RelativeData's\n // percent formatter (written to `state.formatter`) flows through\n // without rebuilding the structural option. Falls back to the\n // structural `yFormatter` already baked in `baseYAxis.axisLabel`\n // (which `String(value)` if neither is set).\n ...(reactiveFormatter ? { formatter: reactiveFormatter } : {}),\n },\n } as EChartsOption['yAxis'],\n tooltip: {\n ...baseTooltip,\n // Rebuild the tooltip formatter so the live y-axis formatter is\n // applied to the y-coordinate in the (x, y) label. xFormatter is\n // structural — relative is a values-axis concept, so xFormatter\n // doesn't change under RelativeData.\n formatter: buildReactiveScatterTooltipFormatter(\n (baseTooltip as { formatter?: unknown }).formatter,\n reactiveFormatter,\n xFormatter,\n ),\n },\n } as EChartsOption\n }\n}\n\n/**\n * Lay out the `dataZoom` array for the scatter chart:\n * - Detect whether any horizontal (x-axis) slider is present — if so\n * lift it above the legend row when a legend is shown.\n * - Detect whether any vertical (y-axis) slider is present — the\n * caller reserves `grid.right` so the slider doesn't overlap the\n * plot area.\n *\n * Returns `null` when there's no `dataZoom` so callers can skip the\n * layout adjustment entirely. An entry is considered an \"x-slider\" if\n * it has `xAxisIndex` set (or no axis index — defaults to x in ECharts).\n * A \"y-slider\" has `yAxisIndex` set.\n */\nfunction layoutDataZoomForScatter(\n dataZoom: unknown,\n hasLegend: boolean,\n): { entries: unknown[]; hasXSlider: boolean; hasYSlider: boolean } | null {\n if (!Array.isArray(dataZoom) || dataZoom.length === 0) return null\n let hasXSlider = false\n let hasYSlider = false\n const entries = dataZoom.map((entry: unknown) => {\n if (entry == null || typeof entry !== 'object') return entry\n const dz = entry as {\n type?: string\n xAxisIndex?: unknown\n yAxisIndex?: unknown\n bottom?: number\n }\n if (dz.type !== 'slider') return dz\n const targetsY = dz.yAxisIndex !== undefined\n if (targetsY) {\n hasYSlider = true\n return dz\n }\n // Either explicit x or defaulted (ECharts defaults sliders to xAxis\n // when no axis index is provided).\n hasXSlider = true\n if (hasLegend) {\n return { ...dz, bottom: ZOOM_LAYOUT.sliderBottomWithLegend }\n }\n return dz\n })\n return { entries, hasXSlider, hasYSlider }\n}\n\n/**\n * If a reactive (store-driven) y formatter is provided, re-build the\n * scatter tooltip formatter using it. Otherwise, return the structural\n * formatter unchanged so the original `xFormatter` / `yFormatter`\n * baked into `scatterplotOptions` still applies. The structural\n * formatter has stable identity per `scatterplotOptions` call, so this\n * path doesn't churn ECharts on every render.\n */\nfunction buildReactiveScatterTooltipFormatter(\n structuralFormatter: unknown,\n reactiveYFormatter: ((value: number) => string) | undefined,\n xFormatter: ((value: number) => string) | undefined,\n) {\n if (!reactiveYFormatter) return structuralFormatter\n return createTooltipFormatter((item) => {\n const value = item.value as readonly [number, number] | undefined\n const x = value?.[0]\n const y = value?.[1]\n const formattedX =\n typeof x === 'number' ? (xFormatter ? xFormatter(x) : String(x)) : ''\n const formattedY =\n typeof y === 'number' ? reactiveYFormatter(y) : String(y ?? '')\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n return {\n name: `(${formattedX}, ${formattedY})`,\n seriesName,\n marker,\n value: '',\n }\n })\n}\n\nfunction buildScatterTooltipFormatter(\n xFormatter: ((value: number) => string) | undefined,\n yFormatter: ((value: number) => string) | undefined,\n) {\n return createTooltipFormatter((item) => {\n const value = item.value as readonly [number, number] | undefined\n const x = value?.[0]\n const y = value?.[1]\n const formattedX =\n typeof x === 'number' ? (xFormatter ? xFormatter(x) : String(x)) : ''\n const formattedY =\n typeof y === 'number' ? (yFormatter ? yFormatter(y) : String(y)) : ''\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n return {\n name: `(${formattedX}, ${formattedY})`,\n seriesName,\n marker,\n value: '',\n }\n })\n}\n\nfunction computeScatterBounds(seriesArr: ScatterplotWidgetData): {\n niceMinX: number\n niceMaxX: number\n niceMinY: number\n niceMaxY: number\n} {\n let minX = Infinity\n let maxX = -Infinity\n let minY = Infinity\n let maxY = -Infinity\n for (const series of seriesArr) {\n for (const point of series) {\n const x = point?.[0]\n const y = point?.[1]\n if (typeof x === 'number' && Number.isFinite(x)) {\n if (x < minX) minX = x\n if (x > maxX) maxX = x\n }\n if (typeof y === 'number' && Number.isFinite(y)) {\n if (y < minY) minY = y\n if (y > maxY) maxY = y\n }\n }\n }\n // Mirror bar's `computeNiceBounds`: clamp min to 0 when data is\n // non-negative (gridline reads cleanly from zero), apply `niceNum` to\n // negative mins, and floor max=0 to 1 so the chart always has range.\n // Scatter can have free coordinates so we apply this per-axis.\n const niceMaxX = Number.isFinite(maxX) ? (maxX <= 0 ? 1 : niceNum(maxX)) : 1\n const niceMaxY = Number.isFinite(maxY) ? (maxY <= 0 ? 1 : niceNum(maxY)) : 1\n const niceMinX = Number.isFinite(minX) ? (minX < 0 ? niceNum(minX) : 0) : 0\n const niceMinY = Number.isFinite(minY) ? (minY < 0 ? niceNum(minY) : 0) : 0\n return { niceMinX, niceMaxX, niceMinY, niceMaxY }\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n container: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n flexDirection: 'column',\n gap: ({ spacing }) => spacing(1),\n height: ({ spacing }) => spacing(38),\n },\n grid: {\n position: 'relative',\n flex: '1 1 auto',\n width: '100%',\n },\n legend: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(2),\n height: ({ spacing }) => spacing(5),\n },\n legendItem: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(1.5),\n },\n} satisfies Record<string, SxProps<Theme>>\n\n// `sx` callback that needs runtime args — extracted at module scope so the\n// `styles` object can satisfy `Record<string, SxProps<Theme>>` cleanly\n// (function `sx`-with-args isn't assignable to plain `SxProps<Theme>`).\nconst dotSx = (top: string, left: string, size: number): SxProps<Theme> => ({\n position: 'absolute',\n top,\n left,\n width: size,\n height: size,\n borderRadius: '50%',\n})\n\nexport interface ScatterplotSkeletonProps {\n /** Number of dots to render. */\n count?: number\n}\n\n/**\n * Loading state for the Scatterplot widget. Mirrors a scatter chart's\n * silhouette — a deterministic spread of small circular dots in the plot\n * area plus a legend stub — so the skeleton reads as \"a scatter chart\"\n * rather than a generic list. Matches bar/histogram/pie skeleton structure\n * (grid stub + legend stub in a flex column).\n */\nexport function ScatterplotSkeleton({ count = 24 }: ScatterplotSkeletonProps) {\n // Deterministic pseudo-scatter positions so the skeleton doesn't flicker.\n const dots = Array.from({ length: count }, (_, i) => {\n const top = 10 + ((i * 37) % 80)\n const left = 5 + ((i * 53) % 90)\n const size = 8 + ((i * 7) % 6)\n return { top: `${top}%`, left: `${left}%`, size }\n })\n return (\n <Box sx={styles.container}>\n <Box sx={styles.grid}>\n {dots.map((d, i) => (\n <Skeleton\n key={`dot-${i}`}\n variant='circular'\n sx={dotSx(d.top, d.left, d.size)}\n />\n ))}\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n buildPngDownloadItem,\n type DownloadContext,\n type DownloadItem,\n} from '../actions/download'\nimport type { ScatterplotWidgetData } from './types'\n\n/**\n * Download menu items for the Scatterplot widget. Always includes a CSV\n * item with `series, x, y` columns (one row per point). When\n * `getCaptureEl` is supplied, prepends a PNG item that rasterises the\n * captured element via `html2canvas`.\n */\nexport function createScatterplotDownloadConfig(args: {\n filename: string\n getData: (ctx: DownloadContext) => ScatterplotWidgetData\n seriesNames?: readonly string[]\n getCaptureEl?: (ctx: DownloadContext) => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push(\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: (ctx) => {\n const data = args.getData(ctx)\n const rows: unknown[][] = [['series', 'x', 'y']]\n for (const [i, series] of data.entries()) {\n const seriesName = args.seriesNames?.[i] ?? `series_${i + 1}`\n for (const [x, y] of series) {\n rows.push([seriesName, x, y])\n }\n }\n return rows\n },\n }),\n )\n return items\n}\n","/**\n * Scatterplot-specific `RelativeData` transform. Scatter data is\n * `[number, number][]` — each series is a list of `[x, y]` tuples.\n * Relative is a values-axis concept, so this rewrites `y` to its\n * share of the series's total `y` (0–100) and leaves `x` raw — x is\n * coordinate space, not part of the cohort total.\n *\n * Pass to `<Widget.RelativeData transform={toRelativeScatterplotData} />`.\n *\n * The denominator is the sum of |y| across the series so mixed-sign\n * y values produce sane signed shares-of-magnitude. A series whose\n * total y-magnitude is zero (all-zero or empty input) is returned\n * unchanged so a stalled or empty data set doesn't show misleading 0%\n * values. Inputs whose shape isn't `[number, number][]` fall through\n * untouched.\n */\nexport const toRelativeScatterplotData = (input: unknown): unknown => {\n if (!Array.isArray(input)) return input\n return input.map((series: unknown): unknown => {\n if (!isXyTupleArray(series)) return series\n const total = series.reduce((acc, [, y]) => acc + Math.abs(y), 0)\n if (total <= 0) return series\n return series.map(([x, y]) => [x, (y / total) * 100] as [number, number])\n })\n}\n\nfunction isXyTupleArray(v: unknown): v is [number, number][] {\n if (!Array.isArray(v)) return false\n return v.every(\n (item) =>\n Array.isArray(item) &&\n item.length === 2 &&\n typeof item[0] === 'number' &&\n Number.isFinite(item[0]) &&\n typeof item[1] === 'number' &&\n Number.isFinite(item[1]),\n )\n}\n\n/**\n * `LockSelection` filter for Scatterplot. Data is `[number, number][][]` —\n * points have no `name`, so selection (and locking) is keyed on a synthetic\n * `${seriesIndex}:${dataIndex}` string (same format `useChartSelection`'s\n * `keyFromClick`/`keysFromBrush` produce for this widget). Unlike Histogram,\n * a point's position carries no external meaning (no `ticks` to desync from),\n * so non-locked points are removed outright rather than zeroed.\n */\nexport function filterScatterplotByLockedPoints(\n input: unknown,\n lockedItems: readonly (string | number)[],\n): unknown {\n if (lockedItems.length === 0) return input\n if (!Array.isArray(input)) return input\n const locked = new Set<string>(lockedItems.map(String))\n return input.map((series: unknown, seriesIndex: number): unknown => {\n if (!isXyTupleArray(series)) return series\n return series.filter((_, dataIndex) =>\n locked.has(`${seriesIndex}:${dataIndex}`),\n )\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scatterplot.js","names":["ScatterplotItem","getScatterplotXY","point","isTuple","x","y","isScatterplotDatum","v","Array","isArray","length","isFiniteNumber","withScatterplotXY","Number","isFinite","EChartsOption","echarts","CallbackDataParams","buildAxisLabelStyle","buildGridConfig","buildLegendConfig","createTooltipFormatter","createTooltipPositioner","niceNum","ZOOM_LAYOUT","OptionFactory","mergeOptions","resolveThemeColor","createItemColorResolver","getScatterplotXY","ScatterplotEChartsOption","ScatterplotOptionFactoryInput","ScatterplotOptionsInput","ScatterplotItem","ScatterplotWidgetData","fixedAxisBounds","scatterplotOptions","theme","xFormatter","yFormatter","grid","left","parseInt","spacing","top","right","containLabel","tooltip","trigger","backgroundColor","palette","grey","borderWidth","padding","textStyle","color","common","white","fontSize","fontFamily","typography","caption","position","formatter","buildScatterTooltipFormatter","legend","hasLegend","labelFormatter","undefined","axisPointer","lineStyle","secondary","main","Object","values","qualitative","bold","Record","xAxis","type","axisLine","show","axisTick","axisLabel","margin","hideOverlap","showMinLabel","showMaxLabel","splitLine","black","divider","yAxis","createScatterplotOptionFactory","options","optionsOverride","series","symbolSize","selection","selectionSet","length","Set","option","data","ctx","structural","Partial","seriesArr","Array","isArray","dataset","baseLegend","baseGrid","baseTooltip","baseXAxis","baseYAxis","reactiveFormatter","niceMinX","niceMaxX","niceMinY","niceMaxY","computeScatterBounds","seriesTemplates","makeDimColor","seriesIdx","datums","baseColor","template","fallback","params","base","key","dataIndex","has","modifyAlpha","dataZoomLayout","layoutDataZoomForScatter","dataZoom","hasXSlider","hasYSlider","fallbackBottom","bottom","baseBottom","gridBottom","sliderHeight","sliderGap","fallbackRight","gridRight","map","s","source","every","i","overrideColor","const","datasetIndex","name","encode","x","y","emphasis","focus","itemStyle","entries","min","max","buildReactiveScatterTooltipFormatter","entry","dz","xAxisIndex","yAxisIndex","targetsY","sliderBottomWithLegend","structuralFormatter","reactiveYFormatter","value","item","formattedX","String","formattedY","marker","seriesName","fixedY","minX","Infinity","maxX","minY","maxY","point","Number","isFinite","Box","Skeleton","SxProps","Theme","styles","container","display","alignItems","justifyContent","flexDirection","gap","spacing","height","grid","position","flex","width","legend","legendItem","Record","dotSx","top","left","size","borderRadius","ScatterplotSkeletonProps","count","ScatterplotSkeleton","t0","$","_c","t1","undefined","T0","T1","t2","t3","t4","dots","Array","from","length","_temp","map","_temp2","t5","t6","Symbol","for","_temp3","t7","i_1","i","d","i_0","_","buildCsvDownloadItem","buildPngDownloadItem","DownloadContext","DownloadItem","getScatterplotXY","ScatterplotItem","ScatterplotWidgetData","createScatterplotDownloadConfig","args","filename","getData","ctx","seriesNames","getCaptureEl","HTMLElement","pngPixelRatio","pngBackgroundColor","items","push","pixelRatio","backgroundColor","getRows","data","rows","i","series","entries","seriesName","point","x","y","getScatterplotXY","isScatterplotDatum","withScatterplotXY","ScatterplotItem","toRelativeScatterplotData","input","Array","isArray","map","series","isPointArray","total","reduce","acc","p","Math","abs","x","y","v","every","filterScatterplotByLockedPoints","lockedItems","length","locked","Set","String","seriesIndex","filter","_","dataIndex","has"],"sources":["../../src/widgets-v2/scatterplot/points.ts","../../src/widgets-v2/scatterplot/options.ts","../../src/widgets-v2/scatterplot/skeleton.tsx","../../src/widgets-v2/scatterplot/download.ts","../../src/widgets-v2/scatterplot/transforms.ts"],"sourcesContent":["import type { ScatterplotItem } from './types'\n\n/** `[x, y]` of a {@link ScatterplotItem}, whichever form it takes. */\nexport function getScatterplotXY(\n point: ScatterplotItem,\n): readonly [number, number] {\n return isTuple(point) ? point : [point.x, point.y]\n}\n\n/** Whether `v` is a valid {@link ScatterplotItem} with finite coordinates. */\nexport function isScatterplotDatum(v: unknown): v is ScatterplotItem {\n if (Array.isArray(v)) {\n return v.length === 2 && isFiniteNumber(v[0]) && isFiniteNumber(v[1])\n }\n if (v == null || typeof v !== 'object') return false\n const { x, y } = v as { x?: unknown; y?: unknown }\n return isFiniteNumber(x) && isFiniteNumber(y)\n}\n\n/** Same point with new coordinates; keeps the object form (and `color`). */\nexport function withScatterplotXY(\n point: ScatterplotItem,\n x: number,\n y: number,\n): ScatterplotItem {\n return isTuple(point) ? [x, y] : { ...point, x, y }\n}\n\nfunction isTuple(point: ScatterplotItem): point is readonly [number, number] {\n return Array.isArray(point)\n}\n\nfunction isFiniteNumber(v: unknown): v is number {\n return typeof v === 'number' && Number.isFinite(v)\n}\n","import type { EChartsOption } from 'echarts'\nimport * as echarts from 'echarts'\nimport type { CallbackDataParams } from 'echarts/types/dist/shared'\nimport {\n buildAxisLabelStyle,\n buildGridConfig,\n buildLegendConfig,\n createTooltipFormatter,\n createTooltipPositioner,\n niceNum,\n} from '../../widgets/utils/chart-config'\nimport { ZOOM_LAYOUT } from '../actions/zoom-toggle'\nimport type { OptionFactory } from '../echart'\nimport { mergeOptions, resolveThemeColor } from '../utils'\nimport { createItemColorResolver } from '../utils/item-color'\nimport { getScatterplotXY } from './points'\nimport type {\n ScatterplotEChartsOption,\n ScatterplotOptionFactoryInput,\n ScatterplotOptionsInput,\n ScatterplotItem,\n ScatterplotWidgetData,\n} from './types'\nimport { fixedAxisBounds } from '../actions/relative-data/scale'\n\n/**\n * Builds the **structural** ECharts option for a scatterplot widget — both\n * axes `type: 'value'` (not category, unlike Bar/Histogram), grid, tooltip\n * triggered per-item rather than per-axis. Intentionally data-agnostic: no\n * series, no dataset, no `legend.show` (those depend on data and are added\n * by {@link createScatterplotOptionFactory}).\n *\n * Styling parity with v1: dark themed tooltip via `createTooltipFormatter`\n * + `createTooltipPositioner`, `buildGridConfig`-based grid, polished\n * axisLine/Tick/splitLine, `overlineDelicate` axis labels, structural\n * legend wired via `buildLegendConfig` (toggled by the merger), and the\n * CARTO `qualitative.bold + secondary` palette — same pattern bar /\n * histogram / pie already use. {@link createScatterplotOptionFactory}\n * wraps this builder in its structural-phase branch.\n */\nexport function scatterplotOptions({\n theme,\n xFormatter,\n yFormatter,\n}: ScatterplotOptionsInput): ScatterplotEChartsOption {\n return {\n grid: {\n left: parseInt(theme.spacing(1)),\n top: parseInt(theme.spacing(3)),\n right: parseInt(theme.spacing(1)),\n // Default: no legend. Merger bumps `bottom` when there are >1 series.\n ...buildGridConfig(false, theme),\n containLabel: true,\n },\n tooltip: {\n // Per-point trigger — different from Bar's 'axis' trigger because\n // points don't share an x-coordinate.\n trigger: 'item',\n backgroundColor: theme.palette.grey[900],\n borderWidth: 0,\n padding: [parseInt(theme.spacing(1)), parseInt(theme.spacing(1))],\n textStyle: {\n color: theme.palette.common.white,\n fontSize: 11,\n fontFamily: theme.typography.caption.fontFamily,\n },\n position: createTooltipPositioner(theme),\n formatter: buildScatterTooltipFormatter(xFormatter, yFormatter),\n },\n // Legend styling baked here; `show` is toggled by the merger based on\n // series count.\n legend: {\n ...buildLegendConfig({ hasLegend: false, labelFormatter: undefined }),\n },\n axisPointer: { lineStyle: { color: theme.palette.grey[400] } },\n color: [\n theme.palette.secondary.main,\n ...Object.values(\n (theme.palette as { qualitative?: { bold?: Record<string, string> } })\n .qualitative?.bold ?? {},\n ),\n ],\n xAxis: {\n type: 'value',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n margin: parseInt(theme.spacing(1)),\n hideOverlap: true,\n showMinLabel: true,\n showMaxLabel: true,\n ...(xFormatter && { formatter: xFormatter }),\n },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n },\n yAxis: {\n type: 'value',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n ...buildAxisLabelStyle(theme),\n margin: parseInt(theme.spacing(1)),\n hideOverlap: true,\n showMinLabel: true,\n showMaxLabel: true,\n ...(yFormatter && { formatter: yFormatter }),\n },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n },\n } as ScatterplotEChartsOption\n}\n\n/**\n * Returns the scatterplot widget's {@link OptionFactory} — one closure\n * that owns BOTH phases of option construction:\n *\n * - **Structural phase** (`option == null`) — builds the theme-aware\n * structural option via {@link scatterplotOptions}, optionally merging\n * the consumer-supplied `optionsOverride`. Called once by Provider to\n * seed `rawOptions` in the store.\n * - **Merge phase** (`option != null`) — fuses post-pipeline `state.data`\n * (`ScatterplotWidgetData`) into the option via the dataset API. Each\n * series's `[x, y]` tuples land in `dataset[i].source` as 2-column\n * rows; the series uses positional encoding (`encode: { x: 0, y: 1 }`)\n * and `type: 'scatter'`. niceMin/niceMax are computed over both axes\n * so the chart frames data on rounded extents and numeric jitters\n * don't shift gridlines per render. Reactive `ctx.formatter` (driven\n * by RelativeData) re-derives the y-axis label and tooltip at fusion\n * time; `xFormatter` stays baked at structural-build time (relative\n * is a values-axis concept; x is coordinate-space).\n *\n * When `ZoomToggle` installs a `dataZoom` slider, grid bottom is\n * extended and the slider is positioned above the legend row (if any) —\n * same layout dance bar / histogram / timeseries do.\n */\nexport function createScatterplotOptionFactory(\n options: ScatterplotOptionFactoryInput,\n): OptionFactory {\n const { theme, xFormatter, yFormatter, optionsOverride } = options\n const series = options.series\n const symbolSize = options.symbolSize ?? 8\n const selection = options.selection\n const selectionSet =\n selection && selection.length > 0 ? new Set<string>(selection) : null\n return (option, data, ctx) => {\n if (option == null) {\n const structural = scatterplotOptions({ theme, xFormatter, yFormatter })\n return optionsOverride\n ? (mergeOptions(\n structural as unknown as Record<string, unknown>,\n optionsOverride as Partial<Record<string, unknown>>,\n ) as EChartsOption)\n : structural\n }\n\n const seriesArr = Array.isArray(data)\n ? (data as ScatterplotWidgetData<ScatterplotItem>)\n : []\n if (seriesArr.length === 0) {\n return { ...option, dataset: [], series: [] }\n }\n const hasLegend = seriesArr.length > 1\n const baseLegend =\n typeof option.legend === 'object' && !Array.isArray(option.legend)\n ? option.legend\n : {}\n const baseGrid =\n typeof option.grid === 'object' && !Array.isArray(option.grid)\n ? option.grid\n : {}\n const baseTooltip =\n typeof option.tooltip === 'object' && !Array.isArray(option.tooltip)\n ? option.tooltip\n : {}\n const baseXAxis =\n typeof option.xAxis === 'object' && !Array.isArray(option.xAxis)\n ? option.xAxis\n : {}\n const baseYAxis =\n typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)\n ? option.yAxis\n : {}\n\n const reactiveFormatter = ctx?.formatter\n\n const { niceMinX, niceMaxX, niceMinY, niceMaxY } = computeScatterBounds(\n seriesArr,\n // A config transform (RelativeData's `'total'` scale) may pin the\n // y ends; each applies only on the side the data reaches.\n fixedAxisBounds(baseYAxis),\n )\n\n // Dim non-selected points via `series.itemStyle.color`. The selection\n // key is `${seriesIndex}:${dataIndex}`; we read those off the params\n // ECharts hands to the callback per-data.\n //\n // We *always* emit `itemStyle.color` (a passthrough when nothing is\n // selected), not conditionally — dropping the key between renders\n // would let ECharts' default merge keep the previous callback alive\n // and items would stay dimmed forever after an external clear.\n // Keeping the key always-present means a plain setOption merge swaps\n // the callback in place, no `replaceMerge` and no entry-animation\n // flash on selection on/off.\n //\n // The base colour is the point's own `color` (object points), else the\n // template's `itemStyle.color`, else the series colour / palette.\n const seriesTemplates = Array.isArray(option.series) ? option.series : []\n const makeDimColor = (seriesIdx: number, datums: readonly unknown[]) => {\n const baseColor = createItemColorResolver({\n theme,\n datums,\n template: seriesTemplates[seriesIdx] ?? seriesTemplates[0],\n fallback: (params) => params.color as string,\n })\n return (params: CallbackDataParams) => {\n const base = baseColor(params)\n if (!selectionSet) return base\n const key = `${seriesIdx}:${params.dataIndex}`\n return selectionSet.has(key)\n ? base\n : echarts.color.modifyAlpha(base, 0.15)\n }\n }\n\n // Zoom slider layout: when ZoomToggle has installed `dataZoom`,\n // reserve grid space and lift any x-slider above the legend (if\n // present). Scatter supports 2D zoom via `axes: ['x', 'y']` — in\n // that case there's also a vertical y-slider on the right edge, so\n // we reserve `grid.right` separately. Inside-only dataZoom entries\n // (no `type: 'slider'`) take no grid space.\n const dataZoomLayout = layoutDataZoomForScatter(option.dataZoom, hasLegend)\n const hasXSlider = dataZoomLayout?.hasXSlider ?? false\n const hasYSlider = dataZoomLayout?.hasYSlider ?? false\n const fallbackBottom =\n typeof baseGrid.bottom === 'number' ? baseGrid.bottom : 24\n const baseBottom = hasLegend ? 56 : fallbackBottom\n const gridBottom = hasXSlider\n ? baseBottom + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : baseBottom\n const fallbackRight =\n typeof baseGrid.right === 'number' ? baseGrid.right : 8\n const gridRight = hasYSlider\n ? fallbackRight + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : fallbackRight\n\n return {\n ...option,\n // ECharts dataset.source wants a mutable [number, number][] shape; we\n // hold readonly tuples internally, so cast at the boundary. Object\n // points are flattened to `[x, y]` so the positional encode and the\n // tooltip keep reading tuples.\n dataset: seriesArr.map((s) => ({\n source: (s.every(Array.isArray)\n ? s\n : s.map(getScatterplotXY)) as unknown as number[][],\n })),\n series: seriesArr.map((s, i) => {\n const overrideColor = resolveThemeColor(theme, series?.[i]?.color)\n return {\n type: 'scatter' as const,\n datasetIndex: i,\n name: series?.[i]?.name ?? `Series ${i + 1}`,\n encode: { x: 0, y: 1 },\n symbolSize,\n emphasis: { focus: 'series' },\n itemStyle: { color: makeDimColor(i, s) },\n ...(overrideColor ? { color: overrideColor } : {}),\n }\n }),\n legend: { ...baseLegend, show: hasLegend },\n grid: { ...baseGrid, bottom: gridBottom, right: gridRight },\n ...(dataZoomLayout ? { dataZoom: dataZoomLayout.entries } : {}),\n xAxis: {\n ...baseXAxis,\n min: niceMinX,\n max: niceMaxX,\n } as EChartsOption['xAxis'],\n yAxis: {\n ...baseYAxis,\n min: niceMinY,\n max: niceMaxY,\n axisLabel: {\n ...((baseYAxis as { axisLabel?: object }).axisLabel ?? {}),\n // Re-derive the y-axis formatter at fusion time so RelativeData's\n // percent formatter (written to `state.formatter`) flows through\n // without rebuilding the structural option. Falls back to the\n // structural `yFormatter` already baked in `baseYAxis.axisLabel`\n // (which `String(value)` if neither is set).\n ...(reactiveFormatter ? { formatter: reactiveFormatter } : {}),\n },\n } as EChartsOption['yAxis'],\n tooltip: {\n ...baseTooltip,\n // Rebuild the tooltip formatter so the live y-axis formatter is\n // applied to the y-coordinate in the (x, y) label. xFormatter is\n // structural — relative is a values-axis concept, so xFormatter\n // doesn't change under RelativeData.\n formatter: buildReactiveScatterTooltipFormatter(\n (baseTooltip as { formatter?: unknown }).formatter,\n reactiveFormatter,\n xFormatter,\n ),\n },\n } as EChartsOption\n }\n}\n\n/**\n * Lay out the `dataZoom` array for the scatter chart:\n * - Detect whether any horizontal (x-axis) slider is present — if so\n * lift it above the legend row when a legend is shown.\n * - Detect whether any vertical (y-axis) slider is present — the\n * caller reserves `grid.right` so the slider doesn't overlap the\n * plot area.\n *\n * Returns `null` when there's no `dataZoom` so callers can skip the\n * layout adjustment entirely. An entry is considered an \"x-slider\" if\n * it has `xAxisIndex` set (or no axis index — defaults to x in ECharts).\n * A \"y-slider\" has `yAxisIndex` set.\n */\nfunction layoutDataZoomForScatter(\n dataZoom: unknown,\n hasLegend: boolean,\n): { entries: unknown[]; hasXSlider: boolean; hasYSlider: boolean } | null {\n if (!Array.isArray(dataZoom) || dataZoom.length === 0) return null\n let hasXSlider = false\n let hasYSlider = false\n const entries = dataZoom.map((entry: unknown) => {\n if (entry == null || typeof entry !== 'object') return entry\n const dz = entry as {\n type?: string\n xAxisIndex?: unknown\n yAxisIndex?: unknown\n bottom?: number\n }\n if (dz.type !== 'slider') return dz\n const targetsY = dz.yAxisIndex !== undefined\n if (targetsY) {\n hasYSlider = true\n return dz\n }\n // Either explicit x or defaulted (ECharts defaults sliders to xAxis\n // when no axis index is provided).\n hasXSlider = true\n if (hasLegend) {\n return { ...dz, bottom: ZOOM_LAYOUT.sliderBottomWithLegend }\n }\n return dz\n })\n return { entries, hasXSlider, hasYSlider }\n}\n\n/**\n * If a reactive (store-driven) y formatter is provided, re-build the\n * scatter tooltip formatter using it. Otherwise, return the structural\n * formatter unchanged so the original `xFormatter` / `yFormatter`\n * baked into `scatterplotOptions` still applies. The structural\n * formatter has stable identity per `scatterplotOptions` call, so this\n * path doesn't churn ECharts on every render.\n */\nfunction buildReactiveScatterTooltipFormatter(\n structuralFormatter: unknown,\n reactiveYFormatter: ((value: number) => string) | undefined,\n xFormatter: ((value: number) => string) | undefined,\n) {\n if (!reactiveYFormatter) return structuralFormatter\n return createTooltipFormatter((item) => {\n const value = item.value as readonly [number, number] | undefined\n const x = value?.[0]\n const y = value?.[1]\n const formattedX =\n typeof x === 'number' ? (xFormatter ? xFormatter(x) : String(x)) : ''\n const formattedY =\n typeof y === 'number' ? reactiveYFormatter(y) : String(y ?? '')\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n return {\n name: `(${formattedX}, ${formattedY})`,\n seriesName,\n marker,\n value: '',\n }\n })\n}\n\nfunction buildScatterTooltipFormatter(\n xFormatter: ((value: number) => string) | undefined,\n yFormatter: ((value: number) => string) | undefined,\n) {\n return createTooltipFormatter((item) => {\n const value = item.value as readonly [number, number] | undefined\n const x = value?.[0]\n const y = value?.[1]\n const formattedX =\n typeof x === 'number' ? (xFormatter ? xFormatter(x) : String(x)) : ''\n const formattedY =\n typeof y === 'number' ? (yFormatter ? yFormatter(y) : String(y)) : ''\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n return {\n name: `(${formattedX}, ${formattedY})`,\n seriesName,\n marker,\n value: '',\n }\n })\n}\n\nfunction computeScatterBounds(\n seriesArr: ScatterplotWidgetData<ScatterplotItem>,\n fixedY: { min?: number; max?: number } = {},\n): {\n niceMinX: number\n niceMaxX: number\n niceMinY: number\n niceMaxY: number\n} {\n let minX = Infinity\n let maxX = -Infinity\n let minY = Infinity\n let maxY = -Infinity\n for (const series of seriesArr) {\n for (const point of series) {\n if (point == null) continue\n const [x, y] = getScatterplotXY(point)\n if (typeof x === 'number' && Number.isFinite(x)) {\n if (x < minX) minX = x\n if (x > maxX) maxX = x\n }\n if (typeof y === 'number' && Number.isFinite(y)) {\n if (y < minY) minY = y\n if (y > maxY) maxY = y\n }\n }\n }\n // Mirror bar's `computeNiceBounds`: clamp min to 0 when data is\n // non-negative (gridline reads cleanly from zero), apply `niceNum` to\n // negative mins, and floor max=0 to 1 so the chart always has range.\n // Scatter can have free coordinates so we apply this per-axis.\n const niceMaxX = Number.isFinite(maxX) ? (maxX <= 0 ? 1 : niceNum(maxX)) : 1\n const niceMaxY = Number.isFinite(maxY)\n ? maxY <= 0\n ? 1\n : (fixedY.max ?? niceNum(maxY))\n : 1\n const niceMinX = Number.isFinite(minX) ? (minX < 0 ? niceNum(minX) : 0) : 0\n const niceMinY = Number.isFinite(minY)\n ? minY < 0\n ? (fixedY.min ?? niceNum(minY))\n : 0\n : 0\n return { niceMinX, niceMaxX, niceMinY, niceMaxY }\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n container: {\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n flexDirection: 'column',\n gap: ({ spacing }) => spacing(1),\n height: ({ spacing }) => spacing(38),\n },\n grid: {\n position: 'relative',\n flex: '1 1 auto',\n width: '100%',\n },\n legend: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(2),\n height: ({ spacing }) => spacing(5),\n },\n legendItem: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(1.5),\n },\n} satisfies Record<string, SxProps<Theme>>\n\n// `sx` callback that needs runtime args — extracted at module scope so the\n// `styles` object can satisfy `Record<string, SxProps<Theme>>` cleanly\n// (function `sx`-with-args isn't assignable to plain `SxProps<Theme>`).\nconst dotSx = (top: string, left: string, size: number): SxProps<Theme> => ({\n position: 'absolute',\n top,\n left,\n width: size,\n height: size,\n borderRadius: '50%',\n})\n\nexport interface ScatterplotSkeletonProps {\n /** Number of dots to render. */\n count?: number\n}\n\n/**\n * Loading state for the Scatterplot widget. Mirrors a scatter chart's\n * silhouette — a deterministic spread of small circular dots in the plot\n * area plus a legend stub — so the skeleton reads as \"a scatter chart\"\n * rather than a generic list. Matches bar/histogram/pie skeleton structure\n * (grid stub + legend stub in a flex column).\n */\nexport function ScatterplotSkeleton({ count = 24 }: ScatterplotSkeletonProps) {\n // Deterministic pseudo-scatter positions so the skeleton doesn't flicker.\n const dots = Array.from({ length: count }, (_, i) => {\n const top = 10 + ((i * 37) % 80)\n const left = 5 + ((i * 53) % 90)\n const size = 8 + ((i * 7) % 6)\n return { top: `${top}%`, left: `${left}%`, size }\n })\n return (\n <Box sx={styles.container}>\n <Box sx={styles.grid}>\n {dots.map((d, i) => (\n <Skeleton\n key={`dot-${i}`}\n variant='circular'\n sx={dotSx(d.top, d.left, d.size)}\n />\n ))}\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>\n )\n}\n","import {\n buildCsvDownloadItem,\n buildPngDownloadItem,\n type DownloadContext,\n type DownloadItem,\n} from '../actions/download'\nimport { getScatterplotXY } from './points'\nimport type { ScatterplotItem, ScatterplotWidgetData } from './types'\n\n/**\n * Download menu items for the Scatterplot widget. Always includes a CSV\n * item with `series, x, y` columns (one row per point). When\n * `getCaptureEl` is supplied, prepends a PNG item that rasterises the\n * captured element via `html2canvas`.\n */\nexport function createScatterplotDownloadConfig(args: {\n filename: string\n getData: (ctx: DownloadContext) => ScatterplotWidgetData<ScatterplotItem>\n seriesNames?: readonly string[]\n getCaptureEl?: (ctx: DownloadContext) => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push(\n buildCsvDownloadItem({\n filename: args.filename,\n getRows: (ctx) => {\n const data = args.getData(ctx)\n const rows: unknown[][] = [['series', 'x', 'y']]\n for (const [i, series] of data.entries()) {\n const seriesName = args.seriesNames?.[i] ?? `series_${i + 1}`\n for (const point of series) {\n const [x, y] = getScatterplotXY(point)\n rows.push([seriesName, x, y])\n }\n }\n return rows\n },\n }),\n )\n return items\n}\n","import {\n getScatterplotXY,\n isScatterplotDatum,\n withScatterplotXY,\n} from './points'\nimport type { ScatterplotItem } from './types'\n\n/**\n * Scatterplot-specific `RelativeData` transform. Scatter data is\n * `ScatterplotItem[][]` — each series is a list of `[x, y]` tuples or\n * `{ x, y, color? }` points (whose shape is kept).\n * Relative is a values-axis concept, so this rewrites `y` to its\n * share of the series's total `y` (0–100) and leaves `x` raw — x is\n * coordinate space, not part of the cohort total.\n *\n * Pass to `<Widget.RelativeData transform={toRelativeScatterplotData} />`.\n *\n * The denominator is the sum of |y| across the series so mixed-sign\n * y values produce sane signed shares-of-magnitude. A series whose\n * total y-magnitude is zero (all-zero or empty input) is returned\n * unchanged so a stalled or empty data set doesn't show misleading 0%\n * values. Inputs whose shape isn't `ScatterplotItem[]` fall through\n * untouched.\n */\nexport const toRelativeScatterplotData = (input: unknown): unknown => {\n if (!Array.isArray(input)) return input\n return input.map((series: unknown): unknown => {\n if (!isPointArray(series)) return series\n const total = series.reduce(\n (acc, p) => acc + Math.abs(getScatterplotXY(p)[1]),\n 0,\n )\n if (total <= 0) return series\n return series.map((p) => {\n const [x, y] = getScatterplotXY(p)\n return withScatterplotXY(p, x, (y / total) * 100)\n })\n })\n}\n\nfunction isPointArray(v: unknown): v is ScatterplotItem[] {\n return Array.isArray(v) && v.every(isScatterplotDatum)\n}\n\n/**\n * `LockSelection` filter for Scatterplot. Data is `ScatterplotItem[][]` —\n * points have no `name`, so selection (and locking) is keyed on a synthetic\n * `${seriesIndex}:${dataIndex}` string (same format `useChartSelection`'s\n * `keyFromClick`/`keysFromBrush` produce for this widget). Unlike Histogram,\n * a point's position carries no external meaning (no `ticks` to desync from),\n * so non-locked points are removed outright rather than zeroed.\n */\nexport function filterScatterplotByLockedPoints(\n input: unknown,\n lockedItems: readonly (string | number)[],\n): unknown {\n if (lockedItems.length === 0) return input\n if (!Array.isArray(input)) return input\n const locked = new Set<string>(lockedItems.map(String))\n return input.map((series: unknown, seriesIndex: number): unknown => {\n if (!isPointArray(series)) return series\n return series.filter((_, dataIndex) =>\n locked.has(`${seriesIndex}:${dataIndex}`),\n )\n })\n}\n"],"mappings":";;;;;;;;;;;AAGA,SAAgBC,EACdC,GAC2B;CAC3B,OAAOC,EAAQD,CAAK,IAAIA,IAAQ,CAACA,EAAME,GAAGF,EAAMG,CAAC;AACnD;AAGA,SAAgBC,EAAmBC,GAAkC;CACnE,IAAIC,MAAMC,QAAQF,CAAC,GACjB,OAAOA,EAAEG,WAAW,KAAKC,EAAeJ,EAAE,EAAE,KAAKI,EAAeJ,EAAE,EAAE;CAEtE,IAAiB,OAAOA,KAAM,aAA1BA,GAAoC,OAAO;CAC/C,IAAM,EAAEH,MAAGC,SAAME;CACjB,OAAOI,EAAeP,CAAC,KAAKO,EAAeN,CAAC;AAC9C;AAGA,SAAgBO,EACdV,GACAE,GACAC,GACiB;CACjB,OAAOF,EAAQD,CAAK,IAAI,CAACE,GAAGC,CAAC,IAAI;EAAE,GAAGH;EAAOE;EAAGC;CAAE;AACpD;AAEA,SAASF,EAAQD,GAA4D;CAC3E,OAAOM,MAAMC,QAAQP,CAAK;AAC5B;AAEA,SAASS,EAAeJ,GAAyB;CAC/C,OAAO,OAAOA,KAAM,YAAYM,OAAOC,SAASP,CAAC;AACnD;;;ACMA,SAAgB6B,EAAmB,EACjCC,UACAC,eACAC,iBACoD;CACpD,OAAO;EACLC,MAAM;GACJC,MAAMC,SAASL,EAAMM,QAAQ,CAAC,CAAC;GAC/BC,KAAKF,SAASL,EAAMM,QAAQ,CAAC,CAAC;GAC9BE,OAAOH,SAASL,EAAMM,QAAQ,CAAC,CAAC;GAEhC,GAAGxB,EAAgB,IAAOkB,CAAK;GAC/BS,cAAc;EAChB;EACAC,SAAS;GAGPC,SAAS;GACTC,iBAAiBZ,EAAMa,QAAQC,KAAK;GACpCC,aAAa;GACbC,SAAS,CAACX,SAASL,EAAMM,QAAQ,CAAC,CAAC,GAAGD,SAASL,EAAMM,QAAQ,CAAC,CAAC,CAAC;GAChEW,WAAW;IACTC,OAAOlB,EAAMa,QAAQM,OAAOC;IAC5BC,UAAU;IACVC,YAAYtB,EAAMuB,WAAWC,QAAQF;GACvC;GACAG,UAAUxC,EAAwBe,CAAK;GACvC0B,WAAWC,EAA6B1B,GAAYC,CAAU;EAChE;EAGA0B,QAAQ,EACN,GAAG7C,EAAkB;GAAE8C,WAAW;GAAOC,gBAAgBC,KAAAA;EAAU,CAAC,EACtE;EACAC,aAAa,EAAEC,WAAW,EAAEf,OAAOlB,EAAMa,QAAQC,KAAK,KAAK,EAAE;EAC7DI,OAAO,CACLlB,EAAMa,QAAQqB,UAAUC,MACxB,GAAGC,OAAOC,OACPrC,EAAMa,QACJyB,aAAaC,QAAQ,CAAC,CAC3B,CAAC;EAEHE,OAAO;GACLC,MAAM;GACNC,UAAU,EAAEC,MAAM,GAAM;GACxBC,UAAU,EAAED,MAAM,GAAM;GACxBE,WAAW;IACT,GAAGjE,EAAoBmB,CAAK;IAC5B+C,QAAQ1C,SAASL,EAAMM,QAAQ,CAAC,CAAC;IACjC0C,aAAa;IACbC,cAAc;IACdC,cAAc;IACd,GAAIjD,KAAc,EAAEyB,WAAWzB,EAAW;GAC5C;GACAkD,WAAW;IACTP,MAAM;IACNX,WAAW,EAAEf,OAAOlB,EAAMa,QAAQuC,QAAQ,MAAMpD,EAAMa,QAAQwC,QAAQ;GACxE;EACF;EACAC,OAAO;GACLZ,MAAM;GACNC,UAAU,EAAEC,MAAM,GAAM;GACxBC,UAAU,EAAED,MAAM,GAAM;GACxBE,WAAW;IACT,GAAGjE,EAAoBmB,CAAK;IAC5B+C,QAAQ1C,SAASL,EAAMM,QAAQ,CAAC,CAAC;IACjC0C,aAAa;IACbC,cAAc;IACdC,cAAc;IACd,GAAIhD,KAAc,EAAEwB,WAAWxB,EAAW;GAC5C;GACAiD,WAAW;IACTP,MAAM;IACNX,WAAW,EAAEf,OAAOlB,EAAMa,QAAQuC,QAAQ,MAAMpD,EAAMa,QAAQwC,QAAQ;GACxE;EACF;CACF;AACF;AAyBA,SAAgBE,EACdC,GACe;CACf,IAAM,EAAExD,UAAOC,eAAYC,eAAYuD,uBAAoBD,GACrDE,IAASF,EAAQE,QACjBC,IAAaH,EAAQG,cAAc,GACnCC,IAAYJ,EAAQI,WACpBC,IACJD,KAAaA,EAAUE,SAAS,IAAI,IAAIC,IAAYH,CAAS,IAAI;CACnE,QAAQI,GAAQC,GAAMC,MAAQ;EAC5B,IAAIF,KAAU,MAAM;GAClB,IAAMG,IAAapE,EAAmB;IAAEC;IAAOC;IAAYC;GAAW,CAAC;GACvE,OAAOuD,IACFpE,EACC8E,GACAV,CACF,IACAU;EACN;EAEA,IAAME,IAAYC,MAAMC,QAAQN,CAAI,IAC/BA,IACD,CAAA;EACJ,IAAII,EAAUP,WAAW,GACvB,OAAO;GAAE,GAAGE;GAAQQ,SAAS,CAAA;GAAId,QAAQ,CAAA;EAAG;EAE9C,IAAM7B,IAAYwC,EAAUP,SAAS,GAC/BW,IACJ,OAAOT,EAAOpC,UAAW,YAAY,CAAC0C,MAAMC,QAAQP,EAAOpC,MAAM,IAC7DoC,EAAOpC,SACP,CAAC,GACD8C,IACJ,OAAOV,EAAO7D,QAAS,YAAY,CAACmE,MAAMC,QAAQP,EAAO7D,IAAI,IACzD6D,EAAO7D,OACP,CAAC,GACDwE,IACJ,OAAOX,EAAOtD,WAAY,YAAY,CAAC4D,MAAMC,QAAQP,EAAOtD,OAAO,IAC/DsD,EAAOtD,UACP,CAAC,GACDkE,IACJ,OAAOZ,EAAOvB,SAAU,YAAY,CAAC6B,MAAMC,QAAQP,EAAOvB,KAAK,IAC3DuB,EAAOvB,QACP,CAAC,GACDoC,IACJ,OAAOb,EAAOV,SAAU,YAAY,CAACgB,MAAMC,QAAQP,EAAOV,KAAK,IAC3DU,EAAOV,QACP,CAAC,GAEDwB,IAAoBZ,GAAKxC,WAEzB,EAAEqD,aAAUC,aAAUC,aAAUC,gBAAaC,EACjDd,GAGAvE,EAAgB+E,CAAS,CAC3B,GAgBMO,IAAkBd,MAAMC,QAAQP,EAAON,MAAM,IAAIM,EAAON,SAAS,CAAA,GACjE2B,KAAgBC,GAAmBC,MAA+B;GACtE,IAAMC,IAAYjG,EAAwB;IACxCS;IACAuF;IACAE,UAAUL,EAAgBE,MAAcF,EAAgB;IACxDM,WAAWC,MAAWA,EAAOzE;GAC/B,CAAC;GACD,QAAQyE,MAA+B;IACrC,IAAMC,IAAOJ,EAAUG,CAAM;IAC7B,IAAI,CAAC9B,GAAc,OAAO+B;IAC1B,IAAMC,IAAM,GAAGP,EAAS,GAAIK,EAAOG;IACnC,OAAOjC,EAAakC,IAAIF,CAAG,IACvBD,IACAjH,EAAQuC,MAAM8E,YAAYJ,GAAM,GAAI;GAC1C;EACF,GAQMK,IAAiBC,EAAyBlC,EAAOmC,UAAUtE,CAAS,GACpEuE,IAAaH,GAAgBG,cAAc,IAC3CC,IAAaJ,GAAgBI,cAAc,IAC3CC,IACJ,OAAO5B,EAAS6B,UAAW,WAAW7B,EAAS6B,SAAS,IACpDC,IAAa3E,IAAY,KAAKyE,GAC9BG,IAAaL,IACfI,IAAarH,EAAYuH,eAAevH,EAAYwH,YACpDH,GACEI,IACJ,OAAOlC,EAASlE,SAAU,WAAWkE,EAASlE,QAAQ,GAClDqG,IAAYR,IACdO,IAAgBzH,EAAYuH,eAAevH,EAAYwH,YACvDC;EAEJ,OAAO;GACL,GAAG5C;GAKHQ,SAASH,EAAUyC,KAAKC,OAAO,EAC7BC,QAASD,EAAEE,MAAM3C,MAAMC,OAAO,IAC1BwC,IACAA,EAAED,IAAItH,CAAgB,EAC5B,EAAE;GACFkE,QAAQW,EAAUyC,KAAKC,GAAGG,MAAM;IAC9B,IAAMC,IAAgB7H,EAAkBU,GAAO0D,IAASwD,EAAE,EAAEhG,KAAK;IACjE,OAAO;KACLwB,MAAM;KACN2E,cAAcH;KACdI,MAAM5D,IAASwD,EAAE,EAAEI,QAAQ,UAAUJ,IAAI;KACzCK,QAAQ;MAAEC,GAAG;MAAGC,GAAG;KAAE;KACrB9D;KACA+D,UAAU,EAAEC,OAAO,SAAS;KAC5BC,WAAW,EAAE1G,OAAOmE,EAAa6B,GAAGH,CAAC,EAAE;KACvC,GAAII,IAAgB,EAAEjG,OAAOiG,EAAc,IAAI,CAAC;IAClD;GACF,CAAC;GACDvF,QAAQ;IAAE,GAAG6C;IAAY7B,MAAMf;GAAU;GACzC1B,MAAM;IAAE,GAAGuE;IAAU6B,QAAQE;IAAYjG,OAAOqG;GAAU;GAC1D,GAAIZ,IAAiB,EAAEE,UAAUF,EAAe4B,QAAQ,IAAI,CAAC;GAC7DpF,OAAO;IACL,GAAGmC;IACHkD,KAAK/C;IACLgD,KAAK/C;GACP;GACA1B,OAAO;IACL,GAAGuB;IACHiD,KAAK7C;IACL8C,KAAK7C;IACLpC,WAAW;KACT,GAAK+B,EAAqC/B,aAAa,CAAC;KAMxD,GAAIgC,IAAoB,EAAEpD,WAAWoD,EAAkB,IAAI,CAAC;IAC9D;GACF;GACApE,SAAS;IACP,GAAGiE;IAKHjD,WAAWsG,EACRrD,EAAwCjD,WACzCoD,GACA7E,CACF;GACF;EACF;CACF;AACF;AAeA,SAASiG,EACPC,GACAtE,GACyE;CACzE,IAAI,CAACyC,MAAMC,QAAQ4B,CAAQ,KAAKA,EAASrC,WAAW,GAAG,OAAO;CAC9D,IAAIsC,IAAa,IACbC,IAAa;CAuBjB,OAAO;EAAEwB,SAtBO1B,EAASW,KAAKmB,MAAmB;GAC/C,IAAqB,OAAOA,KAAU,aAAlCA,GAA4C,OAAOA;GACvD,IAAMC,IAAKD;GAkBX,OAZIC,EAAGxF,SAAS,WACCwF,EAAGE,eAAerG,KAAAA,KAOnCqE,IAAa,IACTvE,IACK;IAAE,GAAGqG;IAAI3B,QAAQpH,EAAYmJ;GAAuB,IAEtDJ,MATL7B,IAAa,IACN6B,KAJwBA;EAanC,CACSL;EAASzB;EAAYC;CAAW;AAC3C;AAUA,SAAS2B,EACPO,GACAC,GACAvI,GACA;CAEA,OADKuI,IACExJ,GAAwB0J,MAAS;EACtC,IAAMD,IAAQC,EAAKD,OACbjB,IAAIiB,IAAQ,IACZhB,IAAIgB,IAAQ,IACZE,IACJ,OAAOnB,KAAM,WAAYvH,IAAaA,EAAWuH,CAAC,IAAIoB,OAAOpB,CAAC,IAAK,IAC/DqB,IACJ,OAAOpB,KAAM,WAAWe,EAAmBf,CAAC,IAAImB,OAAOnB,KAAK,EAAE,GAC1DqB,IAAS,OAAOJ,EAAKI,UAAW,WAAWJ,EAAKI,SAAS,IACzDC,IAAaL,EAAKK,aAAa,GAAGL,EAAKK,WAAU,MAAO;EAC9D,OAAO;GACLzB,MAAM,IAAIqB,EAAU,IAAKE,EAAU;GACnCE;GACAD;GACAL,OAAO;EACT;CACF,CAAC,IAjB+BF;AAkBlC;AAEA,SAAS5G,EACP1B,GACAC,GACA;CACA,OAAOlB,GAAwB0J,MAAS;EACtC,IAAMD,IAAQC,EAAKD,OACbjB,IAAIiB,IAAQ,IACZhB,IAAIgB,IAAQ,IACZE,IACJ,OAAOnB,KAAM,WAAYvH,IAAaA,EAAWuH,CAAC,IAAIoB,OAAOpB,CAAC,IAAK,IAC/DqB,IACJ,OAAOpB,KAAM,WAAYvH,IAAaA,EAAWuH,CAAC,IAAImB,OAAOnB,CAAC,IAAK,IAC/DqB,IAAS,OAAOJ,EAAKI,UAAW,WAAWJ,EAAKI,SAAS,IACzDC,IAAaL,EAAKK,aAAa,GAAGL,EAAKK,WAAU,MAAO;EAC9D,OAAO;GACLzB,MAAM,IAAIqB,EAAU,IAAKE,EAAU;GACnCE;GACAD;GACAL,OAAO;EACT;CACF,CAAC;AACH;AAEA,SAAStD,EACPd,GACA2E,IAAyC,CAAC,GAM1C;CACA,IAAIC,IAAOC,UACPC,IAAO,WACPC,IAAOF,UACPG,IAAO;CACX,KAAK,IAAM3F,KAAUW,GACnB,KAAK,IAAMiF,KAAS5F,GAAQ;EAC1B,IAAI4F,KAAS,MAAM;EACnB,IAAM,CAAC9B,GAAGC,KAAKjI,EAAiB8J,CAAK;EAKrC,AAJI,OAAO9B,KAAM,YAAY+B,OAAOC,SAAShC,CAAC,MACxCA,IAAIyB,MAAMA,IAAOzB,IACjBA,IAAI2B,MAAMA,IAAO3B,KAEnB,OAAOC,KAAM,YAAY8B,OAAOC,SAAS/B,CAAC,MACxCA,IAAI2B,MAAMA,IAAO3B,IACjBA,IAAI4B,MAAMA,IAAO5B;CAEzB;CAMF,IAAMzC,IAAWuE,OAAOC,SAASL,CAAI,IAAKA,KAAQ,IAAI,IAAIjK,EAAQiK,CAAI,IAAK,GACrEjE,IAAWqE,OAAOC,SAASH,CAAI,IACjCA,KAAQ,IACN,IACCL,EAAOjB,OAAO7I,EAAQmK,CAAI,IAC7B;CAOJ,OAAO;EAAEtE,UANQwE,OAAOC,SAASP,CAAI,KAAKA,IAAO,IAAI/J,EAAQ+J,CAAI,IAAI;EAMlDjE;EAAUC,UALZsE,OAAOC,SAASJ,CAAI,KACjCA,IAAO,IACJJ,EAAOlB,OAAO5I,EAAQkK,CAAI,IAC3B;EAEiClE;CAAS;AAClD;;;ACxcA,IAAM2E,IAAS;CACbC,WAAW;EACTC,SAAS;EACTC,YAAY;EACZC,gBAAgB;EAChBC,eAAe;EACfC,MAAM,EAAEC,iBAAcA,EAAQ,CAAC;EAC/BC,SAAS,EAAED,iBAAcA,EAAQ,EAAE;CACrC;CACAE,MAAM;EACJC,UAAU;EACVC,MAAM;EACNC,OAAO;CACT;CACAC,QAAQ;EACNX,SAAS;EACTC,YAAY;EACZG,MAAM,EAAEC,iBAAcA,EAAQ,CAAC;EAC/BC,SAAS,EAAED,iBAAcA,EAAQ,CAAC;CACpC;CACAO,YAAY;EACVZ,SAAS;EACTC,YAAY;EACZG,MAAM,EAAEC,iBAAcA,EAAQ,GAAG;CACnC;AACF,GAKMS,KAASC,GAAaC,GAAcC,OAAkC;CAC1ET,UAAU;CACVO;CACAC;CACAN,OAAOO;CACPX,QAAQW;CACRC,cAAc;AAChB;AAcA,SAAOG,EAAAC,GAAA;CAAA,IAAAC,IAAAC,EAAA,EAAA,GAA6B,EAAAJ,OAAAK,MAAAH,GAAEF,IAAAK,MAAAC,KAAAA,IAAA,KAAAD,GAAUE,GAAAC,GAAAC,GAAAC,GAAAC;CAAA,IAAAR,EAAA,OAAAH,GAAA;EAE9C,IAAAY,IAAaC,MAAKC,KAAM,EAAAC,QAAUf,EAAM,GAAGgB,CAK1C;EAUOb,AARLK,IAAAlC,GAAQqC,IAAAjC,EAAMC,WACZ4B,IAAAjC,GAAQmC,IAAA/B,EAAMS,MACZuB,IAAAE,EAAIK,IAAKC,CAMT,GAACf,EAAA,KAAAH,GAAAG,EAAA,KAAAI,GAAAJ,EAAA,KAAAK,GAAAL,EAAA,KAAAM,GAAAN,EAAA,KAAAO,GAAAP,EAAA,KAAAQ;CAAA,OAAAA,AAAAJ,IAAAJ,EAAA,IAAAK,IAAAL,EAAA,IAAAM,IAAAN,EAAA,IAAAO,IAAAP,EAAA,IAAAQ,IAAAR,EAAA;CAAA,IAAAgB;CAAA,AAAAhB,EAAA,OAAAI,KAAAJ,EAAA,OAAAM,KAAAN,EAAA,OAAAO,KAPJS,IAAA,kBAAC,GAAD;EAAS,IAAAV;EACNC,UAAAA;CADC,CAAA,GAQEP,EAAA,KAAAI,GAAAJ,EAAA,KAAAM,GAAAN,EAAA,KAAAO,GAAAP,EAAA,KAAAgB,KAAAA,IAAAhB,EAAA;CAAA,IAAAiB;CAAA,AAAAjB,EAAA,QAAAkB,OAAAC,IAAA,2BAAA,KACNF,IAAA,kBAAC,GAAD;EAAS,IAAA1C,EAAMa;EACZ,UAAA,CAAC,GAAG,CAAC,CAAC,CAAA0B,IAAKM,CAKX;CANC,CAAA,GAOEpB,EAAA,MAAAiB,KAAAA,IAAAjB,EAAA;CAAA,IAAAqB;CACF,OADErB,EAAA,QAAAK,KAAAL,EAAA,QAAAQ,KAAAR,EAAA,QAAAgB,KAjBRK,IAAA,kBAAC,GAAD;EAAS,IAAAb;EAAT,UAAA,CACEQ,GASAC,CAVE;KAkBEjB,EAAA,MAAAK,GAAAL,EAAA,MAAAQ,GAAAR,EAAA,MAAAgB,GAAAhB,EAAA,MAAAqB,KAAAA,IAAArB,EAAA,KAlBNqB;AAkBM;AA3BH,SAAAD,EAAAE,GAAA;CAAA,OAqBG,kBAAC,GAAD;EAA6B,IAAA/C,EAAMc;EAAnC,UAAA,CACE,kBAAC,GAAD;GAAkB,SAAA;GAAkB,OAAA;GAAW,QAAA;EAAC,CAAA,GAChD,kBAAC,GAAD;GAAiB,OAAA;GAAY,QAAA;EAAC,CAAA,CAF5B;CAAM,GAAA,UAAUkC,GAAhB;AAGE;AAxBT,SAAAR,EAAAS,GAAAC,GAAA;CAAA,OAYG,kBAAC,GAAD;EAEU,SAAA;EACJ,IAAAlC,EAAMiC,EAAChC,KAAMgC,EAAC/B,MAAO+B,EAAC9B,IAAK;CAAC,GAF3B,OAAO6B,GAEoB;AAChC;AAhBL,SAAAV,EAAAa,GAAAH,GAAA;CAGH,IAAA/B,IAAY,KAAO+B,IAAI,KAAM,IAC7B9B,IAAa,IAAM8B,IAAI,KAAM,IAC7B7B,IAAa,IAAM6B,IAAI,IAAK;CAAE,OACvB;EAAA/B,KAAO,GAAGA,EAAG;EAAGC,MAAQ,GAAGA,EAAI;EAAGC;CAAO;AAAC;;;AC7CrD,SAAgBwC,EAAgCC,GAO7B;CACjB,IAAMS,IAAwB,CAAA;CA4B9B,OA3BIT,EAAKK,gBACPI,EAAMC,KACJjB,EAAqB;EACnBQ,UAAUD,EAAKC;EACfI,cAAcL,EAAKK;EACnBM,YAAYX,EAAKO;EACjBK,iBAAiBZ,EAAKQ;CACxB,CAAC,CACH,GAEFC,EAAMC,KACJlB,EAAqB;EACnBS,UAAUD,EAAKC;EACfY,UAAUV,MAAQ;GAChB,IAAMW,IAAOd,EAAKE,QAAQC,CAAG,GACvBY,IAAoB,CAAC;IAAC;IAAU;IAAK;GAAG,CAAC;GAC/C,KAAK,IAAM,CAACC,GAAGC,MAAWH,EAAKI,QAAQ,GAAG;IACxC,IAAMC,IAAanB,EAAKI,cAAcY,MAAM,UAAUA,IAAI;IAC1D,KAAK,IAAMI,KAASH,GAAQ;KAC1B,IAAM,CAACI,GAAGC,KAAK1B,EAAiBwB,CAAK;KACrCL,EAAKL,KAAK;MAACS;MAAYE;MAAGC;KAAC,CAAC;IAC9B;GACF;GACA,OAAOP;EACT;CACF,CAAC,CACH,GACON;AACT;;;AC5BA,IAAakB,KAA6BC,MACnCC,MAAMC,QAAQF,CAAK,IACjBA,EAAMG,KAAKC,MAA6B;CAC7C,IAAI,CAACC,EAAaD,CAAM,GAAG,OAAOA;CAClC,IAAME,IAAQF,EAAOG,QAClBC,GAAKC,MAAMD,IAAME,KAAKC,IAAIhB,EAAiBc,CAAC,CAAC,CAAC,EAAE,GACjD,CACF;CAEA,OADIH,KAAS,IAAUF,IAChBA,EAAOD,KAAKM,MAAM;EACvB,IAAM,CAACG,GAAGC,KAAKlB,EAAiBc,CAAC;EACjC,OAAOZ,EAAkBY,GAAGG,GAAIC,IAAIP,IAAS,GAAG;CAClD,CAAC;AACH,CAAC,IAZiCN;AAepC,SAASK,EAAaS,GAAoC;CACxD,OAAOb,MAAMC,QAAQY,CAAC,KAAKA,EAAEC,MAAMnB,CAAkB;AACvD;AAUA,SAAgBoB,EACdhB,GACAiB,GACS;CAET,IADIA,EAAYC,WAAW,KACvB,CAACjB,MAAMC,QAAQF,CAAK,GAAG,OAAOA;CAClC,IAAMmB,IAAS,IAAIC,IAAYH,EAAYd,IAAIkB,MAAM,CAAC;CACtD,OAAOrB,EAAMG,KAAKC,GAAiBkB,MAC5BjB,EAAaD,CAAM,IACjBA,EAAOmB,QAAQC,GAAGC,MACvBN,EAAOO,IAAI,GAAGJ,EAAW,GAAIG,GAAW,CAC1C,IAHkCrB,CAInC;AACH"}