@epilot/spark-ui 0.20.0 → 0.20.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/components/accordion.cjs +2 -2
  2. package/dist/components/accordion.d.ts +1 -1
  3. package/dist/components/accordion.js +1 -1
  4. package/dist/components/alert-dialog.cjs +1 -1
  5. package/dist/components/alert-dialog.js +1 -1
  6. package/dist/components/autocomplete.cjs +1 -1
  7. package/dist/components/autocomplete.js +1 -1
  8. package/dist/components/bar-chart-with-total.d.cts +1 -1
  9. package/dist/components/bar-chart-with-total.d.ts +1 -1
  10. package/dist/components/bar-chart.cjs +1 -1
  11. package/dist/components/bar-chart.js +2 -2
  12. package/dist/components/calendar.cjs +1 -1
  13. package/dist/components/calendar.js +1 -1
  14. package/dist/components/callout.cjs +1 -1
  15. package/dist/components/callout.d.cts +1 -1
  16. package/dist/components/callout.d.ts +2 -2
  17. package/dist/components/callout.js +1 -1
  18. package/dist/components/dialog.cjs +1 -1
  19. package/dist/components/dialog.js +1 -1
  20. package/dist/components/dropdown-menu.cjs +1 -1
  21. package/dist/components/dropdown-menu.js +1 -1
  22. package/dist/components/empty-state.d.ts +1 -1
  23. package/dist/components/energy-breakdown.cjs +80 -0
  24. package/dist/components/energy-breakdown.cjs.map +1 -0
  25. package/dist/components/energy-breakdown.d.cts +24 -0
  26. package/dist/components/energy-breakdown.d.ts +24 -0
  27. package/dist/components/energy-breakdown.js +79 -0
  28. package/dist/components/energy-breakdown.js.map +1 -0
  29. package/dist/components/energy-history-chart.cjs +63 -0
  30. package/dist/components/energy-history-chart.cjs.map +1 -0
  31. package/dist/components/energy-history-chart.d.cts +64 -0
  32. package/dist/components/energy-history-chart.d.ts +64 -0
  33. package/dist/components/energy-history-chart.js +62 -0
  34. package/dist/components/energy-history-chart.js.map +1 -0
  35. package/dist/components/entity-card.d.ts +1 -1
  36. package/dist/components/input-date.cjs +1 -1
  37. package/dist/components/input-date.js +1 -1
  38. package/dist/components/input-group.d.cts +1 -1
  39. package/dist/components/input-group.d.ts +1 -1
  40. package/dist/components/line-chart.cjs +3 -3
  41. package/dist/components/line-chart.js +4 -4
  42. package/dist/components/message-scroller.cjs +2 -2
  43. package/dist/components/message-scroller.js +2 -2
  44. package/dist/components/number-flow.d.cts +2 -12
  45. package/dist/components/number-flow.d.ts +2 -12
  46. package/dist/components/page-header.cjs +1 -1
  47. package/dist/components/page-header.js +1 -1
  48. package/dist/components/pill.cjs +1 -1
  49. package/dist/components/pill.js +1 -1
  50. package/dist/components/power-history-chart.cjs +498 -0
  51. package/dist/components/power-history-chart.cjs.map +1 -0
  52. package/dist/components/power-history-chart.d.cts +71 -0
  53. package/dist/components/power-history-chart.d.ts +71 -0
  54. package/dist/components/power-history-chart.js +496 -0
  55. package/dist/components/power-history-chart.js.map +1 -0
  56. package/dist/components/power-network.cjs +559 -0
  57. package/dist/components/power-network.cjs.map +1 -0
  58. package/dist/components/power-network.d.cts +80 -0
  59. package/dist/components/power-network.d.ts +80 -0
  60. package/dist/components/power-network.js +553 -0
  61. package/dist/components/power-network.js.map +1 -0
  62. package/dist/components/sankey-chart.cjs +11 -1
  63. package/dist/components/sankey-chart.cjs.map +1 -1
  64. package/dist/components/sankey-chart.d.cts +3 -2
  65. package/dist/components/sankey-chart.d.ts +3 -2
  66. package/dist/components/sankey-chart.js +11 -2
  67. package/dist/components/sankey-chart.js.map +1 -1
  68. package/dist/components/schedule-list.cjs +1 -1
  69. package/dist/components/schedule-list.js +1 -1
  70. package/dist/components/select.cjs +1 -1
  71. package/dist/components/select.js +1 -1
  72. package/dist/components/sheet.cjs +1 -1
  73. package/dist/components/sheet.js +1 -1
  74. package/dist/components/solar-forecast-chart.cjs +108 -0
  75. package/dist/components/solar-forecast-chart.cjs.map +1 -0
  76. package/dist/components/solar-forecast-chart.d.cts +77 -0
  77. package/dist/components/solar-forecast-chart.d.ts +77 -0
  78. package/dist/components/solar-forecast-chart.js +103 -0
  79. package/dist/components/solar-forecast-chart.js.map +1 -0
  80. package/dist/components/stepper.cjs +1 -1
  81. package/dist/components/stepper.js +1 -1
  82. package/dist/components/table.cjs +1 -1
  83. package/dist/components/table.js +1 -1
  84. package/dist/components/tabs.cjs +1 -1
  85. package/dist/components/tabs.js +1 -1
  86. package/dist/components/toast.cjs +1 -1
  87. package/dist/components/toast.js +1 -1
  88. package/dist/components/tooltip.cjs +1 -1
  89. package/dist/components/tooltip.js +1 -1
  90. package/dist/number-flow-Bch81ixZ.d.cts +14 -0
  91. package/dist/number-flow-Bch81ixZ.d.ts +14 -0
  92. package/dist/utils/build-sankey-nodes.cjs +72 -0
  93. package/dist/utils/build-sankey-nodes.cjs.map +1 -0
  94. package/dist/utils/build-sankey-nodes.d.cts +27 -0
  95. package/dist/utils/build-sankey-nodes.d.ts +27 -0
  96. package/dist/utils/build-sankey-nodes.js +71 -0
  97. package/dist/utils/build-sankey-nodes.js.map +1 -0
  98. package/dist/utils/format.cjs +13 -0
  99. package/dist/utils/format.cjs.map +1 -1
  100. package/dist/utils/format.d.cts +7 -1
  101. package/dist/utils/format.d.ts +7 -1
  102. package/dist/utils/format.js +12 -1
  103. package/dist/utils/format.js.map +1 -1
  104. package/package.json +1 -1
@@ -0,0 +1,498 @@
1
+ "use client";
2
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
+ const require_chunk = require("../chunk-DY84GLCh.cjs");
4
+ const require_hooks_use_chart_zoom = require("../hooks/use-chart-zoom.cjs");
5
+ const require_hooks_use_reduced_motion = require("../hooks/use-reduced-motion.cjs");
6
+ require("../utils/chars.cjs");
7
+ const require_utils_format = require("../utils/format.cjs");
8
+ const require_utils_chart_scale = require("../utils/chart-scale.cjs");
9
+ const require_components_chart = require("./chart.cjs");
10
+ const require_components_series_legend = require("./series-legend.cjs");
11
+ const require_components_typography = require("./typography.cjs");
12
+ const require_utils_chart_time_ticks = require("../utils/chart-time-ticks.cjs");
13
+ let react = require("react");
14
+ react = require_chunk.__toESM(react);
15
+ let react_jsx_runtime = require("react/jsx-runtime");
16
+ let _visx_event = require("@visx/event");
17
+ let _visx_scale = require("@visx/scale");
18
+ let _visx_shape = require("@visx/shape");
19
+ let _visx_curve = require("@visx/curve");
20
+ let _visx_tooltip = require("@visx/tooltip");
21
+ let _visx_vendor_d3_array = require("@visx/vendor/d3-array");
22
+ let cnfast = require("cnfast");
23
+ //#region src/components/power-history-chart.tsx
24
+ const AREA_KEYS = [
25
+ "solar",
26
+ "grid",
27
+ "battery"
28
+ ];
29
+ const SERIES_KEYS = [
30
+ "solar",
31
+ "grid",
32
+ "battery",
33
+ "consumption"
34
+ ];
35
+ const SERIES_COLORS = {
36
+ solar: "var(--orange-a9)",
37
+ grid: "var(--blue-9)",
38
+ battery: "var(--green-a9)",
39
+ consumption: "var(--neutral-12)"
40
+ };
41
+ const PADDING_TOP = 20;
42
+ const PADDING_BOTTOM = 28;
43
+ const PADDING_RIGHT = 8;
44
+ const X_TICK_COUNT = 6;
45
+ const DEFAULT_HEIGHT = 260;
46
+ const DETAILED_X_AXIS_THRESHOLD = 360 * 60 * 1e3;
47
+ const tBisector = (0, _visx_vendor_d3_array.bisector)((d) => d.t);
48
+ function touchDistance(a, b) {
49
+ return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);
50
+ }
51
+ function touchMidpoint(a, b) {
52
+ return {
53
+ clientX: (a.clientX + b.clientX) / 2,
54
+ clientY: (a.clientY + b.clientY) / 2
55
+ };
56
+ }
57
+ /**
58
+ * Diverging "power sources" area chart over a continuous time axis: solar
59
+ * (orange), grid (blue) and battery (green) areas around a zero baseline, with
60
+ * consumption overlaid as a line. Negative values (grid feed-in, battery
61
+ * charging) dip below zero. For instantaneous power (day view). A legend at the
62
+ * top toggles each series on/off; the y-axis rescales to the visible ones. visx.
63
+ */
64
+ function PowerHistoryChart({ data, unit, formatX, formatTooltipX, formatValue, labels, omitSeries, highlightAt, title, className, height = DEFAULT_HEIGHT, zoomable = false, zoomResetLabel, zoomDomain, onZoomDomainChange }) {
65
+ const plotClipId = react.useId();
66
+ const fmtTooltipX = formatTooltipX ?? formatX;
67
+ const containerRef = (0, react.useRef)(null);
68
+ const reducedMotion = require_hooks_use_reduced_motion.useReducedMotion();
69
+ const [width, setWidth] = (0, react.useState)(0);
70
+ const [hiddenSeries, setHiddenSeries] = (0, react.useState)(() => /* @__PURE__ */ new Set());
71
+ const omitted = (0, react.useMemo)(() => new Set(omitSeries), [omitSeries]);
72
+ const toggleSeries = (0, react.useCallback)((id) => {
73
+ setHiddenSeries((prev) => {
74
+ const next = new Set(prev);
75
+ if (next.has(id)) next.delete(id);
76
+ else next.add(id);
77
+ return next;
78
+ });
79
+ }, []);
80
+ const isHidden = (0, react.useCallback)((key) => omitted.has(key) || hiddenSeries.has(key), [hiddenSeries, omitted]);
81
+ const { showTooltip, hideTooltip, tooltipData, tooltipLeft, tooltipTop, tooltipOpen } = (0, _visx_tooltip.useTooltip)();
82
+ (0, react.useEffect)(() => {
83
+ const element = containerRef.current;
84
+ if (!element) return;
85
+ const resizeObserver = new ResizeObserver((entries) => {
86
+ const entry = entries[0];
87
+ if (!entry) return;
88
+ setWidth(entry.contentRect.width);
89
+ });
90
+ resizeObserver.observe(element);
91
+ return () => resizeObserver.disconnect();
92
+ }, []);
93
+ const fmtValue = (value) => formatValue ? formatValue(value) : `${require_utils_format.twoDecimalFormat.format(value)} ${unit}`;
94
+ const tMin = data.length ? data[0]?.t ?? 0 : 0;
95
+ const tMax = data.length ? data[data.length - 1]?.t ?? 0 : 0;
96
+ const zoom = require_hooks_use_chart_zoom.useChartZoom({
97
+ enabled: zoomable,
98
+ fullDomain: (0, react.useMemo)(() => {
99
+ if (data.length === 0) return null;
100
+ return [tMin, tMax];
101
+ }, [
102
+ data.length,
103
+ tMin,
104
+ tMax
105
+ ]),
106
+ zoomDomain,
107
+ onZoomDomainChange
108
+ });
109
+ const viewMin = zoom.zoomWindow?.[0] ?? tMin;
110
+ const viewMax = zoom.zoomWindow?.[1] ?? tMax;
111
+ const visibleData = (0, react.useMemo)(() => data.filter((d) => d.t >= viewMin && d.t <= viewMax), [
112
+ data,
113
+ viewMin,
114
+ viewMax
115
+ ]);
116
+ const { yMin, yMax } = (0, react.useMemo)(() => {
117
+ let min = 0;
118
+ let max = 0;
119
+ for (const d of visibleData) {
120
+ if (!isHidden("solar")) max = Math.max(max, d.solar);
121
+ if (!isHidden("consumption")) max = Math.max(max, d.consumption);
122
+ if (!isHidden("grid")) {
123
+ max = Math.max(max, d.grid);
124
+ min = Math.min(min, d.grid);
125
+ }
126
+ if (!isHidden("battery")) {
127
+ max = Math.max(max, d.battery);
128
+ min = Math.min(min, d.battery);
129
+ }
130
+ }
131
+ return {
132
+ yMin: min,
133
+ yMax: max
134
+ };
135
+ }, [visibleData, isHidden]);
136
+ const { ticks: yTicks, min: lo, max: hi } = (0, react.useMemo)(() => require_utils_chart_scale.buildYAxisScale(yMin, yMax), [yMin, yMax]);
137
+ const displayedYDomain = require_hooks_use_chart_zoom.useAnimatedChartDomain([lo, hi], {
138
+ animateChanges: zoom.isPinching,
139
+ reducedMotion
140
+ });
141
+ const gutter = (0, react.useMemo)(() => require_utils_chart_scale.measureYAxisGutter(yTicks, require_utils_chart_scale.formatYAxisTick), [yTicks]);
142
+ const plotRight = Math.max(gutter, width - PADDING_RIGHT);
143
+ const xScale = (0, react.useMemo)(() => (0, _visx_scale.scaleLinear)({
144
+ domain: [viewMin, viewMax === viewMin ? viewMin + 1 : viewMax],
145
+ range: [gutter, plotRight]
146
+ }), [
147
+ viewMin,
148
+ viewMax,
149
+ plotRight,
150
+ gutter
151
+ ]);
152
+ const plotHeight = Math.max(0, height - PADDING_BOTTOM - PADDING_TOP);
153
+ const plotWidth = Math.max(0, plotRight - gutter);
154
+ const yScale = (0, react.useMemo)(() => (0, _visx_scale.scaleLinear)({
155
+ domain: [displayedYDomain[0], displayedYDomain[1] === displayedYDomain[0] ? displayedYDomain[0] + 1 : displayedYDomain[1]],
156
+ range: [height - PADDING_BOTTOM, PADDING_TOP]
157
+ }), [displayedYDomain, height]);
158
+ const xTicks = (0, react.useMemo)(() => require_utils_chart_time_ticks.buildTimeTicks(viewMin, viewMax, X_TICK_COUNT), [viewMin, viewMax]);
159
+ const formatAxisX = zoom.isZoomed && viewMax - viewMin <= DETAILED_X_AXIS_THRESHOLD ? fmtTooltipX : formatX;
160
+ const domainXFromEvent = (0, react.useCallback)((event) => {
161
+ const point = (0, _visx_event.localPoint)(event);
162
+ if (!point) return null;
163
+ return xScale.invert(point.x);
164
+ }, [xScale]);
165
+ const handleTooltip = (0, react.useCallback)((event) => {
166
+ if (zoom.isBrushing || zoom.isPanning) return;
167
+ const point = (0, _visx_event.localPoint)(event);
168
+ if (!point || data.length === 0) return;
169
+ const xMs = xScale.invert(point.x);
170
+ const index = tBisector.left(data, xMs, 1);
171
+ const d0 = data[index - 1];
172
+ const d1 = data[index];
173
+ if (!d0) return;
174
+ const d = d1 && xMs - d0.t > d1.t - xMs ? d1 : d0;
175
+ showTooltip({
176
+ tooltipData: d,
177
+ tooltipLeft: xScale(d.t),
178
+ tooltipTop: PADDING_TOP
179
+ });
180
+ }, [
181
+ data,
182
+ showTooltip,
183
+ xScale,
184
+ zoom.isBrushing,
185
+ zoom.isPanning
186
+ ]);
187
+ const legendItems = SERIES_KEYS.filter((key) => !omitted.has(key)).map((key) => ({
188
+ id: key,
189
+ label: labels[key],
190
+ color: SERIES_COLORS[key]
191
+ }));
192
+ const tooltipRows = tooltipData ? SERIES_KEYS.filter((key) => !isHidden(key)).map((key) => ({
193
+ key,
194
+ label: labels[key],
195
+ color: SERIES_COLORS[key],
196
+ value: fmtValue(tooltipData[key])
197
+ })) : [];
198
+ const showHighlight = highlightAt !== void 0 && highlightAt >= viewMin && highlightAt <= viewMax;
199
+ const [tooltipRef, tooltipSize] = require_components_chart.useMeasuredSize();
200
+ const tooltipPos = require_components_chart.clampTooltipPosition({
201
+ anchorX: tooltipLeft ?? 0,
202
+ anchorY: tooltipTop ?? PADDING_TOP,
203
+ width,
204
+ height,
205
+ tipWidth: tooltipSize.width,
206
+ tipHeight: tooltipSize.height,
207
+ placement: "beside"
208
+ });
209
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
210
+ className: (0, cnfast.cn)("flex w-full flex-col gap-2", className),
211
+ children: [
212
+ title && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_typography.SectionTitle, { children: title }),
213
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_series_legend.SeriesLegend, {
214
+ items: legendItems,
215
+ hiddenIds: hiddenSeries,
216
+ onToggle: toggleSeries
217
+ }),
218
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
219
+ className: "px-1 text-xs text-gray-light",
220
+ children: unit
221
+ }),
222
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
223
+ ref: containerRef,
224
+ className: "relative w-full",
225
+ style: { height },
226
+ children: [
227
+ width > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
228
+ width,
229
+ height,
230
+ children: [
231
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("defs", { children: [AREA_KEYS.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("linearGradient", {
232
+ id: `power-history-fill-${key}`,
233
+ x1: "0",
234
+ y1: "0",
235
+ x2: "0",
236
+ y2: "1",
237
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
238
+ offset: "0%",
239
+ stopColor: SERIES_COLORS[key],
240
+ stopOpacity: .35
241
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("stop", {
242
+ offset: "100%",
243
+ stopColor: SERIES_COLORS[key],
244
+ stopOpacity: .04
245
+ })]
246
+ }, key)), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("clipPath", {
247
+ id: plotClipId,
248
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
249
+ height: plotHeight,
250
+ width: plotWidth,
251
+ x: gutter,
252
+ y: PADDING_TOP
253
+ })
254
+ })] }),
255
+ yTicks.map((tick) => {
256
+ const y = yScale(tick);
257
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
258
+ x1: gutter,
259
+ x2: plotRight,
260
+ y1: y,
261
+ y2: y,
262
+ stroke: "var(--neutral-a4)",
263
+ strokeWidth: 1
264
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
265
+ x: gutter - 7,
266
+ y: y + 3,
267
+ textAnchor: "end",
268
+ fill: "var(--neutral-a11)",
269
+ fontSize: 10,
270
+ children: require_utils_chart_scale.formatYAxisTick(tick)
271
+ })] }, `y-tick-${tick}`);
272
+ }),
273
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("g", {
274
+ clipPath: `url(#${plotClipId})`,
275
+ "data-testid": "chart-plot-clip",
276
+ children: [
277
+ AREA_KEYS.filter((key) => !isHidden(key)).map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_shape.Area, {
278
+ data,
279
+ x: (d) => xScale(d.t),
280
+ y0: yScale(0),
281
+ y1: (d) => yScale(d[key]),
282
+ curve: _visx_curve.curveMonotoneX,
283
+ fill: `url(#power-history-fill-${key})`,
284
+ stroke: "transparent"
285
+ }, `area-${key}`)),
286
+ AREA_KEYS.filter((key) => !isHidden(key)).map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_shape.LinePath, {
287
+ data,
288
+ x: (d) => xScale(d.t),
289
+ y: (d) => yScale(d[key]),
290
+ curve: _visx_curve.curveMonotoneX,
291
+ stroke: SERIES_COLORS[key],
292
+ strokeWidth: 1.5,
293
+ fill: "none"
294
+ }, `line-${key}`)),
295
+ !isHidden("consumption") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_visx_shape.LinePath, {
296
+ data,
297
+ x: (d) => xScale(d.t),
298
+ y: (d) => yScale(d.consumption),
299
+ curve: _visx_curve.curveMonotoneX,
300
+ stroke: SERIES_COLORS.consumption,
301
+ strokeWidth: 1.5,
302
+ fill: "none"
303
+ })
304
+ ]
305
+ }),
306
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
307
+ x1: gutter,
308
+ x2: plotRight,
309
+ y1: yScale(0),
310
+ y2: yScale(0),
311
+ stroke: "var(--neutral-a6)",
312
+ strokeWidth: 1
313
+ }),
314
+ showHighlight && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
315
+ x1: xScale(highlightAt),
316
+ x2: xScale(highlightAt),
317
+ y1: PADDING_TOP,
318
+ y2: height - PADDING_BOTTOM,
319
+ stroke: "var(--spark-a9)",
320
+ strokeWidth: 1.5,
321
+ strokeDasharray: "5 4",
322
+ pointerEvents: "none"
323
+ }),
324
+ xTicks.map((tick, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("text", {
325
+ x: xScale(tick),
326
+ y: height - PADDING_BOTTOM + 16,
327
+ textAnchor: index === 0 ? "start" : index === xTicks.length - 1 ? "end" : "middle",
328
+ fill: "var(--neutral-a11)",
329
+ fontSize: 10,
330
+ children: formatAxisX(tick)
331
+ }, `x-tick-${tick}`)),
332
+ tooltipOpen && tooltipData && !zoom.isBrushing && !zoom.isPanning && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
333
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("line", {
334
+ x1: xScale(tooltipData.t),
335
+ x2: xScale(tooltipData.t),
336
+ y1: PADDING_TOP,
337
+ y2: height - PADDING_BOTTOM,
338
+ stroke: "var(--neutral-a6)",
339
+ strokeDasharray: "4 4",
340
+ pointerEvents: "none"
341
+ }),
342
+ AREA_KEYS.filter((key) => !isHidden(key)).map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
343
+ cx: xScale(tooltipData.t),
344
+ cy: yScale(tooltipData[key]),
345
+ r: 3.5,
346
+ fill: SERIES_COLORS[key],
347
+ stroke: "white",
348
+ strokeWidth: 1.5,
349
+ pointerEvents: "none"
350
+ }, `dot-${key}`)),
351
+ !isHidden("consumption") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
352
+ cx: xScale(tooltipData.t),
353
+ cy: yScale(tooltipData.consumption),
354
+ r: 3.5,
355
+ fill: SERIES_COLORS.consumption,
356
+ stroke: "white",
357
+ strokeWidth: 1.5,
358
+ pointerEvents: "none"
359
+ })
360
+ ] }),
361
+ zoom.brushBand && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
362
+ "data-testid": "chart-brush-band",
363
+ x: Math.min(xScale(zoom.brushBand[0]), xScale(zoom.brushBand[1])),
364
+ y: PADDING_TOP,
365
+ width: Math.abs(xScale(zoom.brushBand[1]) - xScale(zoom.brushBand[0])),
366
+ height: plotHeight,
367
+ fill: "var(--spark-a4)",
368
+ pointerEvents: "none"
369
+ }),
370
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
371
+ x: gutter,
372
+ y: PADDING_TOP,
373
+ width: plotWidth,
374
+ height: plotHeight,
375
+ fill: "transparent",
376
+ style: zoomable ? { touchAction: "pan-y" } : void 0,
377
+ onMouseLeave: () => {
378
+ if (!zoom.isBrushing) hideTooltip();
379
+ },
380
+ onMouseMove: (event) => {
381
+ if (zoom.isBrushing) {
382
+ const domainX = domainXFromEvent(event);
383
+ if (domainX != null) zoom.onPointerMove(domainX);
384
+ return;
385
+ }
386
+ handleTooltip(event);
387
+ },
388
+ onPointerDown: (event) => {
389
+ if (!zoomable || event.pointerType === "touch") return;
390
+ if (event.button !== 0) return;
391
+ const domainX = domainXFromEvent(event);
392
+ if (domainX == null) return;
393
+ event.currentTarget.setPointerCapture?.(event.pointerId);
394
+ hideTooltip();
395
+ zoom.onPointerDown(domainX);
396
+ },
397
+ onPointerMove: (event) => {
398
+ if (!zoomable) return;
399
+ const domainX = domainXFromEvent(event);
400
+ if (domainX != null) zoom.onPointerMove(domainX);
401
+ },
402
+ onPointerUp: (event) => {
403
+ if (!zoomable) return;
404
+ const domainX = domainXFromEvent(event);
405
+ if (domainX != null) zoom.onPointerUp(domainX);
406
+ else zoom.onPointerCancel();
407
+ },
408
+ onPointerCancel: () => {
409
+ zoom.onPointerCancel();
410
+ },
411
+ onDoubleClick: () => {
412
+ if (zoomable) zoom.onDoubleClick();
413
+ },
414
+ onTouchStart: (event) => {
415
+ if (!zoomable) return;
416
+ if (event.touches.length === 2) {
417
+ const [a, b] = [event.touches[0], event.touches[1]];
418
+ if (!a || !b) return;
419
+ const point = (0, _visx_event.localPoint)(event.currentTarget, touchMidpoint(a, b));
420
+ if (!point) return;
421
+ const midpoint = Math.min(1, Math.max(0, (point.x - gutter) / plotWidth));
422
+ zoom.onPinchStart(touchDistance(a, b), midpoint);
423
+ hideTooltip();
424
+ return;
425
+ }
426
+ if (event.touches.length === 1 && zoom.isZoomed) {
427
+ const point = (0, _visx_event.localPoint)(event);
428
+ if (!point) return;
429
+ zoom.onPanStart({
430
+ x: (point.x - gutter) / plotWidth,
431
+ y: (point.y - PADDING_TOP) / plotHeight
432
+ });
433
+ hideTooltip();
434
+ }
435
+ },
436
+ onTouchMove: (event) => {
437
+ if (zoomable && event.touches.length === 2) {
438
+ const [a, b] = [event.touches[0], event.touches[1]];
439
+ if (!a || !b) return;
440
+ const point = (0, _visx_event.localPoint)(event.currentTarget, touchMidpoint(a, b));
441
+ if (!point) return;
442
+ const midpoint = Math.min(1, Math.max(0, (point.x - gutter) / plotWidth));
443
+ zoom.onPinchMove(touchDistance(a, b), midpoint);
444
+ return;
445
+ }
446
+ if (event.touches.length === 1 && zoom.isZoomed) {
447
+ const point = (0, _visx_event.localPoint)(event);
448
+ if (!point) return;
449
+ zoom.onPanMove({
450
+ x: (point.x - gutter) / plotWidth,
451
+ y: (point.y - PADDING_TOP) / plotHeight
452
+ });
453
+ return;
454
+ }
455
+ if (event.touches.length === 1) handleTooltip(event);
456
+ },
457
+ onTouchEnd: (event) => {
458
+ if (zoomable && event.touches.length < 2) zoom.onPinchEnd();
459
+ if (event.touches.length === 0) {
460
+ if (zoomable) zoom.onPanEnd();
461
+ if (zoomable) zoom.onTap();
462
+ hideTooltip();
463
+ }
464
+ },
465
+ onTouchCancel: () => {
466
+ zoom.onPinchEnd();
467
+ zoom.onPanEnd();
468
+ }
469
+ })
470
+ ]
471
+ }),
472
+ zoom.isZoomed && zoomResetLabel && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_chart.ChartZoomResetButton, {
473
+ label: zoomResetLabel,
474
+ onReset: zoom.resetZoom
475
+ }),
476
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
477
+ ref: tooltipRef,
478
+ className: "pointer-events-none absolute z-10",
479
+ style: {
480
+ left: tooltipPos.left,
481
+ top: tooltipPos.top,
482
+ opacity: tooltipOpen && tooltipData && !zoom.isPanning && !zoom.isBrushing ? 1 : 0,
483
+ transition: reducedMotion ? "opacity 140ms ease-out" : "left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out"
484
+ },
485
+ children: tooltipData && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_components_chart.ChartTooltipCard, {
486
+ label: fmtTooltipX(tooltipData.t),
487
+ rows: tooltipRows
488
+ })
489
+ })
490
+ ]
491
+ })
492
+ ]
493
+ });
494
+ }
495
+ //#endregion
496
+ exports.PowerHistoryChart = PowerHistoryChart;
497
+
498
+ //# sourceMappingURL=power-history-chart.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"power-history-chart.cjs","names":["React","useReducedMotion","valueFormat","useChartZoom","buildYAxisScale","useAnimatedChartDomain","measureYAxisGutter","formatYAxisTick","buildTimeTicks","useMeasuredSize","clampTooltipPosition","SectionTitle","SeriesLegend","Area","curveMonotoneX","LinePath","ChartZoomResetButton","ChartTooltipCard"],"sources":["../../src/components/power-history-chart.tsx"],"sourcesContent":["import { curveMonotoneX } from '@visx/curve'\nimport { localPoint } from '@visx/event'\nimport { scaleLinear } from '@visx/scale'\nimport { Area, LinePath } from '@visx/shape'\nimport { useTooltip } from '@visx/tooltip'\nimport { bisector } from '@visx/vendor/d3-array'\nimport * as React from 'react'\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react'\nimport { useAnimatedChartDomain, useChartZoom } from '../hooks/use-chart-zoom'\nimport { useReducedMotion } from '../hooks/use-reduced-motion'\nimport { NARROW_NBSP } from '../utils/chars'\nimport {\n buildYAxisScale,\n formatYAxisTick,\n measureYAxisGutter,\n} from '../utils/chart-scale'\nimport { buildTimeTicks } from '../utils/chart-time-ticks'\nimport type { TimeDomain } from '../utils/chart-zoom'\nimport { cn } from '../utils/cn'\nimport { twoDecimalFormat as valueFormat } from '../utils/format'\nimport {\n ChartTooltipCard,\n type ChartTooltipRow,\n ChartZoomResetButton,\n clampTooltipPosition,\n useMeasuredSize,\n} from './chart'\nimport { SeriesLegend, type SeriesLegendItem } from './series-legend'\nimport { SectionTitle } from './typography'\n\nexport interface PowerHistoryPoint {\n /** Epoch milliseconds. */\n t: number\n solar: number\n /** Signed: positive = import, negative = feed-in. */\n grid: number\n /** Signed: positive = discharge, negative = charge. */\n battery: number\n consumption: number\n}\n\nexport interface PowerHistoryChartProps {\n data: PowerHistoryPoint[]\n /** Axis/tooltip unit, e.g. \"kW\". */\n unit: string\n formatX: (t: number) => string\n /** Tooltip time formatter. Defaults to `formatX`; use to keep the tooltip's\n * full clock time when the axis ticks are compact (hour-only). */\n formatTooltipX?: (t: number) => string\n formatValue?: (value: number) => string\n labels: {\n solar: string\n grid: string\n battery: string\n consumption: string\n }\n /** Series to drop entirely (no legend entry, area, or tooltip row). */\n omitSeries?: readonly PowerHistorySeriesKey[]\n /** Epoch ms to mark with the current-time dashed line (omit to hide). */\n highlightAt?: number\n title?: string\n className?: string\n height?: number\n zoomable?: boolean\n zoomResetLabel?: string\n zoomDomain?: TimeDomain | null\n onZoomDomainChange?: (domain: TimeDomain | null) => void\n}\n\nconst AREA_KEYS = ['solar', 'grid', 'battery'] as const\n\n// All toggleable series, in legend order. The areas (solar/grid/battery) plus\n// the consumption overlay line.\nconst SERIES_KEYS = ['solar', 'grid', 'battery', 'consumption'] as const\nexport type PowerHistorySeriesKey = (typeof SERIES_KEYS)[number]\ntype SeriesKey = PowerHistorySeriesKey\n\nconst SERIES_COLORS = {\n solar: 'var(--orange-a9)',\n grid: 'var(--blue-9)',\n battery: 'var(--green-a9)',\n consumption: 'var(--neutral-12)',\n} as const\n\nconst PADDING_TOP = 20\nconst PADDING_BOTTOM = 28\nconst PADDING_RIGHT = 8\nconst X_TICK_COUNT = 6\nconst DEFAULT_HEIGHT = 260\nconst DETAILED_X_AXIS_THRESHOLD = 6 * 60 * 60 * 1000\n\nconst tBisector = bisector<PowerHistoryPoint, number>((d) => d.t)\n\nfunction touchDistance(a: React.Touch, b: React.Touch): number {\n return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY)\n}\n\nfunction touchMidpoint(\n a: React.Touch,\n b: React.Touch,\n): {\n clientX: number\n clientY: number\n} {\n return {\n clientX: (a.clientX + b.clientX) / 2,\n clientY: (a.clientY + b.clientY) / 2,\n }\n}\n\n/**\n * Diverging \"power sources\" area chart over a continuous time axis: solar\n * (orange), grid (blue) and battery (green) areas around a zero baseline, with\n * consumption overlaid as a line. Negative values (grid feed-in, battery\n * charging) dip below zero. For instantaneous power (day view). A legend at the\n * top toggles each series on/off; the y-axis rescales to the visible ones. visx.\n */\nexport function PowerHistoryChart({\n data,\n unit,\n formatX,\n formatTooltipX,\n formatValue,\n labels,\n omitSeries,\n highlightAt,\n title,\n className,\n height = DEFAULT_HEIGHT,\n zoomable = false,\n zoomResetLabel,\n zoomDomain,\n onZoomDomainChange,\n}: PowerHistoryChartProps) {\n const plotClipId = React.useId()\n const fmtTooltipX = formatTooltipX ?? formatX\n const containerRef = useRef<HTMLDivElement>(null)\n const reducedMotion = useReducedMotion()\n const [width, setWidth] = useState(0)\n const [hiddenSeries, setHiddenSeries] = useState<ReadonlySet<string>>(\n () => new Set(),\n )\n const omitted = useMemo(() => new Set<SeriesKey>(omitSeries), [omitSeries])\n\n const toggleSeries = useCallback((id: string) => {\n setHiddenSeries((prev) => {\n const next = new Set(prev)\n if (next.has(id)) {\n next.delete(id)\n } else {\n next.add(id)\n }\n return next\n })\n }, [])\n\n const isHidden = useCallback(\n (key: SeriesKey) => omitted.has(key) || hiddenSeries.has(key),\n [hiddenSeries, omitted],\n )\n\n const {\n showTooltip,\n hideTooltip,\n tooltipData,\n tooltipLeft,\n tooltipTop,\n tooltipOpen,\n } = useTooltip<PowerHistoryPoint>()\n\n useEffect(() => {\n const element = containerRef.current\n if (!element) return\n\n const resizeObserver = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (!entry) return\n setWidth(entry.contentRect.width)\n })\n\n resizeObserver.observe(element)\n return () => resizeObserver.disconnect()\n }, [])\n\n const fmtValue = (value: number) =>\n formatValue\n ? formatValue(value)\n : `${valueFormat.format(value)}${NARROW_NBSP}${unit}`\n\n const tMin = data.length ? (data[0]?.t ?? 0) : 0\n const tMax = data.length ? (data[data.length - 1]?.t ?? 0) : 0\n const fullDomain = useMemo((): TimeDomain | null => {\n if (data.length === 0) return null\n return [tMin, tMax]\n }, [data.length, tMin, tMax])\n\n const zoom = useChartZoom({\n enabled: zoomable,\n fullDomain,\n zoomDomain,\n onZoomDomainChange,\n })\n\n const viewMin = zoom.zoomWindow?.[0] ?? tMin\n const viewMax = zoom.zoomWindow?.[1] ?? tMax\n\n const visibleData = useMemo(\n () => data.filter((d) => d.t >= viewMin && d.t <= viewMax),\n [data, viewMin, viewMax],\n )\n\n const { yMin, yMax } = useMemo(() => {\n let min = 0\n let max = 0\n for (const d of visibleData) {\n if (!isHidden('solar')) max = Math.max(max, d.solar)\n if (!isHidden('consumption')) max = Math.max(max, d.consumption)\n if (!isHidden('grid')) {\n max = Math.max(max, d.grid)\n min = Math.min(min, d.grid)\n }\n if (!isHidden('battery')) {\n max = Math.max(max, d.battery)\n min = Math.min(min, d.battery)\n }\n }\n return { yMin: min, yMax: max }\n }, [visibleData, isHidden])\n\n const {\n ticks: yTicks,\n min: lo,\n max: hi,\n } = useMemo(() => buildYAxisScale(yMin, yMax), [yMin, yMax])\n const displayedYDomain = useAnimatedChartDomain([lo, hi], {\n animateChanges: zoom.isPinching,\n reducedMotion,\n })\n\n const gutter = useMemo(\n () => measureYAxisGutter(yTicks, formatYAxisTick),\n [yTicks],\n )\n\n const plotRight = Math.max(gutter, width - PADDING_RIGHT)\n\n const xScale = useMemo(\n () =>\n scaleLinear<number>({\n domain: [viewMin, viewMax === viewMin ? viewMin + 1 : viewMax],\n range: [gutter, plotRight],\n }),\n [viewMin, viewMax, plotRight, gutter],\n )\n\n const plotHeight = Math.max(0, height - PADDING_BOTTOM - PADDING_TOP)\n const plotWidth = Math.max(0, plotRight - gutter)\n\n const yScale = useMemo(\n () =>\n scaleLinear<number>({\n domain: [\n displayedYDomain[0],\n displayedYDomain[1] === displayedYDomain[0]\n ? displayedYDomain[0] + 1\n : displayedYDomain[1],\n ],\n range: [height - PADDING_BOTTOM, PADDING_TOP],\n }),\n [displayedYDomain, height],\n )\n\n const xTicks = useMemo(\n () => buildTimeTicks(viewMin, viewMax, X_TICK_COUNT),\n [viewMin, viewMax],\n )\n const formatAxisX =\n zoom.isZoomed && viewMax - viewMin <= DETAILED_X_AXIS_THRESHOLD\n ? fmtTooltipX\n : formatX\n\n const domainXFromEvent = useCallback(\n (\n event:\n | React.MouseEvent<SVGRectElement>\n | React.PointerEvent<SVGRectElement>\n | React.TouchEvent<SVGRectElement>,\n ) => {\n const point = localPoint(event)\n if (!point) return null\n return xScale.invert(point.x)\n },\n [xScale],\n )\n\n const handleTooltip = useCallback(\n (\n event:\n | React.TouchEvent<SVGRectElement>\n | React.MouseEvent<SVGRectElement>,\n ) => {\n if (zoom.isBrushing || zoom.isPanning) return\n const point = localPoint(event)\n if (!point || data.length === 0) return\n\n const xMs = xScale.invert(point.x)\n const index = tBisector.left(data, xMs, 1)\n const d0 = data[index - 1]\n const d1 = data[index]\n if (!d0) return\n\n const d = d1 && xMs - d0.t > d1.t - xMs ? d1 : d0\n showTooltip({\n tooltipData: d,\n tooltipLeft: xScale(d.t),\n tooltipTop: PADDING_TOP,\n })\n },\n [data, showTooltip, xScale, zoom.isBrushing, zoom.isPanning],\n )\n\n const legendItems: SeriesLegendItem[] = SERIES_KEYS.filter(\n (key) => !omitted.has(key),\n ).map((key) => ({\n id: key,\n label: labels[key],\n color: SERIES_COLORS[key],\n }))\n\n const tooltipRows: ChartTooltipRow[] = tooltipData\n ? SERIES_KEYS.filter((key) => !isHidden(key)).map((key) => ({\n key,\n label: labels[key],\n color: SERIES_COLORS[key],\n value: fmtValue(tooltipData[key]),\n }))\n : []\n\n const showHighlight =\n highlightAt !== undefined &&\n highlightAt >= viewMin &&\n highlightAt <= viewMax\n\n const [tooltipRef, tooltipSize] = useMeasuredSize<HTMLDivElement>()\n const tooltipPos = clampTooltipPosition({\n anchorX: tooltipLeft ?? 0,\n anchorY: tooltipTop ?? PADDING_TOP,\n width,\n height,\n tipWidth: tooltipSize.width,\n tipHeight: tooltipSize.height,\n placement: 'beside',\n })\n\n return (\n <div className={cn('flex w-full flex-col gap-2', className)}>\n {title && <SectionTitle>{title}</SectionTitle>}\n <SeriesLegend\n items={legendItems}\n hiddenIds={hiddenSeries}\n onToggle={toggleSeries}\n />\n <span className=\"px-1 text-xs text-gray-light\">{unit}</span>\n <div ref={containerRef} className=\"relative w-full\" style={{ height }}>\n {width > 0 && (\n <svg width={width} height={height}>\n <defs>\n {AREA_KEYS.map((key) => (\n <linearGradient\n key={key}\n id={`power-history-fill-${key}`}\n x1=\"0\"\n y1=\"0\"\n x2=\"0\"\n y2=\"1\"\n >\n <stop\n offset=\"0%\"\n stopColor={SERIES_COLORS[key]}\n stopOpacity={0.35}\n />\n <stop\n offset=\"100%\"\n stopColor={SERIES_COLORS[key]}\n stopOpacity={0.04}\n />\n </linearGradient>\n ))}\n <clipPath id={plotClipId}>\n <rect\n height={plotHeight}\n width={plotWidth}\n x={gutter}\n y={PADDING_TOP}\n />\n </clipPath>\n </defs>\n\n {yTicks.map((tick) => {\n const y = yScale(tick)\n return (\n <g key={`y-tick-${tick}`}>\n <line\n x1={gutter}\n x2={plotRight}\n y1={y}\n y2={y}\n stroke=\"var(--neutral-a4)\"\n strokeWidth={1}\n />\n <text\n x={gutter - 7}\n y={y + 3}\n textAnchor=\"end\"\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n >\n {formatYAxisTick(tick)}\n </text>\n </g>\n )\n })}\n\n <g clipPath={`url(#${plotClipId})`} data-testid=\"chart-plot-clip\">\n {AREA_KEYS.filter((key) => !isHidden(key)).map((key) => (\n <Area<PowerHistoryPoint>\n key={`area-${key}`}\n data={data}\n x={(d) => xScale(d.t)}\n y0={yScale(0)}\n y1={(d) => yScale(d[key])}\n curve={curveMonotoneX}\n fill={`url(#power-history-fill-${key})`}\n stroke=\"transparent\"\n />\n ))}\n\n {AREA_KEYS.filter((key) => !isHidden(key)).map((key) => (\n <LinePath<PowerHistoryPoint>\n key={`line-${key}`}\n data={data}\n x={(d) => xScale(d.t)}\n y={(d) => yScale(d[key])}\n curve={curveMonotoneX}\n stroke={SERIES_COLORS[key]}\n strokeWidth={1.5}\n fill=\"none\"\n />\n ))}\n\n {!isHidden('consumption') && (\n <LinePath<PowerHistoryPoint>\n data={data}\n x={(d) => xScale(d.t)}\n y={(d) => yScale(d.consumption)}\n curve={curveMonotoneX}\n stroke={SERIES_COLORS.consumption}\n strokeWidth={1.5}\n fill=\"none\"\n />\n )}\n </g>\n\n <line\n x1={gutter}\n x2={plotRight}\n y1={yScale(0)}\n y2={yScale(0)}\n stroke=\"var(--neutral-a6)\"\n strokeWidth={1}\n />\n\n {showHighlight && (\n <line\n x1={xScale(highlightAt)}\n x2={xScale(highlightAt)}\n y1={PADDING_TOP}\n y2={height - PADDING_BOTTOM}\n stroke=\"var(--spark-a9)\"\n strokeWidth={1.5}\n strokeDasharray=\"5 4\"\n pointerEvents=\"none\"\n />\n )}\n\n {xTicks.map((tick, index) => (\n <text\n key={`x-tick-${tick}`}\n x={xScale(tick)}\n y={height - PADDING_BOTTOM + 16}\n textAnchor={\n index === 0\n ? 'start'\n : index === xTicks.length - 1\n ? 'end'\n : 'middle'\n }\n fill=\"var(--neutral-a11)\"\n fontSize={10}\n >\n {formatAxisX(tick)}\n </text>\n ))}\n\n {tooltipOpen &&\n tooltipData &&\n !zoom.isBrushing &&\n !zoom.isPanning && (\n <>\n <line\n x1={xScale(tooltipData.t)}\n x2={xScale(tooltipData.t)}\n y1={PADDING_TOP}\n y2={height - PADDING_BOTTOM}\n stroke=\"var(--neutral-a6)\"\n strokeDasharray=\"4 4\"\n pointerEvents=\"none\"\n />\n {AREA_KEYS.filter((key) => !isHidden(key)).map((key) => (\n <circle\n key={`dot-${key}`}\n cx={xScale(tooltipData.t)}\n cy={yScale(tooltipData[key])}\n r={3.5}\n fill={SERIES_COLORS[key]}\n stroke=\"white\"\n strokeWidth={1.5}\n pointerEvents=\"none\"\n />\n ))}\n {!isHidden('consumption') && (\n <circle\n cx={xScale(tooltipData.t)}\n cy={yScale(tooltipData.consumption)}\n r={3.5}\n fill={SERIES_COLORS.consumption}\n stroke=\"white\"\n strokeWidth={1.5}\n pointerEvents=\"none\"\n />\n )}\n </>\n )}\n\n {zoom.brushBand && (\n <rect\n data-testid=\"chart-brush-band\"\n x={Math.min(\n xScale(zoom.brushBand[0]),\n xScale(zoom.brushBand[1]),\n )}\n y={PADDING_TOP}\n width={Math.abs(\n xScale(zoom.brushBand[1]) - xScale(zoom.brushBand[0]),\n )}\n height={plotHeight}\n fill=\"var(--spark-a4)\"\n pointerEvents=\"none\"\n />\n )}\n\n <rect\n x={gutter}\n y={PADDING_TOP}\n width={plotWidth}\n height={plotHeight}\n fill=\"transparent\"\n style={zoomable ? { touchAction: 'pan-y' } : undefined}\n onMouseLeave={() => {\n if (!zoom.isBrushing) hideTooltip()\n }}\n onMouseMove={(event) => {\n if (zoom.isBrushing) {\n const domainX = domainXFromEvent(event)\n if (domainX != null) zoom.onPointerMove(domainX)\n return\n }\n handleTooltip(event)\n }}\n onPointerDown={(event) => {\n if (!zoomable || event.pointerType === 'touch') return\n if (event.button !== 0) return\n const domainX = domainXFromEvent(event)\n if (domainX == null) return\n event.currentTarget.setPointerCapture?.(event.pointerId)\n hideTooltip()\n zoom.onPointerDown(domainX)\n }}\n onPointerMove={(event) => {\n if (!zoomable) return\n const domainX = domainXFromEvent(event)\n if (domainX != null) zoom.onPointerMove(domainX)\n }}\n onPointerUp={(event) => {\n if (!zoomable) return\n const domainX = domainXFromEvent(event)\n if (domainX != null) zoom.onPointerUp(domainX)\n else zoom.onPointerCancel()\n }}\n onPointerCancel={() => {\n zoom.onPointerCancel()\n }}\n onDoubleClick={() => {\n if (zoomable) zoom.onDoubleClick()\n }}\n onTouchStart={(event) => {\n if (!zoomable) return\n if (event.touches.length === 2) {\n const [a, b] = [event.touches[0], event.touches[1]]\n if (!a || !b) return\n const point = localPoint(\n event.currentTarget,\n touchMidpoint(a, b) as MouseEvent,\n )\n if (!point) return\n const midpoint = Math.min(\n 1,\n Math.max(0, (point.x - gutter) / plotWidth),\n )\n zoom.onPinchStart(touchDistance(a, b), midpoint)\n hideTooltip()\n return\n }\n if (event.touches.length === 1 && zoom.isZoomed) {\n const point = localPoint(event)\n if (!point) return\n zoom.onPanStart({\n x: (point.x - gutter) / plotWidth,\n y: (point.y - PADDING_TOP) / plotHeight,\n })\n hideTooltip()\n }\n }}\n onTouchMove={(event) => {\n if (zoomable && event.touches.length === 2) {\n const [a, b] = [event.touches[0], event.touches[1]]\n if (!a || !b) return\n const point = localPoint(\n event.currentTarget,\n touchMidpoint(a, b) as MouseEvent,\n )\n if (!point) return\n const midpoint = Math.min(\n 1,\n Math.max(0, (point.x - gutter) / plotWidth),\n )\n zoom.onPinchMove(touchDistance(a, b), midpoint)\n return\n }\n if (event.touches.length === 1 && zoom.isZoomed) {\n const point = localPoint(event)\n if (!point) return\n zoom.onPanMove({\n x: (point.x - gutter) / plotWidth,\n y: (point.y - PADDING_TOP) / plotHeight,\n })\n return\n }\n if (event.touches.length === 1) handleTooltip(event)\n }}\n onTouchEnd={(event) => {\n if (zoomable && event.touches.length < 2) zoom.onPinchEnd()\n if (event.touches.length === 0) {\n if (zoomable) zoom.onPanEnd()\n if (zoomable) zoom.onTap()\n hideTooltip()\n }\n }}\n onTouchCancel={() => {\n zoom.onPinchEnd()\n zoom.onPanEnd()\n }}\n />\n </svg>\n )}\n\n {zoom.isZoomed && zoomResetLabel && (\n <ChartZoomResetButton\n label={zoomResetLabel}\n onReset={zoom.resetZoom}\n />\n )}\n\n <div\n ref={tooltipRef}\n className=\"pointer-events-none absolute z-10\"\n style={{\n left: tooltipPos.left,\n top: tooltipPos.top,\n opacity:\n tooltipOpen && tooltipData && !zoom.isPanning && !zoom.isBrushing\n ? 1\n : 0,\n transition: reducedMotion\n ? 'opacity 140ms ease-out'\n : 'left 140ms ease-out, top 140ms ease-out, opacity 140ms ease-out',\n }}\n >\n {tooltipData && (\n <ChartTooltipCard\n label={fmtTooltipX(tooltipData.t)}\n rows={tooltipRows}\n />\n )}\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ "use client";
2
+
3
+ import { TimeDomain } from "../utils/chart-zoom.cjs";
4
+
5
+ //#region src/components/power-history-chart.d.ts
6
+ interface PowerHistoryPoint {
7
+ /** Epoch milliseconds. */
8
+ t: number;
9
+ solar: number;
10
+ /** Signed: positive = import, negative = feed-in. */
11
+ grid: number;
12
+ /** Signed: positive = discharge, negative = charge. */
13
+ battery: number;
14
+ consumption: number;
15
+ }
16
+ interface PowerHistoryChartProps {
17
+ data: PowerHistoryPoint[];
18
+ /** Axis/tooltip unit, e.g. "kW". */
19
+ unit: string;
20
+ formatX: (t: number) => string;
21
+ /** Tooltip time formatter. Defaults to `formatX`; use to keep the tooltip's
22
+ * full clock time when the axis ticks are compact (hour-only). */
23
+ formatTooltipX?: (t: number) => string;
24
+ formatValue?: (value: number) => string;
25
+ labels: {
26
+ solar: string;
27
+ grid: string;
28
+ battery: string;
29
+ consumption: string;
30
+ };
31
+ /** Series to drop entirely (no legend entry, area, or tooltip row). */
32
+ omitSeries?: readonly PowerHistorySeriesKey[];
33
+ /** Epoch ms to mark with the current-time dashed line (omit to hide). */
34
+ highlightAt?: number;
35
+ title?: string;
36
+ className?: string;
37
+ height?: number;
38
+ zoomable?: boolean;
39
+ zoomResetLabel?: string;
40
+ zoomDomain?: TimeDomain | null;
41
+ onZoomDomainChange?: (domain: TimeDomain | null) => void;
42
+ }
43
+ declare const SERIES_KEYS: readonly ["solar", "grid", "battery", "consumption"];
44
+ type PowerHistorySeriesKey = (typeof SERIES_KEYS)[number];
45
+ /**
46
+ * Diverging "power sources" area chart over a continuous time axis: solar
47
+ * (orange), grid (blue) and battery (green) areas around a zero baseline, with
48
+ * consumption overlaid as a line. Negative values (grid feed-in, battery
49
+ * charging) dip below zero. For instantaneous power (day view). A legend at the
50
+ * top toggles each series on/off; the y-axis rescales to the visible ones. visx.
51
+ */
52
+ declare function PowerHistoryChart({
53
+ data,
54
+ unit,
55
+ formatX,
56
+ formatTooltipX,
57
+ formatValue,
58
+ labels,
59
+ omitSeries,
60
+ highlightAt,
61
+ title,
62
+ className,
63
+ height,
64
+ zoomable,
65
+ zoomResetLabel,
66
+ zoomDomain,
67
+ onZoomDomainChange
68
+ }: PowerHistoryChartProps): import("react/jsx-runtime").JSX.Element;
69
+ //#endregion
70
+ export { PowerHistoryChart, PowerHistoryChartProps, PowerHistoryPoint, PowerHistorySeriesKey };
71
+ //# sourceMappingURL=power-history-chart.d.cts.map