exploreda 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/README.md +144 -0
  2. package/dist/ExplorEda.cjs +4608 -11288
  3. package/dist/ExplorEda.cjs.map +1 -1
  4. package/dist/ExplorEda.css +2282 -1689
  5. package/dist/ExplorEda.css.map +1 -1
  6. package/dist/ExplorEda.d.cts +124 -278
  7. package/dist/ExplorEda.d.ts +124 -278
  8. package/dist/ExplorEda.js +4479 -11166
  9. package/dist/ExplorEda.js.map +1 -1
  10. package/dist/calculations.cjs +18 -0
  11. package/dist/calculations.cjs.map +1 -0
  12. package/dist/calculations.d.cts +63 -0
  13. package/dist/calculations.d.ts +63 -0
  14. package/dist/calculations.js +3 -0
  15. package/dist/calculations.js.map +1 -0
  16. package/dist/charts/bar.cjs +27 -0
  17. package/dist/charts/bar.cjs.map +1 -0
  18. package/dist/charts/bar.d.cts +2 -0
  19. package/dist/charts/bar.d.ts +2 -0
  20. package/dist/charts/bar.js +18 -0
  21. package/dist/charts/bar.js.map +1 -0
  22. package/dist/charts/box-plot.cjs +26 -0
  23. package/dist/charts/box-plot.cjs.map +1 -0
  24. package/dist/charts/box-plot.d.cts +2 -0
  25. package/dist/charts/box-plot.d.ts +2 -0
  26. package/dist/charts/box-plot.js +17 -0
  27. package/dist/charts/box-plot.js.map +1 -0
  28. package/dist/charts/color-legend.cjs +22 -0
  29. package/dist/charts/color-legend.cjs.map +1 -0
  30. package/dist/charts/color-legend.d.cts +2 -0
  31. package/dist/charts/color-legend.d.ts +2 -0
  32. package/dist/charts/color-legend.js +13 -0
  33. package/dist/charts/color-legend.js.map +1 -0
  34. package/dist/charts/data-table.cjs +22 -0
  35. package/dist/charts/data-table.cjs.map +1 -0
  36. package/dist/charts/data-table.d.cts +2 -0
  37. package/dist/charts/data-table.d.ts +2 -0
  38. package/dist/charts/data-table.js +13 -0
  39. package/dist/charts/data-table.js.map +1 -0
  40. package/dist/charts/line.cjs +30 -0
  41. package/dist/charts/line.cjs.map +1 -0
  42. package/dist/charts/line.d.cts +2 -0
  43. package/dist/charts/line.d.ts +2 -0
  44. package/dist/charts/line.js +17 -0
  45. package/dist/charts/line.js.map +1 -0
  46. package/dist/charts/markdown.cjs +16 -0
  47. package/dist/charts/markdown.cjs.map +1 -0
  48. package/dist/charts/markdown.css +77 -0
  49. package/dist/charts/markdown.css.map +1 -0
  50. package/dist/charts/markdown.d.cts +2 -0
  51. package/dist/charts/markdown.d.ts +2 -0
  52. package/dist/charts/markdown.js +7 -0
  53. package/dist/charts/markdown.js.map +1 -0
  54. package/dist/charts/pivot-table.cjs +23 -0
  55. package/dist/charts/pivot-table.cjs.map +1 -0
  56. package/dist/charts/pivot-table.d.cts +2 -0
  57. package/dist/charts/pivot-table.d.ts +2 -0
  58. package/dist/charts/pivot-table.js +14 -0
  59. package/dist/charts/pivot-table.js.map +1 -0
  60. package/dist/charts/row.cjs +27 -0
  61. package/dist/charts/row.cjs.map +1 -0
  62. package/dist/charts/row.d.cts +6 -0
  63. package/dist/charts/row.d.ts +6 -0
  64. package/dist/charts/row.js +18 -0
  65. package/dist/charts/row.js.map +1 -0
  66. package/dist/charts/scatter.cjs +24 -0
  67. package/dist/charts/scatter.cjs.map +1 -0
  68. package/dist/charts/scatter.d.cts +2 -0
  69. package/dist/charts/scatter.d.ts +2 -0
  70. package/dist/charts/scatter.js +15 -0
  71. package/dist/charts/scatter.js.map +1 -0
  72. package/dist/charts/summary-table.cjs +19 -0
  73. package/dist/charts/summary-table.cjs.map +1 -0
  74. package/dist/charts/summary-table.d.cts +2 -0
  75. package/dist/charts/summary-table.d.ts +2 -0
  76. package/dist/charts/summary-table.js +10 -0
  77. package/dist/charts/summary-table.js.map +1 -0
  78. package/dist/charts/three-d-scatter.cjs +24 -0
  79. package/dist/charts/three-d-scatter.cjs.map +1 -0
  80. package/dist/charts/three-d-scatter.d.cts +6 -0
  81. package/dist/charts/three-d-scatter.d.ts +6 -0
  82. package/dist/charts/three-d-scatter.js +15 -0
  83. package/dist/charts/three-d-scatter.js.map +1 -0
  84. package/dist/chunk-3PGYFLE3.cjs +499 -0
  85. package/dist/chunk-3PGYFLE3.cjs.map +1 -0
  86. package/dist/chunk-4HNDKMWF.js +167 -0
  87. package/dist/chunk-4HNDKMWF.js.map +1 -0
  88. package/dist/chunk-4QNENKTV.cjs +1214 -0
  89. package/dist/chunk-4QNENKTV.cjs.map +1 -0
  90. package/dist/chunk-54M32JJB.js +132 -0
  91. package/dist/chunk-54M32JJB.js.map +1 -0
  92. package/dist/chunk-5B23JVH3.cjs +2238 -0
  93. package/dist/chunk-5B23JVH3.cjs.map +1 -0
  94. package/dist/chunk-5LH6NSNL.js +456 -0
  95. package/dist/chunk-5LH6NSNL.js.map +1 -0
  96. package/dist/chunk-6DOKKCJ5.cjs +313 -0
  97. package/dist/chunk-6DOKKCJ5.cjs.map +1 -0
  98. package/dist/chunk-6HZX5CBT.cjs +1074 -0
  99. package/dist/chunk-6HZX5CBT.cjs.map +1 -0
  100. package/dist/chunk-6U5DOIQM.js +1071 -0
  101. package/dist/chunk-6U5DOIQM.js.map +1 -0
  102. package/dist/chunk-7GBZIK2R.cjs +80 -0
  103. package/dist/chunk-7GBZIK2R.cjs.map +1 -0
  104. package/dist/chunk-7PTJNIOD.js +520 -0
  105. package/dist/chunk-7PTJNIOD.js.map +1 -0
  106. package/dist/chunk-AHZYQ7FN.js +319 -0
  107. package/dist/chunk-AHZYQ7FN.js.map +1 -0
  108. package/dist/chunk-AOODAOL4.cjs +55 -0
  109. package/dist/chunk-AOODAOL4.cjs.map +1 -0
  110. package/dist/chunk-ASKFIRMC.cjs +165 -0
  111. package/dist/chunk-ASKFIRMC.cjs.map +1 -0
  112. package/dist/chunk-B7OQUBH4.cjs +171 -0
  113. package/dist/chunk-B7OQUBH4.cjs.map +1 -0
  114. package/dist/chunk-BIMEHDLB.js +72 -0
  115. package/dist/chunk-BIMEHDLB.js.map +1 -0
  116. package/dist/chunk-C62KHV7S.js +1225 -0
  117. package/dist/chunk-C62KHV7S.js.map +1 -0
  118. package/dist/chunk-C7GQT65O.cjs +1119 -0
  119. package/dist/chunk-C7GQT65O.cjs.map +1 -0
  120. package/dist/chunk-CGDWDV4Z.js +1211 -0
  121. package/dist/chunk-CGDWDV4Z.js.map +1 -0
  122. package/dist/chunk-CJQQFNEY.js +69 -0
  123. package/dist/chunk-CJQQFNEY.js.map +1 -0
  124. package/dist/chunk-DHYLSXNR.js +964 -0
  125. package/dist/chunk-DHYLSXNR.js.map +1 -0
  126. package/dist/chunk-DKFA4KOJ.cjs +87 -0
  127. package/dist/chunk-DKFA4KOJ.cjs.map +1 -0
  128. package/dist/chunk-DS5BS7PP.cjs +357 -0
  129. package/dist/chunk-DS5BS7PP.cjs.map +1 -0
  130. package/dist/chunk-EGMFQSGK.js +909 -0
  131. package/dist/chunk-EGMFQSGK.js.map +1 -0
  132. package/dist/chunk-EU5EFHO5.cjs +53 -0
  133. package/dist/chunk-EU5EFHO5.cjs.map +1 -0
  134. package/dist/chunk-FM46QSDM.js +837 -0
  135. package/dist/chunk-FM46QSDM.js.map +1 -0
  136. package/dist/chunk-GV2LRR32.cjs +843 -0
  137. package/dist/chunk-GV2LRR32.cjs.map +1 -0
  138. package/dist/chunk-H3XKFSA5.cjs +322 -0
  139. package/dist/chunk-H3XKFSA5.cjs.map +1 -0
  140. package/dist/chunk-H5AVMMCE.js +347 -0
  141. package/dist/chunk-H5AVMMCE.js.map +1 -0
  142. package/dist/chunk-JDMUN4VK.cjs +986 -0
  143. package/dist/chunk-JDMUN4VK.cjs.map +1 -0
  144. package/dist/chunk-JNO7OXCC.js +2171 -0
  145. package/dist/chunk-JNO7OXCC.js.map +1 -0
  146. package/dist/chunk-JQMG4ZR7.js +111 -0
  147. package/dist/chunk-JQMG4ZR7.js.map +1 -0
  148. package/dist/chunk-L2Q2R43U.cjs +118 -0
  149. package/dist/chunk-L2Q2R43U.cjs.map +1 -0
  150. package/dist/chunk-LBTZVERO.js +466 -0
  151. package/dist/chunk-LBTZVERO.js.map +1 -0
  152. package/dist/chunk-LUUGGTTK.cjs +1227 -0
  153. package/dist/chunk-LUUGGTTK.cjs.map +1 -0
  154. package/dist/chunk-MEEPH7ZC.cjs +911 -0
  155. package/dist/chunk-MEEPH7ZC.cjs.map +1 -0
  156. package/dist/chunk-MJPDJ5AS.js +184 -0
  157. package/dist/chunk-MJPDJ5AS.js.map +1 -0
  158. package/dist/chunk-MJROUIDZ.cjs +219 -0
  159. package/dist/chunk-MJROUIDZ.cjs.map +1 -0
  160. package/dist/chunk-MUWSBYJS.js +528 -0
  161. package/dist/chunk-MUWSBYJS.js.map +1 -0
  162. package/dist/chunk-NDF5LCST.js +1088 -0
  163. package/dist/chunk-NDF5LCST.js.map +1 -0
  164. package/dist/chunk-NGWTPED4.js +311 -0
  165. package/dist/chunk-NGWTPED4.js.map +1 -0
  166. package/dist/chunk-PP4VCONW.js +739 -0
  167. package/dist/chunk-PP4VCONW.js.map +1 -0
  168. package/dist/chunk-PRMC2A6P.cjs +488 -0
  169. package/dist/chunk-PRMC2A6P.cjs.map +1 -0
  170. package/dist/chunk-PST6UU6S.cjs +742 -0
  171. package/dist/chunk-PST6UU6S.cjs.map +1 -0
  172. package/dist/chunk-Q7LK2UWH.js +33 -0
  173. package/dist/chunk-Q7LK2UWH.js.map +1 -0
  174. package/dist/chunk-SFV5LZPD.js +162 -0
  175. package/dist/chunk-SFV5LZPD.js.map +1 -0
  176. package/dist/chunk-SKXGYJJG.cjs +370 -0
  177. package/dist/chunk-SKXGYJJG.cjs.map +1 -0
  178. package/dist/chunk-SWLNKY6R.js +477 -0
  179. package/dist/chunk-SWLNKY6R.js.map +1 -0
  180. package/dist/chunk-TGVLNHUB.cjs +483 -0
  181. package/dist/chunk-TGVLNHUB.cjs.map +1 -0
  182. package/dist/chunk-TLLRW6S3.js +74 -0
  183. package/dist/chunk-TLLRW6S3.js.map +1 -0
  184. package/dist/chunk-TRAIXZ6M.cjs +140 -0
  185. package/dist/chunk-TRAIXZ6M.cjs.map +1 -0
  186. package/dist/chunk-U74A5VK5.cjs +74 -0
  187. package/dist/chunk-U74A5VK5.cjs.map +1 -0
  188. package/dist/chunk-UAVDLBTA.cjs +74 -0
  189. package/dist/chunk-UAVDLBTA.cjs.map +1 -0
  190. package/dist/chunk-UJWS6TRV.js +354 -0
  191. package/dist/chunk-UJWS6TRV.js.map +1 -0
  192. package/dist/chunk-UUJMUPB3.cjs +531 -0
  193. package/dist/chunk-UUJMUPB3.cjs.map +1 -0
  194. package/dist/chunk-VTKHZIJB.cjs +549 -0
  195. package/dist/chunk-VTKHZIJB.cjs.map +1 -0
  196. package/dist/chunk-YXPAWUXO.js +51 -0
  197. package/dist/chunk-YXPAWUXO.js.map +1 -0
  198. package/dist/chunk-ZD64SCZB.js +80 -0
  199. package/dist/chunk-ZD64SCZB.js.map +1 -0
  200. package/dist/core.cjs +28 -0
  201. package/dist/core.cjs.map +1 -0
  202. package/dist/core.d.cts +22 -0
  203. package/dist/core.d.ts +22 -0
  204. package/dist/core.js +3 -0
  205. package/dist/core.js.map +1 -0
  206. package/dist/dataLayerState-B4XmQjQN.d.cts +258 -0
  207. package/dist/dataLayerState-B4XmQjQN.d.ts +258 -0
  208. package/package.json +30 -52
@@ -0,0 +1,1211 @@
1
+ import { BaseChart, formatTick } from './chunk-UJWS6TRV.js';
2
+ import { numericScale } from './chunk-7PTJNIOD.js';
3
+ import { FieldSelector, ComboBox } from './chunk-SFV5LZPD.js';
4
+ import { NumericInputEnter } from './chunk-BIMEHDLB.js';
5
+ import { Switch } from './chunk-Q7LK2UWH.js';
6
+ import { useGetColumnDataForIds, useGetLiveIds, useGetColumnDataForMultipleIds } from './chunk-ZD64SCZB.js';
7
+ import { applyFilter } from './chunk-YXPAWUXO.js';
8
+ import { useColumnNames, multi_select_default } from './chunk-SWLNKY6R.js';
9
+ import { Label } from './chunk-MJPDJ5AS.js';
10
+ import { useDataLayer, finiteNumber, getChartAxisFields, getChartAxisLabel, hasFieldDisplayFormat } from './chunk-JNO7OXCC.js';
11
+ import { LineChart as LineChart$1 } from 'lucide-react';
12
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
13
+ import { extent } from 'd3-array';
14
+ import { scaleLinear } from 'd3-scale';
15
+ import { useState, useMemo, useEffect, useId } from 'react';
16
+
17
+ function AxisReadout({
18
+ x: x2,
19
+ y: y2,
20
+ xValue,
21
+ yValue,
22
+ width,
23
+ height,
24
+ color,
25
+ label,
26
+ rightAxis = false,
27
+ radius = 4,
28
+ xFormatter = formatTick,
29
+ yFormatter = formatTick
30
+ }) {
31
+ if (![x2, y2, xValue, yValue].every(Number.isFinite)) return null;
32
+ const xText = xFormatter(xValue);
33
+ const yText = yFormatter(yValue);
34
+ const xLabelWidth = xText.length * 6 + 12;
35
+ const yLabelWidth = yText.length * 6 + 12;
36
+ const labelX = Math.max(
37
+ xLabelWidth / 2,
38
+ Math.min(width - xLabelWidth / 2, x2)
39
+ );
40
+ const edge = rightAxis ? width : 0;
41
+ return /* @__PURE__ */ jsxs(
42
+ "g",
43
+ {
44
+ className: "eda-axis-readout",
45
+ pointerEvents: "none",
46
+ role: "img",
47
+ "aria-label": label,
48
+ children: [
49
+ /* @__PURE__ */ jsxs(
50
+ "g",
51
+ {
52
+ stroke: color,
53
+ strokeOpacity: 0.4,
54
+ strokeWidth: 1,
55
+ strokeDasharray: "2 3",
56
+ children: [
57
+ /* @__PURE__ */ jsx("line", { x1: x2, x2, y1: y2, y2: height + 3 }),
58
+ /* @__PURE__ */ jsx("line", { x1: x2, x2: edge, y1: y2, y2 })
59
+ ]
60
+ }
61
+ ),
62
+ /* @__PURE__ */ jsx(
63
+ "circle",
64
+ {
65
+ cx: x2,
66
+ cy: y2,
67
+ r: radius,
68
+ fill: "var(--card)",
69
+ stroke: color,
70
+ strokeWidth: 1.5
71
+ }
72
+ ),
73
+ /* @__PURE__ */ jsx("circle", { cx: x2, cy: y2, r: 2, fill: color }),
74
+ /* @__PURE__ */ jsxs("g", { fill: "var(--card)", children: [
75
+ /* @__PURE__ */ jsx(
76
+ "rect",
77
+ {
78
+ x: labelX - xLabelWidth / 2,
79
+ y: height + 5,
80
+ width: xLabelWidth,
81
+ height: 20
82
+ }
83
+ ),
84
+ /* @__PURE__ */ jsx(
85
+ "rect",
86
+ {
87
+ x: rightAxis ? edge + 3 : -yLabelWidth - 3,
88
+ y: y2 - 10,
89
+ width: yLabelWidth,
90
+ height: 20
91
+ }
92
+ )
93
+ ] }),
94
+ /* @__PURE__ */ jsxs("g", { fill: color, fontSize: 10, fontWeight: 600, children: [
95
+ /* @__PURE__ */ jsx("text", { x: labelX, y: height + 18, textAnchor: "middle", children: xText }),
96
+ /* @__PURE__ */ jsx(
97
+ "text",
98
+ {
99
+ x: rightAxis ? edge + 8 : -8,
100
+ y: y2,
101
+ dy: ".32em",
102
+ textAnchor: rightAxis ? "start" : "end",
103
+ children: yText
104
+ }
105
+ )
106
+ ] })
107
+ ]
108
+ }
109
+ );
110
+ }
111
+
112
+ // src/lib/chartUtils.ts
113
+ function reduceDataPoints(data, numBuckets) {
114
+ if (!data || data.length === 0) {
115
+ return [];
116
+ }
117
+ const validBuckets = Math.max(1, Math.min(1e3, Math.floor(numBuckets)));
118
+ const orderedData = [...data].sort((a, b) => {
119
+ const aFinite = Number.isFinite(a.x);
120
+ const bFinite = Number.isFinite(b.x);
121
+ if (aFinite !== bFinite) return aFinite ? -1 : 1;
122
+ return aFinite ? a.x - b.x : 0;
123
+ });
124
+ if (data.length <= validBuckets * 3) {
125
+ return orderedData.map((point2) => ({ ...point2, type: "start" }));
126
+ }
127
+ const xExtent = {
128
+ min: Math.min(...orderedData.map((d) => d.x)),
129
+ max: Math.max(...orderedData.map((d) => d.x))
130
+ };
131
+ if (xExtent.min === xExtent.max) {
132
+ const firstPoint = data[0];
133
+ return firstPoint ? [{ ...firstPoint, type: "start" }] : [];
134
+ }
135
+ const buckets = Array(validBuckets).fill(null).map(() => []);
136
+ orderedData.forEach((point2) => {
137
+ const bucketIndex = Math.min(
138
+ Math.floor(
139
+ (point2.x - xExtent.min) / (xExtent.max - xExtent.min) * validBuckets
140
+ ),
141
+ validBuckets - 1
142
+ );
143
+ buckets[bucketIndex]?.push({ ...point2, type: "start" });
144
+ });
145
+ const result = [];
146
+ buckets.forEach((bucket) => {
147
+ if (bucket.length === 0) {
148
+ return;
149
+ }
150
+ const firstPoint = bucket[0];
151
+ if (!firstPoint) {
152
+ return;
153
+ }
154
+ result.push({ ...firstPoint, type: "start" });
155
+ if (bucket.length > 1) {
156
+ const minPoint = bucket.reduce((min, p) => p.y < min.y ? p : min);
157
+ const maxPoint = bucket.reduce((max, p) => p.y > max.y ? p : max);
158
+ if (minPoint !== firstPoint) {
159
+ result.push({ ...minPoint, type: "min" });
160
+ }
161
+ if (maxPoint !== firstPoint && maxPoint !== minPoint) {
162
+ result.push({ ...maxPoint, type: "max" });
163
+ }
164
+ }
165
+ });
166
+ return result.sort((a, b) => a.x - b.x);
167
+ }
168
+
169
+ // ../../node_modules/.pnpm/d3-shape@3.2.0/node_modules/d3-shape/src/constant.js
170
+ function constant_default(x2) {
171
+ return function constant() {
172
+ return x2;
173
+ };
174
+ }
175
+
176
+ // ../../node_modules/.pnpm/d3-path@3.1.0/node_modules/d3-path/src/path.js
177
+ var pi = Math.PI;
178
+ var tau = 2 * pi;
179
+ var epsilon = 1e-6;
180
+ var tauEpsilon = tau - epsilon;
181
+ function append(strings) {
182
+ this._ += strings[0];
183
+ for (let i = 1, n = strings.length; i < n; ++i) {
184
+ this._ += arguments[i] + strings[i];
185
+ }
186
+ }
187
+ function appendRound(digits) {
188
+ let d = Math.floor(digits);
189
+ if (!(d >= 0)) throw new Error(`invalid digits: ${digits}`);
190
+ if (d > 15) return append;
191
+ const k = 10 ** d;
192
+ return function(strings) {
193
+ this._ += strings[0];
194
+ for (let i = 1, n = strings.length; i < n; ++i) {
195
+ this._ += Math.round(arguments[i] * k) / k + strings[i];
196
+ }
197
+ };
198
+ }
199
+ var Path = class {
200
+ constructor(digits) {
201
+ this._x0 = this._y0 = // start of current subpath
202
+ this._x1 = this._y1 = null;
203
+ this._ = "";
204
+ this._append = digits == null ? append : appendRound(digits);
205
+ }
206
+ moveTo(x2, y2) {
207
+ this._append`M${this._x0 = this._x1 = +x2},${this._y0 = this._y1 = +y2}`;
208
+ }
209
+ closePath() {
210
+ if (this._x1 !== null) {
211
+ this._x1 = this._x0, this._y1 = this._y0;
212
+ this._append`Z`;
213
+ }
214
+ }
215
+ lineTo(x2, y2) {
216
+ this._append`L${this._x1 = +x2},${this._y1 = +y2}`;
217
+ }
218
+ quadraticCurveTo(x1, y1, x2, y2) {
219
+ this._append`Q${+x1},${+y1},${this._x1 = +x2},${this._y1 = +y2}`;
220
+ }
221
+ bezierCurveTo(x1, y1, x2, y2, x3, y3) {
222
+ this._append`C${+x1},${+y1},${+x2},${+y2},${this._x1 = +x3},${this._y1 = +y3}`;
223
+ }
224
+ arcTo(x1, y1, x2, y2, r) {
225
+ x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
226
+ if (r < 0) throw new Error(`negative radius: ${r}`);
227
+ let x0 = this._x1, y0 = this._y1, x21 = x2 - x1, y21 = y2 - y1, x01 = x0 - x1, y01 = y0 - y1, l01_2 = x01 * x01 + y01 * y01;
228
+ if (this._x1 === null) {
229
+ this._append`M${this._x1 = x1},${this._y1 = y1}`;
230
+ } else if (!(l01_2 > epsilon)) ;
231
+ else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {
232
+ this._append`L${this._x1 = x1},${this._y1 = y1}`;
233
+ } else {
234
+ let x20 = x2 - x0, y20 = y2 - y0, l21_2 = x21 * x21 + y21 * y21, l20_2 = x20 * x20 + y20 * y20, l21 = Math.sqrt(l21_2), l01 = Math.sqrt(l01_2), l = r * Math.tan((pi - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2), t01 = l / l01, t21 = l / l21;
235
+ if (Math.abs(t01 - 1) > epsilon) {
236
+ this._append`L${x1 + t01 * x01},${y1 + t01 * y01}`;
237
+ }
238
+ this._append`A${r},${r},0,0,${+(y01 * x20 > x01 * y20)},${this._x1 = x1 + t21 * x21},${this._y1 = y1 + t21 * y21}`;
239
+ }
240
+ }
241
+ arc(x2, y2, r, a0, a1, ccw) {
242
+ x2 = +x2, y2 = +y2, r = +r, ccw = !!ccw;
243
+ if (r < 0) throw new Error(`negative radius: ${r}`);
244
+ let dx = r * Math.cos(a0), dy = r * Math.sin(a0), x0 = x2 + dx, y0 = y2 + dy, cw = 1 ^ ccw, da = ccw ? a0 - a1 : a1 - a0;
245
+ if (this._x1 === null) {
246
+ this._append`M${x0},${y0}`;
247
+ } else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {
248
+ this._append`L${x0},${y0}`;
249
+ }
250
+ if (!r) return;
251
+ if (da < 0) da = da % tau + tau;
252
+ if (da > tauEpsilon) {
253
+ this._append`A${r},${r},0,1,${cw},${x2 - dx},${y2 - dy}A${r},${r},0,1,${cw},${this._x1 = x0},${this._y1 = y0}`;
254
+ } else if (da > epsilon) {
255
+ this._append`A${r},${r},0,${+(da >= pi)},${cw},${this._x1 = x2 + r * Math.cos(a1)},${this._y1 = y2 + r * Math.sin(a1)}`;
256
+ }
257
+ }
258
+ rect(x2, y2, w, h) {
259
+ this._append`M${this._x0 = this._x1 = +x2},${this._y0 = this._y1 = +y2}h${w = +w}v${+h}h${-w}Z`;
260
+ }
261
+ toString() {
262
+ return this._;
263
+ }
264
+ };
265
+
266
+ // ../../node_modules/.pnpm/d3-shape@3.2.0/node_modules/d3-shape/src/path.js
267
+ function withPath(shape) {
268
+ let digits = 3;
269
+ shape.digits = function(_) {
270
+ if (!arguments.length) return digits;
271
+ if (_ == null) {
272
+ digits = null;
273
+ } else {
274
+ const d = Math.floor(_);
275
+ if (!(d >= 0)) throw new RangeError(`invalid digits: ${_}`);
276
+ digits = d;
277
+ }
278
+ return shape;
279
+ };
280
+ return () => new Path(digits);
281
+ }
282
+ function array_default(x2) {
283
+ return typeof x2 === "object" && "length" in x2 ? x2 : Array.from(x2);
284
+ }
285
+
286
+ // ../../node_modules/.pnpm/d3-shape@3.2.0/node_modules/d3-shape/src/curve/linear.js
287
+ function Linear(context) {
288
+ this._context = context;
289
+ }
290
+ Linear.prototype = {
291
+ areaStart: function() {
292
+ this._line = 0;
293
+ },
294
+ areaEnd: function() {
295
+ this._line = NaN;
296
+ },
297
+ lineStart: function() {
298
+ this._point = 0;
299
+ },
300
+ lineEnd: function() {
301
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
302
+ this._line = 1 - this._line;
303
+ },
304
+ point: function(x2, y2) {
305
+ x2 = +x2, y2 = +y2;
306
+ switch (this._point) {
307
+ case 0:
308
+ this._point = 1;
309
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
310
+ break;
311
+ case 1:
312
+ this._point = 2;
313
+ // falls through
314
+ default:
315
+ this._context.lineTo(x2, y2);
316
+ break;
317
+ }
318
+ }
319
+ };
320
+ function linear_default(context) {
321
+ return new Linear(context);
322
+ }
323
+
324
+ // ../../node_modules/.pnpm/d3-shape@3.2.0/node_modules/d3-shape/src/point.js
325
+ function x(p) {
326
+ return p[0];
327
+ }
328
+ function y(p) {
329
+ return p[1];
330
+ }
331
+
332
+ // ../../node_modules/.pnpm/d3-shape@3.2.0/node_modules/d3-shape/src/line.js
333
+ function line_default(x2, y2) {
334
+ var defined = constant_default(true), context = null, curve = linear_default, output = null, path2 = withPath(line);
335
+ x2 = typeof x2 === "function" ? x2 : x2 === void 0 ? x : constant_default(x2);
336
+ y2 = typeof y2 === "function" ? y2 : y2 === void 0 ? y : constant_default(y2);
337
+ function line(data) {
338
+ var i, n = (data = array_default(data)).length, d, defined0 = false, buffer;
339
+ if (context == null) output = curve(buffer = path2());
340
+ for (i = 0; i <= n; ++i) {
341
+ if (!(i < n && defined(d = data[i], i, data)) === defined0) {
342
+ if (defined0 = !defined0) output.lineStart();
343
+ else output.lineEnd();
344
+ }
345
+ if (defined0) output.point(+x2(d, i, data), +y2(d, i, data));
346
+ }
347
+ if (buffer) return output = null, buffer + "" || null;
348
+ }
349
+ line.x = function(_) {
350
+ return arguments.length ? (x2 = typeof _ === "function" ? _ : constant_default(+_), line) : x2;
351
+ };
352
+ line.y = function(_) {
353
+ return arguments.length ? (y2 = typeof _ === "function" ? _ : constant_default(+_), line) : y2;
354
+ };
355
+ line.defined = function(_) {
356
+ return arguments.length ? (defined = typeof _ === "function" ? _ : constant_default(!!_), line) : defined;
357
+ };
358
+ line.curve = function(_) {
359
+ return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
360
+ };
361
+ line.context = function(_) {
362
+ return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
363
+ };
364
+ return line;
365
+ }
366
+
367
+ // ../../node_modules/.pnpm/d3-shape@3.2.0/node_modules/d3-shape/src/curve/monotone.js
368
+ function sign(x2) {
369
+ return x2 < 0 ? -1 : 1;
370
+ }
371
+ function slope3(that, x2, y2) {
372
+ var h0 = that._x1 - that._x0, h1 = x2 - that._x1, s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0), s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0), p = (s0 * h1 + s1 * h0) / (h0 + h1);
373
+ return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
374
+ }
375
+ function slope2(that, t) {
376
+ var h = that._x1 - that._x0;
377
+ return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
378
+ }
379
+ function point(that, t0, t1) {
380
+ var x0 = that._x0, y0 = that._y0, x1 = that._x1, y1 = that._y1, dx = (x1 - x0) / 3;
381
+ that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
382
+ }
383
+ function MonotoneX(context) {
384
+ this._context = context;
385
+ }
386
+ MonotoneX.prototype = {
387
+ areaStart: function() {
388
+ this._line = 0;
389
+ },
390
+ areaEnd: function() {
391
+ this._line = NaN;
392
+ },
393
+ lineStart: function() {
394
+ this._x0 = this._x1 = this._y0 = this._y1 = this._t0 = NaN;
395
+ this._point = 0;
396
+ },
397
+ lineEnd: function() {
398
+ switch (this._point) {
399
+ case 2:
400
+ this._context.lineTo(this._x1, this._y1);
401
+ break;
402
+ case 3:
403
+ point(this, this._t0, slope2(this, this._t0));
404
+ break;
405
+ }
406
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
407
+ this._line = 1 - this._line;
408
+ },
409
+ point: function(x2, y2) {
410
+ var t1 = NaN;
411
+ x2 = +x2, y2 = +y2;
412
+ if (x2 === this._x1 && y2 === this._y1) return;
413
+ switch (this._point) {
414
+ case 0:
415
+ this._point = 1;
416
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
417
+ break;
418
+ case 1:
419
+ this._point = 2;
420
+ break;
421
+ case 2:
422
+ this._point = 3;
423
+ point(this, slope2(this, t1 = slope3(this, x2, y2)), t1);
424
+ break;
425
+ default:
426
+ point(this, this._t0, t1 = slope3(this, x2, y2));
427
+ break;
428
+ }
429
+ this._x0 = this._x1, this._x1 = x2;
430
+ this._y0 = this._y1, this._y1 = y2;
431
+ this._t0 = t1;
432
+ }
433
+ };
434
+ (Object.create(MonotoneX.prototype)).point = function(x2, y2) {
435
+ MonotoneX.prototype.point.call(this, y2, x2);
436
+ };
437
+ function monotoneX(context) {
438
+ return new MonotoneX(context);
439
+ }
440
+
441
+ // ../../node_modules/.pnpm/d3-shape@3.2.0/node_modules/d3-shape/src/curve/step.js
442
+ function Step(context, t) {
443
+ this._context = context;
444
+ this._t = t;
445
+ }
446
+ Step.prototype = {
447
+ areaStart: function() {
448
+ this._line = 0;
449
+ },
450
+ areaEnd: function() {
451
+ this._line = NaN;
452
+ },
453
+ lineStart: function() {
454
+ this._x = this._y = NaN;
455
+ this._point = 0;
456
+ },
457
+ lineEnd: function() {
458
+ if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
459
+ if (this._line || this._line !== 0 && this._point === 1) this._context.closePath();
460
+ if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
461
+ },
462
+ point: function(x2, y2) {
463
+ x2 = +x2, y2 = +y2;
464
+ switch (this._point) {
465
+ case 0:
466
+ this._point = 1;
467
+ this._line ? this._context.lineTo(x2, y2) : this._context.moveTo(x2, y2);
468
+ break;
469
+ case 1:
470
+ this._point = 2;
471
+ // falls through
472
+ default: {
473
+ if (this._t <= 0) {
474
+ this._context.lineTo(this._x, y2);
475
+ this._context.lineTo(x2, y2);
476
+ } else {
477
+ var x1 = this._x * (1 - this._t) + x2 * this._t;
478
+ this._context.lineTo(x1, this._y);
479
+ this._context.lineTo(x1, y2);
480
+ }
481
+ break;
482
+ }
483
+ }
484
+ this._x = x2, this._y = y2;
485
+ }
486
+ };
487
+ function stepAfter(context) {
488
+ return new Step(context, 1);
489
+ }
490
+ var curveTypes = {
491
+ linear: linear_default,
492
+ monotoneX,
493
+ step: stepAfter
494
+ };
495
+ var COLOR_PALETTES = {
496
+ default: [
497
+ "#2563eb",
498
+ // blue-600
499
+ "#dc2626",
500
+ // red-600
501
+ "#9333ea",
502
+ // purple-600
503
+ "#ea580c",
504
+ // orange-600
505
+ "#0891b2",
506
+ // cyan-600
507
+ "#4f46e5",
508
+ // indigo-600
509
+ "#be123c",
510
+ // rose-600
511
+ "#ca8a04",
512
+ // yellow-600
513
+ "#16a34a",
514
+ // green-600
515
+ "#059669"
516
+ // emerald-600
517
+ ]
518
+ };
519
+ var LineChart = ({
520
+ settings,
521
+ width,
522
+ height,
523
+ facetIds
524
+ }) => {
525
+ const [hovered, setHovered] = useState(null);
526
+ const updateChart = useDataLayer((state) => state.updateChart);
527
+ const getFieldLabel = useDataLayer((state) => state.getFieldLabel);
528
+ const formatFieldValue = useDataLayer((state) => state.formatFieldValue);
529
+ const fieldSettings = useDataLayer((state) => state.fieldSettings);
530
+ const displayValue = (field, value) => hasFieldDisplayFormat(fieldSettings[field]) ? formatFieldValue?.(field, value) ?? String(value) : String(value);
531
+ const allXData = useGetColumnDataForIds(settings.xField);
532
+ const liveIds = useGetLiveIds(settings);
533
+ const selectedIds = useMemo(
534
+ () => facetIds ? liveIds.filter((id) => facetIds.includes(id)) : liveIds,
535
+ [liveIds, facetIds]
536
+ );
537
+ const liveXData = useGetColumnDataForIds(settings.xField, selectedIds);
538
+ const allSeriesData = useGetColumnDataForMultipleIds(settings.seriesField);
539
+ const liveSeriesData = useGetColumnDataForMultipleIds(
540
+ settings.seriesField,
541
+ selectedIds
542
+ );
543
+ const baseMargin = settings.margin;
544
+ const yValuesByAxis = settings.seriesField.reduce(
545
+ (values, field) => {
546
+ const useRightAxis = settings.seriesSettings[field]?.useRightAxis;
547
+ (allSeriesData[field] ?? []).forEach((value) => {
548
+ const y2 = finiteNumber(value) ?? NaN;
549
+ if (Number.isFinite(y2)) {
550
+ values[useRightAxis ? "right" : "left"].push(y2);
551
+ }
552
+ });
553
+ return values;
554
+ },
555
+ { left: [], right: [] }
556
+ );
557
+ const leftYExtent = extent(yValuesByAxis.left);
558
+ const leftYTicks = Number.isFinite(leftYExtent[0]) ? scaleLinear().domain(leftYExtent).nice().ticks(5) : [];
559
+ const axisFields = getChartAxisFields(settings);
560
+ const xAxisLabel = getChartAxisLabel(
561
+ axisFields.x,
562
+ settings.xAxisLabel,
563
+ getFieldLabel
564
+ );
565
+ const yAxisLabel = getChartAxisLabel(
566
+ axisFields.y,
567
+ settings.yAxisLabel,
568
+ getFieldLabel
569
+ );
570
+ const requestedLabelMargin = Math.max(
571
+ baseMargin.left,
572
+ ...leftYTicks.map(
573
+ (tick) => String(tick).length * 7 + (yAxisLabel ? 38 : 18)
574
+ )
575
+ );
576
+ const minPlotWidth = Math.min(
577
+ 80,
578
+ Math.max(0, width - baseMargin.left - baseMargin.right)
579
+ );
580
+ const maxLabelMargin = Math.max(0, width - baseMargin.right - minPlotWidth);
581
+ const margin = {
582
+ ...baseMargin,
583
+ left: Math.min(requestedLabelMargin, maxLabelMargin),
584
+ bottom: Math.max(baseMargin.bottom, xAxisLabel ? 46 : 28)
585
+ };
586
+ if (settings.seriesField.some(
587
+ (field) => settings.seriesSettings[field]?.useRightAxis
588
+ )) {
589
+ margin.right = Math.max(margin.right, 60);
590
+ }
591
+ if (settings.showLegend) {
592
+ switch (settings.legendPosition) {
593
+ case "top":
594
+ margin.top += 18;
595
+ break;
596
+ case "bottom":
597
+ margin.bottom += 18;
598
+ break;
599
+ case "right":
600
+ margin.right += Math.min(110, width * 0.24);
601
+ break;
602
+ case "left":
603
+ margin.left += Math.min(110, width * 0.24);
604
+ break;
605
+ }
606
+ }
607
+ const innerWidth = width - margin.left - margin.right;
608
+ const innerHeight = height - margin.top - margin.bottom;
609
+ const processedLiveSeriesData = useMemo(() => {
610
+ const orderedIndices = liveXData.map((_, index) => index).sort((a, b) => {
611
+ const aValue = liveXData[a];
612
+ const bValue = liveXData[b];
613
+ const aX = finiteNumber(aValue) ?? NaN;
614
+ const bX = finiteNumber(bValue) ?? NaN;
615
+ const aFinite = Number.isFinite(aX);
616
+ const bFinite = Number.isFinite(bX);
617
+ if (aFinite !== bFinite) return aFinite ? -1 : 1;
618
+ return aFinite ? aX - bX || a - b : a - b;
619
+ });
620
+ return settings.seriesField.map((field) => {
621
+ const data = liveSeriesData[field] ?? [];
622
+ const reducedData = [];
623
+ let segment = [];
624
+ const flushSegment = () => {
625
+ if (segment.length > 0) {
626
+ reducedData.push(...reduceDataPoints(segment, innerWidth));
627
+ segment = [];
628
+ }
629
+ };
630
+ orderedIndices.forEach((i) => {
631
+ const value = data[i];
632
+ const xValue = liveXData[i];
633
+ const x2 = finiteNumber(xValue) ?? NaN;
634
+ const y2 = finiteNumber(value) ?? NaN;
635
+ if (!Number.isFinite(x2) || !Number.isFinite(y2)) {
636
+ flushSegment();
637
+ reducedData.push({ x: x2, y: null });
638
+ return;
639
+ }
640
+ segment.push({ x: x2, y: y2 });
641
+ });
642
+ flushSegment();
643
+ return { name: field, data: reducedData };
644
+ });
645
+ }, [settings.seriesField, liveSeriesData, liveXData, innerWidth]);
646
+ const seriesColors = useMemo(() => {
647
+ const colors = {};
648
+ const palette = COLOR_PALETTES.default;
649
+ const usedPaletteColors = /* @__PURE__ */ new Set();
650
+ settings.seriesField.forEach((field) => {
651
+ const existingColor = settings.seriesSettings[field]?.lineColor;
652
+ if (existingColor && existingColor !== "#000000") {
653
+ colors[field] = existingColor;
654
+ if (palette.includes(existingColor)) {
655
+ usedPaletteColors.add(existingColor);
656
+ }
657
+ }
658
+ });
659
+ const unusedPaletteColors = palette.filter(
660
+ (color) => !usedPaletteColors.has(color)
661
+ );
662
+ settings.seriesField.forEach((field) => {
663
+ if (colors[field]) return;
664
+ const nextColor = unusedPaletteColors.shift();
665
+ colors[field] = nextColor ?? palette[settings.seriesField.indexOf(field) % palette.length];
666
+ });
667
+ return colors;
668
+ }, [settings.seriesField, settings.seriesSettings]);
669
+ useEffect(() => {
670
+ requestAnimationFrame(() => {
671
+ const newSeriesSettings = { ...settings.seriesSettings };
672
+ let hasChanges = false;
673
+ settings.seriesField.forEach((field) => {
674
+ if (!newSeriesSettings[field]) {
675
+ newSeriesSettings[field] = { ...DEFAULT_SERIES_SETTINGS };
676
+ hasChanges = true;
677
+ }
678
+ if (!newSeriesSettings[field]?.lineColor || newSeriesSettings[field]?.lineColor === "default") {
679
+ newSeriesSettings[field] = {
680
+ ...newSeriesSettings[field],
681
+ lineColor: seriesColors[field]
682
+ };
683
+ hasChanges = true;
684
+ }
685
+ });
686
+ if (hasChanges) {
687
+ updateChart(settings.id, {
688
+ seriesSettings: newSeriesSettings
689
+ });
690
+ }
691
+ });
692
+ }, [
693
+ seriesColors,
694
+ settings.id,
695
+ settings.seriesField,
696
+ settings.seriesSettings,
697
+ updateChart
698
+ ]);
699
+ if (processedLiveSeriesData.length === 0) {
700
+ return null;
701
+ }
702
+ const xExtent = extent(
703
+ allXData.map((value) => finiteNumber(value) ?? NaN).filter(Number.isFinite)
704
+ );
705
+ const rightAxisSeries = processedLiveSeriesData.filter(
706
+ (series) => settings.seriesSettings[series.name]?.useRightAxis
707
+ );
708
+ const rightYExtent = extent(yValuesByAxis.right);
709
+ const xScale = numericScale(settings.xAxis).domain(xExtent).range([0, innerWidth]).nice();
710
+ const leftYScale = numericScale(settings.yAxis).domain(leftYExtent).range([innerHeight, 0]).nice();
711
+ const rightYScale = numericScale(settings.yAxis).domain(rightYExtent).range([innerHeight, 0]).nice();
712
+ const createLineGenerator = (yField) => line_default().defined((d) => d.y != null && Number.isFinite(d.x)).x((d) => xScale(d.x)).y(
713
+ (d) => settings.seriesSettings[yField]?.useRightAxis ? rightYScale(d.y ?? 0) : leftYScale(d.y ?? 0)
714
+ ).curve(curveTypes[settings.styles.curveType]);
715
+ const Legend = () => {
716
+ if (!settings.showLegend) return null;
717
+ const vertical = settings.legendPosition === "left" || settings.legendPosition === "right";
718
+ const sideWidth = Math.min(100, width * 0.22);
719
+ const position = settings.legendPosition === "top" ? { top: 0, left: margin.left, right: baseMargin.right } : settings.legendPosition === "bottom" ? { bottom: 0, left: margin.left, right: baseMargin.right } : settings.legendPosition === "left" ? { left: 0, top: margin.top, width: sideWidth } : { right: 0, top: margin.top, width: sideWidth };
720
+ return /* @__PURE__ */ jsx(
721
+ "div",
722
+ {
723
+ className: "eda-line-legend",
724
+ style: { ...position, flexDirection: vertical ? "column" : "row" },
725
+ "aria-label": "Chart series",
726
+ children: settings.seriesField.map((name) => /* @__PURE__ */ jsxs("span", { className: "eda-line-legend-item", children: [
727
+ /* @__PURE__ */ jsx("svg", { width: "14", height: "6", "aria-hidden": "true", children: /* @__PURE__ */ jsx(
728
+ "line",
729
+ {
730
+ x1: "0",
731
+ x2: "14",
732
+ y1: "3",
733
+ y2: "3",
734
+ stroke: seriesColors[name],
735
+ strokeWidth: "2",
736
+ strokeDasharray: settings.seriesSettings[name]?.lineStyle === "dashed" ? "4 2" : settings.seriesSettings[name]?.lineStyle === "dotted" ? "1 2" : void 0
737
+ }
738
+ ) }),
739
+ /* @__PURE__ */ jsxs("span", { children: [
740
+ name,
741
+ settings.seriesSettings[name]?.useRightAxis ? " \u2197" : ""
742
+ ] })
743
+ ] }, name))
744
+ }
745
+ );
746
+ };
747
+ const hoverX = hovered ? hovered.x : NaN;
748
+ const hoverY = hovered ? hovered.y : NaN;
749
+ const hoverRight = hovered ? settings.seriesSettings[hovered.field]?.useRightAxis : false;
750
+ return /* @__PURE__ */ jsxs(
751
+ "div",
752
+ {
753
+ className: "relative",
754
+ style: { width, height },
755
+ onPointerLeave: () => setHovered(null),
756
+ onPointerDownCapture: () => setHovered(null),
757
+ onKeyDownCapture: (event) => {
758
+ if (event.key === "Escape") setHovered(null);
759
+ },
760
+ onPointerMove: (event) => {
761
+ if (event.buttons) return;
762
+ const rect = event.currentTarget.getBoundingClientRect();
763
+ const x2 = event.clientX - rect.left - margin.left;
764
+ const y2 = event.clientY - rect.top - margin.top;
765
+ if (x2 < 0 || x2 > innerWidth || y2 < 0 || y2 > innerHeight) {
766
+ setHovered(null);
767
+ return;
768
+ }
769
+ const target = xScale.invert(x2);
770
+ let nearestX = NaN;
771
+ let distance = Infinity;
772
+ for (const series of processedLiveSeriesData) {
773
+ for (const point2 of series.data) {
774
+ if (!Number.isFinite(point2.x)) continue;
775
+ const next = Math.abs(point2.x - target);
776
+ if (next < distance) {
777
+ nearestX = point2.x;
778
+ distance = next;
779
+ }
780
+ }
781
+ }
782
+ if (!Number.isFinite(nearestX)) {
783
+ setHovered(null);
784
+ return;
785
+ }
786
+ let field = null;
787
+ let valueAtX = NaN;
788
+ distance = Infinity;
789
+ for (const series of processedLiveSeriesData) {
790
+ for (const point2 of series.data) {
791
+ if (point2.x !== nearestX || point2.y == null) continue;
792
+ const scale = settings.seriesSettings[series.name]?.useRightAxis ? rightYScale : leftYScale;
793
+ const next = Math.abs(scale(point2.y) - y2);
794
+ if (next < distance) {
795
+ field = series.name;
796
+ valueAtX = point2.y;
797
+ distance = next;
798
+ }
799
+ }
800
+ }
801
+ setHovered(field === null ? null : { x: nearestX, y: valueAtX, field });
802
+ },
803
+ children: [
804
+ /* @__PURE__ */ jsx(
805
+ BaseChart,
806
+ {
807
+ width,
808
+ height,
809
+ xScale,
810
+ yScale: leftYScale,
811
+ settings: {
812
+ ...settings,
813
+ margin,
814
+ xAxis: {
815
+ ...settings.xAxis,
816
+ grid: settings.xAxis.grid ?? settings.showYGrid
817
+ },
818
+ yAxis: {
819
+ ...settings.yAxis,
820
+ grid: settings.yAxis.grid ?? settings.showXGrid
821
+ }
822
+ },
823
+ overlay: /* @__PURE__ */ jsxs(Fragment, { children: [
824
+ rightAxisSeries.length > 0 && /* @__PURE__ */ jsx("g", { transform: `translate(${innerWidth}, 0)`, children: rightYScale.ticks(5).map((tick) => /* @__PURE__ */ jsxs(
825
+ "g",
826
+ {
827
+ transform: `translate(0, ${rightYScale(tick)})`,
828
+ children: [
829
+ /* @__PURE__ */ jsx("line", { x1: 0, x2: 6, y1: 0, y2: 0, stroke: "currentColor" }),
830
+ /* @__PURE__ */ jsx(
831
+ "text",
832
+ {
833
+ x: 9,
834
+ y: 0,
835
+ dy: ".32em",
836
+ fontSize: 10,
837
+ textAnchor: "start",
838
+ fill: "currentColor",
839
+ children: tick
840
+ }
841
+ )
842
+ ]
843
+ },
844
+ tick
845
+ )) }),
846
+ hovered && /* @__PURE__ */ jsx(
847
+ AxisReadout,
848
+ {
849
+ x: xScale(hoverX),
850
+ y: (hoverRight ? rightYScale : leftYScale)(hoverY),
851
+ xValue: hoverX,
852
+ yValue: hoverY,
853
+ width: innerWidth,
854
+ height: innerHeight,
855
+ color: seriesColors[hovered.field],
856
+ rightAxis: hoverRight,
857
+ xFormatter: (value) => displayValue(settings.xField, value),
858
+ yFormatter: (value) => displayValue(hovered.field, value),
859
+ label: `${getFieldLabel?.(settings.xField) ?? settings.xField}: ${displayValue(settings.xField, hoverX)}; ${getFieldLabel?.(hovered.field) ?? hovered.field}: ${displayValue(hovered.field, hoverY)}`
860
+ }
861
+ )
862
+ ] }),
863
+ brushingMode: "horizontal",
864
+ onBrushChange: (extent2) => updateChart(settings.id, {
865
+ filters: [
866
+ ...settings.filters.filter(
867
+ (filter) => filter.field !== settings.xField
868
+ ),
869
+ ...extent2 ? [
870
+ {
871
+ type: "range",
872
+ field: settings.xField,
873
+ min: xScale.invert(extent2[0][0]),
874
+ max: xScale.invert(extent2[1][0])
875
+ }
876
+ ] : []
877
+ ]
878
+ }),
879
+ children: /* @__PURE__ */ jsx("g", { children: processedLiveSeriesData.map((series) => {
880
+ const lineGenerator = createLineGenerator(series.name);
881
+ const seriesSettings = settings.seriesSettings[series.name] ?? {
882
+ showPoints: false,
883
+ pointSize: 4,
884
+ pointOpacity: 1,
885
+ lineWidth: 2,
886
+ lineOpacity: 0.8,
887
+ lineStyle: "solid",
888
+ useRightAxis: false
889
+ };
890
+ const seriesColor = seriesColors[series.name];
891
+ return /* @__PURE__ */ jsxs("g", { children: [
892
+ /* @__PURE__ */ jsx(
893
+ "path",
894
+ {
895
+ d: lineGenerator(series.data) || void 0,
896
+ fill: "none",
897
+ stroke: seriesColor,
898
+ strokeWidth: seriesSettings.lineWidth,
899
+ strokeOpacity: seriesSettings.lineOpacity,
900
+ strokeDasharray: seriesSettings.lineStyle === "dashed" ? "5,5" : seriesSettings.lineStyle === "dotted" ? "2,2" : void 0
901
+ }
902
+ ),
903
+ seriesSettings.showPoints && series.data.map(
904
+ (d, j) => d.y == null ? null : /* @__PURE__ */ jsx(
905
+ "circle",
906
+ {
907
+ cx: xScale(d.x),
908
+ cy: (seriesSettings.useRightAxis ? rightYScale : leftYScale)(d.y),
909
+ r: seriesSettings.pointSize,
910
+ fill: seriesColor,
911
+ fillOpacity: seriesSettings.pointOpacity
912
+ },
913
+ j
914
+ )
915
+ )
916
+ ] }, series.name);
917
+ }) })
918
+ }
919
+ ),
920
+ /* @__PURE__ */ jsx(Legend, {})
921
+ ]
922
+ }
923
+ );
924
+ };
925
+ function LineSeriesSettings({
926
+ seriesName,
927
+ settings,
928
+ onSettingsChange
929
+ }) {
930
+ const id = useId();
931
+ const update = (next) => onSettingsChange({ ...settings, ...next });
932
+ const numericFields = [
933
+ { key: "lineWidth", label: "Line width", min: 1, max: 10, step: 0.5 },
934
+ { key: "lineOpacity", label: "Line opacity", min: 0, max: 1, step: 0.1 },
935
+ ...settings.showPoints ? [
936
+ { key: "pointSize", label: "Point size", min: 1, max: 20, step: 1 },
937
+ {
938
+ key: "pointOpacity",
939
+ label: "Point opacity",
940
+ min: 0,
941
+ max: 1,
942
+ step: 0.1
943
+ }
944
+ ] : []
945
+ ];
946
+ return /* @__PURE__ */ jsxs("fieldset", { className: "space-y-3 border-t border-border pt-3", children: [
947
+ /* @__PURE__ */ jsx("legend", { className: "px-1 text-sm font-semibold", children: seriesName }),
948
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-5", children: [
949
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
950
+ /* @__PURE__ */ jsx(
951
+ Switch,
952
+ {
953
+ id: `${id}-points`,
954
+ "aria-label": `${seriesName} points`,
955
+ checked: settings.showPoints,
956
+ onCheckedChange: (showPoints) => update({ showPoints })
957
+ }
958
+ ),
959
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-points`, children: "Show points" })
960
+ ] }),
961
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
962
+ /* @__PURE__ */ jsx(
963
+ Switch,
964
+ {
965
+ id: `${id}-axis`,
966
+ "aria-label": `${seriesName} right axis`,
967
+ checked: settings.useRightAxis,
968
+ onCheckedChange: (useRightAxis) => update({ useRightAxis })
969
+ }
970
+ ),
971
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-axis`, children: "Right axis" })
972
+ ] })
973
+ ] }),
974
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3", children: [
975
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
976
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-color`, children: "Color" }),
977
+ /* @__PURE__ */ jsx(
978
+ "input",
979
+ {
980
+ id: `${id}-color`,
981
+ "aria-label": `${seriesName} color`,
982
+ type: "color",
983
+ value: settings.lineColor ?? "#3479a8",
984
+ onChange: (event) => update({ lineColor: event.target.value }),
985
+ className: "h-8 w-full rounded border"
986
+ }
987
+ )
988
+ ] }),
989
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
990
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-style`, children: "Line style" }),
991
+ /* @__PURE__ */ jsxs(
992
+ "select",
993
+ {
994
+ id: `${id}-style`,
995
+ value: settings.lineStyle,
996
+ onChange: (event) => update({
997
+ lineStyle: event.target.value
998
+ }),
999
+ className: "h-8 w-full rounded border bg-background px-2 text-sm",
1000
+ children: [
1001
+ /* @__PURE__ */ jsx("option", { value: "solid", children: "Solid" }),
1002
+ /* @__PURE__ */ jsx("option", { value: "dashed", children: "Dashed" }),
1003
+ /* @__PURE__ */ jsx("option", { value: "dotted", children: "Dotted" })
1004
+ ]
1005
+ }
1006
+ )
1007
+ ] }),
1008
+ numericFields.map(({ key, label, min, max, step }) => /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1009
+ /* @__PURE__ */ jsx(Label, { htmlFor: `${id}-${key}`, children: label }),
1010
+ /* @__PURE__ */ jsx(
1011
+ NumericInputEnter,
1012
+ {
1013
+ id: `${id}-${key}`,
1014
+ value: settings[key],
1015
+ onChange: (value) => update({ [key]: value }),
1016
+ min,
1017
+ max,
1018
+ stepSmall: step,
1019
+ className: "h-8"
1020
+ }
1021
+ )
1022
+ ] }, key))
1023
+ ] })
1024
+ ] });
1025
+ }
1026
+ var LineChartSettingsPanel = ({ settings, onSettingsChange }) => {
1027
+ const updateSettings = (updates) => {
1028
+ onSettingsChange({ ...settings, ...updates });
1029
+ };
1030
+ const updateStyles = (updates) => {
1031
+ updateSettings({
1032
+ styles: { ...settings.styles, ...updates }
1033
+ });
1034
+ };
1035
+ const updateSeriesSettings = (seriesName, seriesSettings) => {
1036
+ updateSettings({
1037
+ seriesSettings: {
1038
+ ...settings.seriesSettings,
1039
+ [seriesName]: seriesSettings
1040
+ }
1041
+ });
1042
+ };
1043
+ const availableFields = useColumnNames();
1044
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1045
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[120px_1fr] items-center gap-4", children: [
1046
+ /* @__PURE__ */ jsx(Label, { children: "X Field" }),
1047
+ /* @__PURE__ */ jsx(
1048
+ FieldSelector,
1049
+ {
1050
+ label: "",
1051
+ value: settings.xField,
1052
+ onChange: (value) => updateSettings({ xField: value })
1053
+ }
1054
+ ),
1055
+ /* @__PURE__ */ jsx(Label, { children: "Series Fields" }),
1056
+ /* @__PURE__ */ jsx(
1057
+ multi_select_default,
1058
+ {
1059
+ options: availableFields.map((f) => ({
1060
+ label: f,
1061
+ value: f
1062
+ })),
1063
+ value: settings.seriesField.map((f) => ({
1064
+ label: f,
1065
+ value: f
1066
+ })),
1067
+ onChange: (values) => {
1068
+ const newSeriesFields = values.map((v) => v.value);
1069
+ const newSeriesSettings = { ...settings.seriesSettings };
1070
+ newSeriesFields.forEach((field) => {
1071
+ if (!newSeriesSettings[field]) {
1072
+ newSeriesSettings[field] = { ...DEFAULT_SERIES_SETTINGS };
1073
+ }
1074
+ });
1075
+ Object.keys(newSeriesSettings).forEach((field) => {
1076
+ if (!newSeriesFields.includes(field)) {
1077
+ delete newSeriesSettings[field];
1078
+ }
1079
+ });
1080
+ updateSettings({
1081
+ seriesField: newSeriesFields,
1082
+ seriesSettings: newSeriesSettings
1083
+ });
1084
+ }
1085
+ }
1086
+ )
1087
+ ] }),
1088
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-[120px_1fr] items-center gap-4", children: [
1089
+ /* @__PURE__ */ jsx(Label, { children: "Line Style" }),
1090
+ /* @__PURE__ */ jsx(
1091
+ ComboBox,
1092
+ {
1093
+ value: {
1094
+ label: settings.styles.curveType === "linear" ? "Linear" : settings.styles.curveType === "monotoneX" ? "Smooth" : "Step",
1095
+ value: settings.styles.curveType
1096
+ },
1097
+ options: [
1098
+ { label: "Linear", value: "linear" },
1099
+ { label: "Smooth", value: "monotoneX" },
1100
+ { label: "Step", value: "step" }
1101
+ ],
1102
+ onChange: (option) => updateStyles({ curveType: option?.value ?? "linear" }),
1103
+ optionToString: (option) => option.label
1104
+ }
1105
+ ),
1106
+ /* @__PURE__ */ jsx(Label, { children: "Show Legend" }),
1107
+ /* @__PURE__ */ jsx("div", { className: "flex items-center", children: /* @__PURE__ */ jsx(
1108
+ Switch,
1109
+ {
1110
+ checked: settings.showLegend,
1111
+ onCheckedChange: (checked) => updateSettings({ showLegend: checked })
1112
+ }
1113
+ ) }),
1114
+ settings.showLegend && /* @__PURE__ */ jsxs(Fragment, { children: [
1115
+ /* @__PURE__ */ jsx(Label, { children: "Legend Position" }),
1116
+ /* @__PURE__ */ jsx(
1117
+ ComboBox,
1118
+ {
1119
+ value: {
1120
+ label: settings.legendPosition.charAt(0).toUpperCase() + settings.legendPosition.slice(1),
1121
+ value: settings.legendPosition
1122
+ },
1123
+ options: [
1124
+ { label: "Top", value: "top" },
1125
+ { label: "Right", value: "right" },
1126
+ { label: "Bottom", value: "bottom" },
1127
+ { label: "Left", value: "left" }
1128
+ ],
1129
+ onChange: (option) => updateSettings({
1130
+ legendPosition: option?.value ?? "top"
1131
+ }),
1132
+ optionToString: (option) => option.label
1133
+ }
1134
+ )
1135
+ ] })
1136
+ ] }),
1137
+ /* @__PURE__ */ jsx("div", { className: "space-y-4", children: settings.seriesField.map((field) => /* @__PURE__ */ jsx(
1138
+ LineSeriesSettings,
1139
+ {
1140
+ seriesName: field,
1141
+ settings: settings.seriesSettings[field] ?? DEFAULT_SERIES_SETTINGS,
1142
+ onSettingsChange: (next) => updateSeriesSettings(field, next)
1143
+ },
1144
+ field
1145
+ )) })
1146
+ ] });
1147
+ };
1148
+
1149
+ // src/components/charts/LineChart/definition.ts
1150
+ var DEFAULT_SERIES_SETTINGS = {
1151
+ showPoints: false,
1152
+ pointSize: 4,
1153
+ pointOpacity: 1,
1154
+ lineWidth: 2,
1155
+ lineOpacity: 0.8,
1156
+ lineStyle: "solid",
1157
+ useRightAxis: false
1158
+ };
1159
+ var lineChartDefinition = {
1160
+ type: "line",
1161
+ name: "Line Chart",
1162
+ description: "Display data as connected points over time or sequence",
1163
+ icon: LineChart$1,
1164
+ component: LineChart,
1165
+ settingsPanel: LineChartSettingsPanel,
1166
+ createDefaultSettings: (layout) => ({
1167
+ id: "",
1168
+ type: "line",
1169
+ title: "",
1170
+ field: "",
1171
+ layout,
1172
+ colorScaleId: void 0,
1173
+ colorField: void 0,
1174
+ facet: {
1175
+ enabled: false,
1176
+ type: "grid",
1177
+ rowVariable: "",
1178
+ columnVariable: ""
1179
+ },
1180
+ xAxis: {},
1181
+ yAxis: {},
1182
+ margin: { top: 20, right: 60, bottom: 30, left: 60 },
1183
+ filters: [],
1184
+ xAxisLabel: "",
1185
+ yAxisLabel: "",
1186
+ xGridLines: 5,
1187
+ yGridLines: 5,
1188
+ xField: "",
1189
+ seriesField: [],
1190
+ seriesSettings: {},
1191
+ styles: {
1192
+ curveType: "linear"
1193
+ },
1194
+ showXGrid: true,
1195
+ showYGrid: true,
1196
+ showLegend: true,
1197
+ legendPosition: "top"
1198
+ }),
1199
+ validateSettings: (settings) => {
1200
+ return settings.xField !== "" && settings.seriesField.length > 0;
1201
+ },
1202
+ getFilterFunction: (settings, fieldGetter) => {
1203
+ return (d) => settings.filters.every(
1204
+ (filter) => applyFilter(fieldGetter(filter.field)[d], filter)
1205
+ );
1206
+ }
1207
+ };
1208
+
1209
+ export { DEFAULT_SERIES_SETTINGS, lineChartDefinition };
1210
+ //# sourceMappingURL=chunk-CGDWDV4Z.js.map
1211
+ //# sourceMappingURL=chunk-CGDWDV4Z.js.map