@carto/ps-react-ui 4.11.1 → 4.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/echart-BMPpj7n_.js +250 -0
- package/dist/echart-BMPpj7n_.js.map +1 -0
- package/dist/types/widgets-v2/echart/edge-label-clamp.d.ts +57 -0
- package/dist/types/widgets-v2/echart/edge-label-clamp.test.d.ts +1 -0
- package/dist/widgets-v2/bar.js +87 -99
- package/dist/widgets-v2/bar.js.map +1 -1
- package/dist/widgets-v2/echart.js +1 -1
- package/dist/widgets-v2/histogram.js +96 -107
- package/dist/widgets-v2/histogram.js.map +1 -1
- package/dist/widgets-v2/timeseries.js +104 -116
- package/dist/widgets-v2/timeseries.js.map +1 -1
- package/dist/widgets-v2.js +2 -2
- package/package.json +3 -3
- package/src/widgets-v2/bar/options.test.ts +31 -4
- package/src/widgets-v2/bar/options.ts +18 -22
- package/src/widgets-v2/echart/echart-ui.test.tsx +70 -0
- package/src/widgets-v2/echart/echart-ui.tsx +28 -0
- package/src/widgets-v2/echart/edge-label-clamp.test.ts +198 -0
- package/src/widgets-v2/echart/edge-label-clamp.ts +216 -0
- package/src/widgets-v2/histogram/options.test.ts +11 -4
- package/src/widgets-v2/histogram/options.ts +17 -21
- package/src/widgets-v2/timeseries/options.test.ts +9 -4
- package/src/widgets-v2/timeseries/options.ts +17 -22
- package/dist/echart-CU0KmClP.js +0 -176
- package/dist/echart-CU0KmClP.js.map +0 -1
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { n as A, d as
|
|
3
|
-
import { jsxs as
|
|
1
|
+
import * as G from "echarts";
|
|
2
|
+
import { n as A, d as K, g as V, c as R, f as Y } from "../option-builders-F-c9ELi1.js";
|
|
3
|
+
import { jsxs as O, jsx as y } from "react/jsx-runtime";
|
|
4
4
|
import { c as q } from "react/compiler-runtime";
|
|
5
|
-
import { Box as S, Skeleton as
|
|
5
|
+
import { Box as S, Skeleton as b } from "@mui/material";
|
|
6
6
|
import "../widget-store-Bw5zRUGg.js";
|
|
7
7
|
import "zustand/shallow";
|
|
8
8
|
import "@mui/icons-material";
|
|
@@ -27,10 +27,10 @@ import { a as J } from "../exports-Cx-f6m6U.js";
|
|
|
27
27
|
import { b as Q } from "../png-item-BE9uEqlD.js";
|
|
28
28
|
function X({
|
|
29
29
|
theme: e,
|
|
30
|
-
formatter:
|
|
30
|
+
formatter: i,
|
|
31
31
|
labelFormatter: r
|
|
32
32
|
}) {
|
|
33
|
-
let
|
|
33
|
+
let c = 0, a = 1;
|
|
34
34
|
return {
|
|
35
35
|
grid: {
|
|
36
36
|
left: parseInt(e.spacing(1)),
|
|
@@ -53,13 +53,13 @@ function X({
|
|
|
53
53
|
axisPointer: {
|
|
54
54
|
type: "line"
|
|
55
55
|
},
|
|
56
|
-
position:
|
|
57
|
-
formatter: F(
|
|
56
|
+
position: V(e),
|
|
57
|
+
formatter: F(i, r)
|
|
58
58
|
},
|
|
59
59
|
// Legend styling baked here; `show` is toggled by the merger based on
|
|
60
60
|
// series count.
|
|
61
61
|
legend: {
|
|
62
|
-
...
|
|
62
|
+
...K({
|
|
63
63
|
hasLegend: !1
|
|
64
64
|
})
|
|
65
65
|
},
|
|
@@ -82,14 +82,14 @@ function X({
|
|
|
82
82
|
margin: 0,
|
|
83
83
|
hideOverlap: !0,
|
|
84
84
|
...r && {
|
|
85
|
-
formatter: (
|
|
85
|
+
formatter: (o) => r(new Date(o))
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
yAxis: {
|
|
90
90
|
type: "value",
|
|
91
|
-
min: (
|
|
92
|
-
max: (
|
|
91
|
+
min: (o) => (c = o.min < 0 ? A(o.min) : 0, c),
|
|
92
|
+
max: (o) => (a = o.max <= 0 ? 1 : A(o.max), a),
|
|
93
93
|
axisLine: {
|
|
94
94
|
show: !1
|
|
95
95
|
},
|
|
@@ -111,129 +111,117 @@ function X({
|
|
|
111
111
|
showMinLabel: !0,
|
|
112
112
|
verticalAlign: "bottom",
|
|
113
113
|
inside: !0,
|
|
114
|
-
formatter: (
|
|
114
|
+
formatter: (o) => o !== a && o !== c || o === 0 ? "" : i ? i(o) : String(o)
|
|
115
115
|
}
|
|
116
116
|
}
|
|
117
117
|
};
|
|
118
118
|
}
|
|
119
|
-
function
|
|
119
|
+
function Ie(e) {
|
|
120
120
|
const {
|
|
121
|
-
theme:
|
|
121
|
+
theme: i,
|
|
122
122
|
formatter: r,
|
|
123
|
-
labelFormatter:
|
|
124
|
-
optionsOverride:
|
|
125
|
-
} = e,
|
|
126
|
-
return (t,
|
|
123
|
+
labelFormatter: c,
|
|
124
|
+
optionsOverride: a
|
|
125
|
+
} = e, o = e.series, h = e.smooth ?? !0, g = e.area ?? !1, l = e.selection, m = l && l.length > 0 ? new Set(l) : null, s = (t) => t instanceof Date ? t.getTime() : t;
|
|
126
|
+
return (t, p, k) => {
|
|
127
127
|
if (t == null) {
|
|
128
|
-
const
|
|
129
|
-
theme:
|
|
128
|
+
const n = X({
|
|
129
|
+
theme: i,
|
|
130
130
|
formatter: r,
|
|
131
|
-
labelFormatter:
|
|
131
|
+
labelFormatter: c
|
|
132
132
|
});
|
|
133
|
-
return
|
|
133
|
+
return a ? H(n, a) : n;
|
|
134
134
|
}
|
|
135
|
-
const
|
|
136
|
-
if (
|
|
135
|
+
const w = Array.isArray(p) ? p : [];
|
|
136
|
+
if (w.length === 0)
|
|
137
137
|
return {
|
|
138
138
|
...t,
|
|
139
139
|
dataset: [],
|
|
140
140
|
series: []
|
|
141
141
|
};
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return !p || b == null || p.has(l(b)) ? u : E.color.modifyAlpha(u, 0.15);
|
|
142
|
+
const v = w.length > 1, j = Array.isArray(t.series) ? t.series : [], N = j[0] ?? {}, M = typeof t.yAxis == "object" && !Array.isArray(t.yAxis) ? t.yAxis : {}, C = typeof t.grid == "object" && !Array.isArray(t.grid) ? t.grid : {}, P = typeof t.tooltip == "object" && !Array.isArray(t.tooltip) ? t.tooltip : {}, Z = typeof t.legend == "object" && !Array.isArray(t.legend) ? t.legend : {}, L = k?.formatter;
|
|
143
|
+
let T = 0, I = 1;
|
|
144
|
+
const D = W(t.dataZoom, v), $ = typeof C.bottom == "number" ? C.bottom : 24, _ = v ? 56 : $, z = D ? _ + B.sliderHeight + B.sliderGap : _, E = {
|
|
145
|
+
color: (n) => {
|
|
146
|
+
const x = n.value?.name, f = n.color;
|
|
147
|
+
return !m || x == null || m.has(s(x)) ? f : G.color.modifyAlpha(f, 0.15);
|
|
149
148
|
}
|
|
150
149
|
};
|
|
151
150
|
return {
|
|
152
151
|
...t,
|
|
153
|
-
dataset:
|
|
154
|
-
source:
|
|
152
|
+
dataset: w.map((n) => ({
|
|
153
|
+
source: n
|
|
155
154
|
})),
|
|
156
|
-
series:
|
|
157
|
-
const
|
|
155
|
+
series: w.map((n, d) => {
|
|
156
|
+
const x = j[d] ?? N, f = U(i, o?.[d]?.color);
|
|
158
157
|
return {
|
|
159
|
-
...typeof
|
|
158
|
+
...typeof x == "object" ? x : {},
|
|
160
159
|
type: "line",
|
|
161
|
-
datasetIndex:
|
|
162
|
-
name:
|
|
160
|
+
datasetIndex: d,
|
|
161
|
+
name: o?.[d]?.name ?? `Series ${d + 1}`,
|
|
163
162
|
encode: {
|
|
164
163
|
x: "name",
|
|
165
164
|
y: "value"
|
|
166
165
|
},
|
|
167
|
-
smooth:
|
|
166
|
+
smooth: h,
|
|
168
167
|
// When a selection is active, surface markers so the per-point
|
|
169
168
|
// color callback has something to dim — a continuous line would
|
|
170
169
|
// hide the visual selection feedback.
|
|
171
|
-
showSymbol:
|
|
172
|
-
...
|
|
170
|
+
showSymbol: m != null,
|
|
171
|
+
...g ? {
|
|
173
172
|
areaStyle: {}
|
|
174
173
|
} : {},
|
|
175
174
|
emphasis: {
|
|
176
175
|
focus: "series"
|
|
177
176
|
},
|
|
178
|
-
itemStyle:
|
|
179
|
-
...
|
|
180
|
-
color:
|
|
177
|
+
itemStyle: E,
|
|
178
|
+
...f ? {
|
|
179
|
+
color: f,
|
|
181
180
|
lineStyle: {
|
|
182
|
-
color:
|
|
181
|
+
color: f
|
|
183
182
|
}
|
|
184
183
|
} : {}
|
|
185
184
|
};
|
|
186
185
|
}),
|
|
187
186
|
legend: {
|
|
188
|
-
...
|
|
189
|
-
show:
|
|
187
|
+
...Z,
|
|
188
|
+
show: v
|
|
190
189
|
},
|
|
191
190
|
grid: {
|
|
192
|
-
...
|
|
193
|
-
bottom:
|
|
191
|
+
...C,
|
|
192
|
+
bottom: z
|
|
194
193
|
},
|
|
195
|
-
...
|
|
196
|
-
dataZoom:
|
|
194
|
+
...D ? {
|
|
195
|
+
dataZoom: D
|
|
197
196
|
} : {},
|
|
198
197
|
yAxis: {
|
|
199
|
-
...
|
|
200
|
-
min:
|
|
201
|
-
max:
|
|
198
|
+
...M,
|
|
199
|
+
min: (n) => (T = n.min < 0 ? A(n.min) : 0, T),
|
|
200
|
+
max: (n) => (I = n.max <= 0 ? 1 : A(n.max), I),
|
|
202
201
|
axisLabel: {
|
|
203
|
-
...
|
|
204
|
-
formatter: (
|
|
202
|
+
...M.axisLabel ?? {},
|
|
203
|
+
formatter: (n) => n !== I && n !== T || n === 0 ? "" : L ? L(n) : String(n)
|
|
205
204
|
}
|
|
206
205
|
},
|
|
207
206
|
tooltip: {
|
|
208
|
-
...
|
|
209
|
-
formatter: F(
|
|
207
|
+
...P,
|
|
208
|
+
formatter: F(L, c)
|
|
210
209
|
}
|
|
211
210
|
};
|
|
212
211
|
};
|
|
213
212
|
}
|
|
214
|
-
function F(e,
|
|
213
|
+
function F(e, i) {
|
|
215
214
|
return Y((r) => {
|
|
216
|
-
const
|
|
215
|
+
const c = r.value, a = c?.value, o = typeof a == "number" && e ? e(a) : a ?? "", h = typeof r.marker == "string" ? r.marker : "", g = r.seriesName ? `${r.seriesName}: ` : "", l = c?.name ?? r.name, m = i && l != null ? i(l instanceof Date ? l : new Date(l)) : l ?? "";
|
|
217
216
|
return {
|
|
218
|
-
name: String(
|
|
219
|
-
seriesName:
|
|
220
|
-
marker:
|
|
221
|
-
value:
|
|
217
|
+
name: String(m),
|
|
218
|
+
seriesName: g,
|
|
219
|
+
marker: h,
|
|
220
|
+
value: o
|
|
222
221
|
};
|
|
223
222
|
});
|
|
224
223
|
}
|
|
225
|
-
|
|
226
|
-
let o = 0, r = -1 / 0;
|
|
227
|
-
for (const n of e)
|
|
228
|
-
for (const c of n)
|
|
229
|
-
typeof c?.value != "number" || !Number.isFinite(c.value) || (c.value < o && (o = c.value), c.value > r && (r = c.value));
|
|
230
|
-
const a = o < 0 ? A(o) : 0, i = r <= 0 ? 1 : A(r);
|
|
231
|
-
return {
|
|
232
|
-
niceMinVal: a,
|
|
233
|
-
niceMaxVal: i
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
const g = {
|
|
224
|
+
const u = {
|
|
237
225
|
container: {
|
|
238
226
|
display: "flex",
|
|
239
227
|
flexDirection: "column",
|
|
@@ -289,68 +277,68 @@ const g = {
|
|
|
289
277
|
}) => e(1.5)
|
|
290
278
|
}
|
|
291
279
|
};
|
|
292
|
-
function
|
|
280
|
+
function De() {
|
|
293
281
|
const e = q(2);
|
|
294
|
-
let
|
|
295
|
-
e[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (
|
|
296
|
-
/* @__PURE__ */
|
|
297
|
-
/* @__PURE__ */
|
|
298
|
-
/* @__PURE__ */
|
|
299
|
-
] }), e[0] =
|
|
282
|
+
let i;
|
|
283
|
+
e[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (i = /* @__PURE__ */ O(S, { sx: u.graph, children: [
|
|
284
|
+
/* @__PURE__ */ y(b, { variant: "rectangular", sx: u.segmentA }),
|
|
285
|
+
/* @__PURE__ */ y(b, { variant: "rectangular", sx: u.segmentB }),
|
|
286
|
+
/* @__PURE__ */ y(b, { variant: "rectangular", sx: u.segmentC })
|
|
287
|
+
] }), e[0] = i) : i = e[0];
|
|
300
288
|
let r;
|
|
301
|
-
return e[1] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (r = /* @__PURE__ */
|
|
302
|
-
|
|
303
|
-
/* @__PURE__ */
|
|
289
|
+
return e[1] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (r = /* @__PURE__ */ O(S, { sx: u.container, children: [
|
|
290
|
+
i,
|
|
291
|
+
/* @__PURE__ */ y(S, { sx: u.legend, children: [0, 1].map(ee) })
|
|
304
292
|
] }), e[1] = r) : r = e[1], r;
|
|
305
293
|
}
|
|
306
|
-
function
|
|
307
|
-
return /* @__PURE__ */
|
|
308
|
-
/* @__PURE__ */
|
|
309
|
-
/* @__PURE__ */
|
|
294
|
+
function ee(e) {
|
|
295
|
+
return /* @__PURE__ */ O(S, { sx: u.legendItem, children: [
|
|
296
|
+
/* @__PURE__ */ y(b, { variant: "circular", width: 8, height: 8 }),
|
|
297
|
+
/* @__PURE__ */ y(b, { width: 48, height: 8 })
|
|
310
298
|
] }, `legend-${e}`);
|
|
311
299
|
}
|
|
312
|
-
function
|
|
313
|
-
const
|
|
314
|
-
return e.getCaptureEl &&
|
|
300
|
+
function Oe(e) {
|
|
301
|
+
const i = [];
|
|
302
|
+
return e.getCaptureEl && i.push(Q({
|
|
315
303
|
filename: e.filename,
|
|
316
304
|
getCaptureEl: e.getCaptureEl,
|
|
317
305
|
pixelRatio: e.pngPixelRatio,
|
|
318
306
|
backgroundColor: e.pngBackgroundColor
|
|
319
|
-
})),
|
|
307
|
+
})), i.push({
|
|
320
308
|
id: "csv",
|
|
321
309
|
label: "Download as CSV",
|
|
322
310
|
resolve: () => {
|
|
323
|
-
const r = e.getData(),
|
|
324
|
-
for (const
|
|
325
|
-
for (const t of
|
|
326
|
-
const
|
|
327
|
-
|
|
311
|
+
const r = e.getData(), c = r.length, a = [], o = /* @__PURE__ */ new Set();
|
|
312
|
+
for (const s of r)
|
|
313
|
+
for (const t of s) {
|
|
314
|
+
const p = String(t.name);
|
|
315
|
+
o.has(p) || (o.add(p), a.push(t.name));
|
|
328
316
|
}
|
|
329
|
-
const
|
|
330
|
-
for (let
|
|
331
|
-
|
|
332
|
-
const
|
|
333
|
-
for (const
|
|
334
|
-
const t = [
|
|
335
|
-
for (const
|
|
336
|
-
|
|
317
|
+
const h = r.map((s) => new Map(s.map((t) => [String(t.name), t.value]))), g = ["time"];
|
|
318
|
+
for (let s = 0; s < c; s++)
|
|
319
|
+
g.push(e.seriesNames?.[s] ?? `series_${s + 1}`);
|
|
320
|
+
const l = [g];
|
|
321
|
+
for (const s of a) {
|
|
322
|
+
const t = [te(s)], p = String(s);
|
|
323
|
+
for (const k of h) t.push(k.get(p) ?? "");
|
|
324
|
+
l.push(t);
|
|
337
325
|
}
|
|
338
|
-
const
|
|
326
|
+
const m = J(l);
|
|
339
327
|
return Promise.resolve({
|
|
340
|
-
url:
|
|
328
|
+
url: m.url,
|
|
341
329
|
filename: `${e.filename}.csv`,
|
|
342
|
-
revoke:
|
|
330
|
+
revoke: m.revoke
|
|
343
331
|
});
|
|
344
332
|
}
|
|
345
|
-
}),
|
|
333
|
+
}), i;
|
|
346
334
|
}
|
|
347
|
-
function
|
|
335
|
+
function te(e) {
|
|
348
336
|
return e instanceof Date ? e.toISOString() : typeof e == "number" ? new Date(e).toISOString() : e;
|
|
349
337
|
}
|
|
350
338
|
export {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
339
|
+
De as TimeseriesSkeleton,
|
|
340
|
+
Oe as createTimeseriesDownloadConfig,
|
|
341
|
+
Ie as createTimeseriesOptionFactory,
|
|
354
342
|
X as timeseriesOptions
|
|
355
343
|
};
|
|
356
344
|
//# sourceMappingURL=timeseries.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeseries.js","sources":["../../src/widgets-v2/timeseries/options.ts","../../src/widgets-v2/timeseries/skeleton.tsx","../../src/widgets-v2/timeseries/download.ts"],"sourcesContent":["import type { EChartsOption } from 'echarts'\nimport * as echarts from 'echarts'\nimport type { CallbackDataParams } from 'echarts/types/dist/shared'\nimport {\n buildGridConfig,\n buildLegendConfig,\n createTooltipFormatter,\n createTooltipPositioner,\n niceNum,\n} from '../../widgets/utils/chart-config'\nimport { ZOOM_LAYOUT } from '../actions/zoom-toggle'\nimport type { OptionFactory } from '../echart'\nimport { mergeOptions, resolveThemeColor } from '../utils'\nimport { positionDataZoomForLegend } from '../utils/data-zoom-layout'\nimport type {\n TimeseriesEChartsOption,\n TimeseriesOptionFactoryInput,\n TimeseriesOptionsInput,\n TimeseriesWidgetData,\n} from './types'\n\n/**\n * Builds the **structural** ECharts option for a timeseries widget —\n * time x-axis, value y-axis, themed tooltip, themed legend, CARTO color\n * palette. Mirrors {@link import('../bar/options').barOptions} so all\n * four ECharts widgets share v1 look-and-feel.\n *\n * Intentional deviations from bar (timeseries-specific):\n * - **X-axis is `type: 'time'`** (not 'category'). ECharts handles\n * uneven sample spacing and zoom-level-aware label formatting.\n * `labelFormatter` is wrapped so the consumer sees a `Date`, not\n * a numeric timestamp.\n * - **Tooltip body reads `{ name, value }` rows**, same as bar, but\n * the `name` may arrive as `Date | number | string`. The\n * `labelFormatter` receives a `Date` regardless.\n *\n * Intentionally data-agnostic: no series, no dataset, no `legend.show`\n * (those depend on data and are added by the option factory's merge\n * phase via {@link createTimeseriesOptionFactory}).\n */\nexport function timeseriesOptions({\n theme,\n formatter,\n labelFormatter,\n}: TimeseriesOptionsInput): TimeseriesEChartsOption {\n // Closure shared between yAxis min/max callbacks and the label formatter,\n // so only the rounded extents are labelled (matches v1 + bar).\n let niceMin = 0\n let niceMax = 1\n\n return {\n grid: {\n left: parseInt(theme.spacing(1)),\n top: parseInt(theme.spacing(3)),\n right: parseInt(theme.spacing(1)),\n // Default: no legend. Merger bumps this when there are >1 series.\n ...buildGridConfig(false, theme),\n containLabel: true,\n },\n tooltip: {\n trigger: 'axis',\n backgroundColor: theme.palette.grey[900],\n borderWidth: 0,\n padding: [parseInt(theme.spacing(1)), parseInt(theme.spacing(1))],\n textStyle: {\n color: theme.palette.common.white,\n fontSize: 11,\n fontFamily: theme.typography.caption.fontFamily,\n },\n axisPointer: { type: 'line' },\n position: createTooltipPositioner(theme),\n formatter: buildTimeseriesTooltipFormatter(formatter, labelFormatter),\n },\n // Legend styling baked here; `show` is toggled by the merger based on\n // series count.\n legend: {\n ...buildLegendConfig({ hasLegend: false }),\n },\n axisPointer: { lineStyle: { color: theme.palette.grey[400] } },\n color: [\n theme.palette.secondary.main,\n ...Object.values(\n (theme.palette as { qualitative?: { bold?: Record<string, string> } })\n .qualitative?.bold ?? {},\n ),\n ],\n xAxis: {\n type: 'time',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n padding: [parseInt(theme.spacing(0.5)), 0, 0, 0],\n margin: 0,\n hideOverlap: true,\n ...(labelFormatter && {\n formatter: (value: number) => labelFormatter(new Date(value)),\n }),\n },\n },\n yAxis: {\n type: 'value',\n min: (extent: { min: number }) => {\n niceMin = extent.min < 0 ? niceNum(extent.min) : 0\n return niceMin\n },\n max: (extent: { min: number; max: number }) => {\n niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)\n return niceMax\n },\n axisLine: { show: false },\n axisTick: { show: false },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n axisLabel: {\n fontSize: theme.typography.overlineDelicate?.fontSize,\n fontFamily: theme.typography.overlineDelicate?.fontFamily,\n margin: parseInt(theme.spacing(1)),\n show: true,\n showMaxLabel: true,\n showMinLabel: true,\n verticalAlign: 'bottom',\n inside: true,\n formatter: (value: number) => {\n if (value !== niceMax && value !== niceMin) return ''\n if (value === 0) return ''\n return formatter ? formatter(value) : String(value)\n },\n },\n },\n } as TimeseriesEChartsOption\n}\n\n/**\n * Returns the timeseries widget's {@link OptionFactory} — one closure\n * that owns BOTH phases of option construction:\n *\n * - **Structural phase** (`option == null`) — builds the theme-aware\n * structural option via {@link timeseriesOptions}, optionally merging\n * the consumer-supplied `optionsOverride`. Called once by Provider to\n * seed `rawOptions` in the store.\n * - **Merge phase** (`option != null`) — fuses post-pipeline `state.data`\n * (`TimeseriesWidgetData`) into the option via the dataset API: one\n * dataset per series, each series referencing its dataset by index,\n * encoded by `name` (x — time) and `value` (y). Mirrors {@link import('../bar/options').createBarOptionFactory}:\n * series-template merge for `addStack`, reactive formatters from\n * `ctx`, `niceNum`-rounded y-axis bounds at fusion time, and\n * `positionDataZoomForLegend` layout for ZoomToggle sliders.\n */\nexport function createTimeseriesOptionFactory(\n options: TimeseriesOptionFactoryInput,\n): OptionFactory {\n const { theme, formatter, labelFormatter, optionsOverride } = options\n const series = options.series\n const smooth = options.smooth ?? true\n const area = options.area ?? false\n const selection = options.selection\n const selectionSet =\n selection && selection.length > 0\n ? new Set<string | number>(selection)\n : null\n // `name` may be Date | number | string. Normalize to the same type the\n // selection is keyed on (Date → ms) so Set lookups match.\n const normalizeName = (n: Date | number | string): string | number =>\n n instanceof Date ? n.getTime() : n\n return (option, data, ctx) => {\n if (option == null) {\n const structural = timeseriesOptions({ theme, formatter, labelFormatter })\n return optionsOverride\n ? (mergeOptions(\n structural as unknown as Record<string, unknown>,\n optionsOverride as Partial<Record<string, unknown>>,\n ) as EChartsOption)\n : structural\n }\n\n const seriesArr = Array.isArray(data) ? (data as TimeseriesWidgetData) : []\n if (seriesArr.length === 0) {\n return { ...option, dataset: [], series: [] }\n }\n const hasLegend = seriesArr.length > 1\n const seriesTemplates = Array.isArray(option.series) ? option.series : []\n const broadcastTemplate = seriesTemplates[0] ?? {}\n const baseYAxis =\n typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)\n ? option.yAxis\n : {}\n const baseGrid =\n typeof option.grid === 'object' && !Array.isArray(option.grid)\n ? option.grid\n : {}\n const baseTooltip =\n typeof option.tooltip === 'object' && !Array.isArray(option.tooltip)\n ? option.tooltip\n : {}\n const baseLegend =\n typeof option.legend === 'object' && !Array.isArray(option.legend)\n ? option.legend\n : {}\n\n // Reactive (live store) formatter from ctx — distinct from the\n // closure-time `formatter` captured for the structural-build branch\n // above. RelativeData can install a percent formatter on the store\n // after the factory was constructed; the merge phase reads `ctx` to\n // pick that up. `labelFormatter` (Date → string) is structural-only —\n // not relativizable — so the merge branch reads the closure-time value.\n const liveFormatter = ctx?.formatter\n\n const { niceMinVal, niceMaxVal } = computeTimeseriesNiceBounds(seriesArr)\n\n // Zoom slider layout: when ZoomToggle has installed `dataZoom`, push the\n // slider above the legend (if any) and reserve room in the grid below.\n const dataZoomLayout = positionDataZoomForLegend(option.dataZoom, hasLegend)\n const fallbackBottom =\n typeof baseGrid.bottom === 'number' ? baseGrid.bottom : 24\n const baseBottom = hasLegend ? 56 : fallbackBottom\n const gridBottom = dataZoomLayout\n ? baseBottom + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : baseBottom\n\n // Dim non-selected points via `series.itemStyle.color`. Per-row\n // `itemStyle` on dataset object-rows is silently ignored when\n // `series.encode` is in play.\n //\n // We *always* emit `itemStyle.color` (a passthrough when nothing is\n // selected), not conditionally — dropping the key between renders\n // would let ECharts' default merge keep the previous callback alive\n // and points would stay dimmed forever after an external clear.\n // Always emitting lets normal merge swap the callback in place, no\n // `replaceMerge` and no entry-animation flash on selection on/off.\n const dimItemStyle = {\n color: (params: CallbackDataParams) => {\n const datum = params.value as\n | { name?: Date | number | string }\n | undefined\n const raw = datum?.name\n const base = params.color as string\n if (!selectionSet || raw == null) return base\n return selectionSet.has(normalizeName(raw))\n ? base\n : echarts.color.modifyAlpha(base, 0.15)\n },\n }\n\n return {\n ...option,\n dataset: seriesArr.map((s) => ({ source: s as readonly object[] })),\n series: seriesArr.map((_, i) => {\n const template =\n (seriesTemplates[i] as object | undefined) ??\n (broadcastTemplate as object)\n // For line series, set BOTH `series[i].color` (legend swatch +\n // markers) AND `series[i].lineStyle.color` (the line itself) so\n // the override paints everywhere a series has a colour slot.\n const overrideColor = resolveThemeColor(theme, series?.[i]?.color)\n return {\n ...(typeof template === 'object' ? template : {}),\n type: 'line' as const,\n datasetIndex: i,\n name: series?.[i]?.name ?? `Series ${i + 1}`,\n encode: { x: 'name', y: 'value' },\n smooth,\n // When a selection is active, surface markers so the per-point\n // color callback has something to dim — a continuous line would\n // hide the visual selection feedback.\n showSymbol: selectionSet != null,\n ...(area ? { areaStyle: {} } : {}),\n emphasis: { focus: 'series' },\n itemStyle: dimItemStyle,\n ...(overrideColor\n ? { color: overrideColor, lineStyle: { color: overrideColor } }\n : {}),\n }\n }),\n legend: { ...baseLegend, show: hasLegend },\n grid: { ...baseGrid, bottom: gridBottom },\n ...(dataZoomLayout ? { dataZoom: dataZoomLayout } : {}),\n yAxis: {\n ...baseYAxis,\n min: niceMinVal,\n max: niceMaxVal,\n axisLabel: {\n ...((baseYAxis as { axisLabel?: object }).axisLabel ?? {}),\n formatter: (value: number) => {\n if (value !== niceMaxVal && value !== niceMinVal) return ''\n if (value === 0) return ''\n return liveFormatter ? liveFormatter(value) : String(value)\n },\n },\n } as EChartsOption['yAxis'],\n tooltip: {\n ...baseTooltip,\n formatter: buildTimeseriesTooltipFormatter(\n liveFormatter,\n labelFormatter,\n ),\n },\n } as EChartsOption\n }\n}\n\n/**\n * Tooltip formatter for the timeseries `{ name, value }` row shape.\n * `name` arrives as `Date | number | string` (the time-axis stores the\n * raw value the consumer supplied). The consumer's `labelFormatter`\n * expects a `Date`, so we coerce non-Date values via `new Date(...)`\n * before invoking it.\n */\nfunction buildTimeseriesTooltipFormatter(\n formatter: ((value: number) => string) | undefined,\n labelFormatter: ((value: Date) => string) | undefined,\n) {\n return createTooltipFormatter((item) => {\n const row = item.value as\n | { name?: Date | number | string; value?: number }\n | undefined\n const raw = row?.value\n const formattedValue =\n typeof raw === 'number' && formatter ? formatter(raw) : (raw ?? '')\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n const rawName = row?.name ?? item.name\n const name =\n labelFormatter && rawName != null\n ? labelFormatter(rawName instanceof Date ? rawName : new Date(rawName))\n : (rawName ?? '')\n return { name: String(name), seriesName, marker, value: formattedValue }\n })\n}\n\nfunction computeTimeseriesNiceBounds(seriesArr: TimeseriesWidgetData): {\n niceMinVal: number\n niceMaxVal: number\n} {\n let min = 0\n let max = -Infinity\n for (const series of seriesArr) {\n for (const d of series) {\n if (typeof d?.value !== 'number' || !Number.isFinite(d.value)) continue\n if (d.value < min) min = d.value\n if (d.value > max) max = d.value\n }\n }\n const niceMinVal = min < 0 ? niceNum(min) : 0\n const niceMaxVal = max <= 0 ? 1 : niceNum(max)\n return { niceMinVal, niceMaxVal }\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'space-between',\n gap: ({ spacing }) => spacing(1),\n height: ({ spacing }) => spacing(38),\n },\n graph: {\n position: 'relative',\n flex: '1 1 auto',\n width: '100%',\n },\n segmentA: {\n position: 'absolute',\n left: 0,\n right: '70%',\n top: '60%',\n height: 4,\n },\n segmentB: {\n position: 'absolute',\n left: '25%',\n right: '40%',\n top: '35%',\n height: 4,\n },\n segmentC: {\n position: 'absolute',\n left: '55%',\n right: 0,\n top: '50%',\n height: 4,\n },\n legend: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(2),\n height: ({ spacing }) => spacing(5),\n },\n legendItem: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(1.5),\n },\n} satisfies Record<string, SxProps<Theme>>\n\n/**\n * Loading state for the Timeseries widget. Mirrors a line chart's\n * silhouette — three thin horizontal segments at staggered offsets to\n * suggest a moving line, plus a 2-dot legend stub. Sibling-consistent\n * with Bar / Histogram / Scatter skeletons (column-flex container with\n * legend strip below).\n */\nexport function TimeseriesSkeleton() {\n return (\n <Box sx={styles.container}>\n <Box sx={styles.graph}>\n <Skeleton variant='rectangular' sx={styles.segmentA} />\n <Skeleton variant='rectangular' sx={styles.segmentB} />\n <Skeleton variant='rectangular' sx={styles.segmentC} />\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>\n )\n}\n","import {\n buildPngDownloadItem,\n downloadToCSV,\n type DownloadItem,\n} from '../actions/download'\nimport type { TimeseriesWidgetData } from './types'\n\n/**\n * Download menu items for the Timeseries widget. Always includes a CSV\n * item with `time, series_1, series_2, …` columns (one row per unique time\n * across all series; ISO-8601 strings for `Date`/numeric times). When\n * `getCaptureEl` is supplied, prepends a PNG item that rasterises the\n * captured element via `html2canvas`.\n */\nexport function createTimeseriesDownloadConfig(args: {\n filename: string\n getData: () => TimeseriesWidgetData\n seriesNames?: readonly string[]\n getCaptureEl?: () => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push({\n id: 'csv',\n label: 'Download as CSV',\n resolve: () => {\n const data = args.getData()\n const seriesCount = data.length\n\n // Collect every unique time, preserving insertion order.\n const timeKeys: (Date | number | string)[] = []\n const seenKeys = new Set<string>()\n for (const series of data) {\n for (const point of series) {\n const key = String(point.name)\n if (!seenKeys.has(key)) {\n seenKeys.add(key)\n timeKeys.push(point.name)\n }\n }\n }\n\n // Build a quick lookup per series for O(rows × series) emit.\n const lookups = data.map(\n (series) => new Map(series.map((p) => [String(p.name), p.value])),\n )\n\n const header: unknown[] = ['time']\n for (let i = 0; i < seriesCount; i++) {\n header.push(args.seriesNames?.[i] ?? `series_${i + 1}`)\n }\n const rows: unknown[][] = [header]\n for (const key of timeKeys) {\n const row: unknown[] = [formatTime(key)]\n const lookupKey = String(key)\n for (const lookup of lookups) row.push(lookup.get(lookupKey) ?? '')\n rows.push(row)\n }\n\n const handle = downloadToCSV(rows)\n return Promise.resolve({\n url: handle.url,\n filename: `${args.filename}.csv`,\n revoke: handle.revoke,\n })\n },\n })\n return items\n}\n\nfunction formatTime(v: Date | number | string): string {\n if (v instanceof Date) return v.toISOString()\n if (typeof v === 'number') return new Date(v).toISOString()\n return v\n}\n"],"names":["timeseriesOptions","theme","formatter","labelFormatter","niceMin","niceMax","grid","left","parseInt","spacing","top","right","buildGridConfig","containLabel","tooltip","trigger","backgroundColor","palette","grey","borderWidth","padding","textStyle","color","common","white","fontSize","fontFamily","typography","caption","axisPointer","type","position","createTooltipPositioner","buildTimeseriesTooltipFormatter","legend","buildLegendConfig","hasLegend","lineStyle","secondary","main","Object","values","qualitative","bold","xAxis","axisLine","show","axisTick","axisLabel","margin","hideOverlap","value","Date","yAxis","min","extent","niceNum","max","splitLine","black","divider","overlineDelicate","showMaxLabel","showMinLabel","verticalAlign","inside","String","createTimeseriesOptionFactory","options","optionsOverride","series","smooth","area","selection","selectionSet","length","Set","normalizeName","n","getTime","option","data","ctx","structural","mergeOptions","seriesArr","Array","isArray","dataset","seriesTemplates","broadcastTemplate","baseYAxis","baseGrid","baseTooltip","baseLegend","liveFormatter","niceMinVal","niceMaxVal","computeTimeseriesNiceBounds","dataZoomLayout","positionDataZoomForLegend","dataZoom","fallbackBottom","bottom","baseBottom","gridBottom","ZOOM_LAYOUT","sliderHeight","sliderGap","dimItemStyle","params","raw","name","base","has","echarts","modifyAlpha","map","s","source","_","i","template","overrideColor","resolveThemeColor","datasetIndex","encode","x","y","showSymbol","areaStyle","emphasis","focus","itemStyle","createTooltipFormatter","item","row","formattedValue","marker","seriesName","rawName","d","Number","isFinite","styles","container","display","flexDirection","justifyContent","gap","height","graph","flex","width","segmentA","segmentB","segmentC","alignItems","legendItem","TimeseriesSkeleton","$","_c","t0","Symbol","for","jsxs","Box","jsx","Skeleton","t1","_temp","createTimeseriesDownloadConfig","args","items","getCaptureEl","push","buildPngDownloadItem","filename","pixelRatio","pngPixelRatio","pngBackgroundColor","id","label","resolve","getData","seriesCount","timeKeys","seenKeys","point","key","add","lookups","Map","p","header","seriesNames","rows","formatTime","lookupKey","lookup","get","handle","downloadToCSV","Promise","url","revoke","v","toISOString"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"timeseries.js","sources":["../../src/widgets-v2/timeseries/options.ts","../../src/widgets-v2/timeseries/skeleton.tsx","../../src/widgets-v2/timeseries/download.ts"],"sourcesContent":["import type { EChartsOption } from 'echarts'\nimport * as echarts from 'echarts'\nimport type { CallbackDataParams } from 'echarts/types/dist/shared'\nimport {\n buildGridConfig,\n buildLegendConfig,\n createTooltipFormatter,\n createTooltipPositioner,\n niceNum,\n} from '../../widgets/utils/chart-config'\nimport { ZOOM_LAYOUT } from '../actions/zoom-toggle'\nimport type { OptionFactory } from '../echart'\nimport { mergeOptions, resolveThemeColor } from '../utils'\nimport { positionDataZoomForLegend } from '../utils/data-zoom-layout'\nimport type {\n TimeseriesEChartsOption,\n TimeseriesOptionFactoryInput,\n TimeseriesOptionsInput,\n TimeseriesWidgetData,\n} from './types'\n\n/**\n * Builds the **structural** ECharts option for a timeseries widget —\n * time x-axis, value y-axis, themed tooltip, themed legend, CARTO color\n * palette. Mirrors {@link import('../bar/options').barOptions} so all\n * four ECharts widgets share v1 look-and-feel.\n *\n * Intentional deviations from bar (timeseries-specific):\n * - **X-axis is `type: 'time'`** (not 'category'). ECharts handles\n * uneven sample spacing and zoom-level-aware label formatting.\n * `labelFormatter` is wrapped so the consumer sees a `Date`, not\n * a numeric timestamp.\n * - **Tooltip body reads `{ name, value }` rows**, same as bar, but\n * the `name` may arrive as `Date | number | string`. The\n * `labelFormatter` receives a `Date` regardless.\n *\n * Intentionally data-agnostic: no series, no dataset, no `legend.show`\n * (those depend on data and are added by the option factory's merge\n * phase via {@link createTimeseriesOptionFactory}).\n */\nexport function timeseriesOptions({\n theme,\n formatter,\n labelFormatter,\n}: TimeseriesOptionsInput): TimeseriesEChartsOption {\n // Closure shared between yAxis min/max callbacks and the label formatter,\n // so only the rounded extents are labelled (matches v1 + bar).\n let niceMin = 0\n let niceMax = 1\n\n return {\n grid: {\n left: parseInt(theme.spacing(1)),\n top: parseInt(theme.spacing(3)),\n right: parseInt(theme.spacing(1)),\n // Default: no legend. Merger bumps this when there are >1 series.\n ...buildGridConfig(false, theme),\n containLabel: true,\n },\n tooltip: {\n trigger: 'axis',\n backgroundColor: theme.palette.grey[900],\n borderWidth: 0,\n padding: [parseInt(theme.spacing(1)), parseInt(theme.spacing(1))],\n textStyle: {\n color: theme.palette.common.white,\n fontSize: 11,\n fontFamily: theme.typography.caption.fontFamily,\n },\n axisPointer: { type: 'line' },\n position: createTooltipPositioner(theme),\n formatter: buildTimeseriesTooltipFormatter(formatter, labelFormatter),\n },\n // Legend styling baked here; `show` is toggled by the merger based on\n // series count.\n legend: {\n ...buildLegendConfig({ hasLegend: false }),\n },\n axisPointer: { lineStyle: { color: theme.palette.grey[400] } },\n color: [\n theme.palette.secondary.main,\n ...Object.values(\n (theme.palette as { qualitative?: { bold?: Record<string, string> } })\n .qualitative?.bold ?? {},\n ),\n ],\n xAxis: {\n type: 'time',\n axisLine: { show: false },\n axisTick: { show: false },\n axisLabel: {\n padding: [parseInt(theme.spacing(0.5)), 0, 0, 0],\n margin: 0,\n hideOverlap: true,\n ...(labelFormatter && {\n formatter: (value: number) => labelFormatter(new Date(value)),\n }),\n },\n },\n yAxis: {\n type: 'value',\n min: (extent: { min: number }) => {\n niceMin = extent.min < 0 ? niceNum(extent.min) : 0\n return niceMin\n },\n max: (extent: { min: number; max: number }) => {\n niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)\n return niceMax\n },\n axisLine: { show: false },\n axisTick: { show: false },\n splitLine: {\n show: true,\n lineStyle: { color: theme.palette.black?.[4] ?? theme.palette.divider },\n },\n axisLabel: {\n fontSize: theme.typography.overlineDelicate?.fontSize,\n fontFamily: theme.typography.overlineDelicate?.fontFamily,\n margin: parseInt(theme.spacing(1)),\n show: true,\n showMaxLabel: true,\n showMinLabel: true,\n verticalAlign: 'bottom',\n inside: true,\n formatter: (value: number) => {\n if (value !== niceMax && value !== niceMin) return ''\n if (value === 0) return ''\n return formatter ? formatter(value) : String(value)\n },\n },\n },\n } as TimeseriesEChartsOption\n}\n\n/**\n * Returns the timeseries widget's {@link OptionFactory} — one closure\n * that owns BOTH phases of option construction:\n *\n * - **Structural phase** (`option == null`) — builds the theme-aware\n * structural option via {@link timeseriesOptions}, optionally merging\n * the consumer-supplied `optionsOverride`. Called once by Provider to\n * seed `rawOptions` in the store.\n * - **Merge phase** (`option != null`) — fuses post-pipeline `state.data`\n * (`TimeseriesWidgetData`) into the option via the dataset API: one\n * dataset per series, each series referencing its dataset by index,\n * encoded by `name` (x — time) and `value` (y). Mirrors {@link import('../bar/options').createBarOptionFactory}:\n * series-template merge for `addStack`, reactive formatters from\n * `ctx`, `niceNum`-rounded y-axis bounds at fusion time, and\n * `positionDataZoomForLegend` layout for ZoomToggle sliders.\n */\nexport function createTimeseriesOptionFactory(\n options: TimeseriesOptionFactoryInput,\n): OptionFactory {\n const { theme, formatter, labelFormatter, optionsOverride } = options\n const series = options.series\n const smooth = options.smooth ?? true\n const area = options.area ?? false\n const selection = options.selection\n const selectionSet =\n selection && selection.length > 0\n ? new Set<string | number>(selection)\n : null\n // `name` may be Date | number | string. Normalize to the same type the\n // selection is keyed on (Date → ms) so Set lookups match.\n const normalizeName = (n: Date | number | string): string | number =>\n n instanceof Date ? n.getTime() : n\n return (option, data, ctx) => {\n if (option == null) {\n const structural = timeseriesOptions({ theme, formatter, labelFormatter })\n return optionsOverride\n ? (mergeOptions(\n structural as unknown as Record<string, unknown>,\n optionsOverride as Partial<Record<string, unknown>>,\n ) as EChartsOption)\n : structural\n }\n\n const seriesArr = Array.isArray(data) ? (data as TimeseriesWidgetData) : []\n if (seriesArr.length === 0) {\n return { ...option, dataset: [], series: [] }\n }\n const hasLegend = seriesArr.length > 1\n const seriesTemplates = Array.isArray(option.series) ? option.series : []\n const broadcastTemplate = seriesTemplates[0] ?? {}\n const baseYAxis =\n typeof option.yAxis === 'object' && !Array.isArray(option.yAxis)\n ? option.yAxis\n : {}\n const baseGrid =\n typeof option.grid === 'object' && !Array.isArray(option.grid)\n ? option.grid\n : {}\n const baseTooltip =\n typeof option.tooltip === 'object' && !Array.isArray(option.tooltip)\n ? option.tooltip\n : {}\n const baseLegend =\n typeof option.legend === 'object' && !Array.isArray(option.legend)\n ? option.legend\n : {}\n\n // Reactive (live store) formatter from ctx — distinct from the\n // closure-time `formatter` captured for the structural-build branch\n // above. RelativeData can install a percent formatter on the store\n // after the factory was constructed; the merge phase reads `ctx` to\n // pick that up. `labelFormatter` (Date → string) is structural-only —\n // not relativizable — so the merge branch reads the closure-time value.\n const liveFormatter = ctx?.formatter\n\n // Closure shared between the yAxis min/max callbacks and the label\n // formatter, so only the rounded extents are labelled (matches v1 +\n // bar). Delegating the extent to ECharts (rather than precomputing\n // scalars from the raw data) keeps stacked lines inside the plot: when\n // StackToggle marks the series, ECharts feeds the *post-stack* extent\n // to these callbacks, so `niceNum` rounds the stacked total.\n let niceMin = 0\n let niceMax = 1\n\n // Zoom slider layout: when ZoomToggle has installed `dataZoom`, push the\n // slider above the legend (if any) and reserve room in the grid below.\n const dataZoomLayout = positionDataZoomForLegend(option.dataZoom, hasLegend)\n const fallbackBottom =\n typeof baseGrid.bottom === 'number' ? baseGrid.bottom : 24\n const baseBottom = hasLegend ? 56 : fallbackBottom\n const gridBottom = dataZoomLayout\n ? baseBottom + ZOOM_LAYOUT.sliderHeight + ZOOM_LAYOUT.sliderGap\n : baseBottom\n\n // Dim non-selected points via `series.itemStyle.color`. Per-row\n // `itemStyle` on dataset object-rows is silently ignored when\n // `series.encode` is in play.\n //\n // We *always* emit `itemStyle.color` (a passthrough when nothing is\n // selected), not conditionally — dropping the key between renders\n // would let ECharts' default merge keep the previous callback alive\n // and points would stay dimmed forever after an external clear.\n // Always emitting lets normal merge swap the callback in place, no\n // `replaceMerge` and no entry-animation flash on selection on/off.\n const dimItemStyle = {\n color: (params: CallbackDataParams) => {\n const datum = params.value as\n | { name?: Date | number | string }\n | undefined\n const raw = datum?.name\n const base = params.color as string\n if (!selectionSet || raw == null) return base\n return selectionSet.has(normalizeName(raw))\n ? base\n : echarts.color.modifyAlpha(base, 0.15)\n },\n }\n\n return {\n ...option,\n dataset: seriesArr.map((s) => ({ source: s as readonly object[] })),\n series: seriesArr.map((_, i) => {\n const template =\n (seriesTemplates[i] as object | undefined) ??\n (broadcastTemplate as object)\n // For line series, set BOTH `series[i].color` (legend swatch +\n // markers) AND `series[i].lineStyle.color` (the line itself) so\n // the override paints everywhere a series has a colour slot.\n const overrideColor = resolveThemeColor(theme, series?.[i]?.color)\n return {\n ...(typeof template === 'object' ? template : {}),\n type: 'line' as const,\n datasetIndex: i,\n name: series?.[i]?.name ?? `Series ${i + 1}`,\n encode: { x: 'name', y: 'value' },\n smooth,\n // When a selection is active, surface markers so the per-point\n // color callback has something to dim — a continuous line would\n // hide the visual selection feedback.\n showSymbol: selectionSet != null,\n ...(area ? { areaStyle: {} } : {}),\n emphasis: { focus: 'series' },\n itemStyle: dimItemStyle,\n ...(overrideColor\n ? { color: overrideColor, lineStyle: { color: overrideColor } }\n : {}),\n }\n }),\n legend: { ...baseLegend, show: hasLegend },\n grid: { ...baseGrid, bottom: gridBottom },\n ...(dataZoomLayout ? { dataZoom: dataZoomLayout } : {}),\n yAxis: {\n ...baseYAxis,\n min: (extent: { min: number }) => {\n niceMin = extent.min < 0 ? niceNum(extent.min) : 0\n return niceMin\n },\n max: (extent: { min: number; max: number }) => {\n niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)\n return niceMax\n },\n axisLabel: {\n ...((baseYAxis as { axisLabel?: object }).axisLabel ?? {}),\n formatter: (value: number) => {\n if (value !== niceMax && value !== niceMin) return ''\n if (value === 0) return ''\n return liveFormatter ? liveFormatter(value) : String(value)\n },\n },\n } as EChartsOption['yAxis'],\n tooltip: {\n ...baseTooltip,\n formatter: buildTimeseriesTooltipFormatter(\n liveFormatter,\n labelFormatter,\n ),\n },\n } as EChartsOption\n }\n}\n\n/**\n * Tooltip formatter for the timeseries `{ name, value }` row shape.\n * `name` arrives as `Date | number | string` (the time-axis stores the\n * raw value the consumer supplied). The consumer's `labelFormatter`\n * expects a `Date`, so we coerce non-Date values via `new Date(...)`\n * before invoking it.\n */\nfunction buildTimeseriesTooltipFormatter(\n formatter: ((value: number) => string) | undefined,\n labelFormatter: ((value: Date) => string) | undefined,\n) {\n return createTooltipFormatter((item) => {\n const row = item.value as\n | { name?: Date | number | string; value?: number }\n | undefined\n const raw = row?.value\n const formattedValue =\n typeof raw === 'number' && formatter ? formatter(raw) : (raw ?? '')\n const marker = typeof item.marker === 'string' ? item.marker : ''\n const seriesName = item.seriesName ? `${item.seriesName}: ` : ''\n const rawName = row?.name ?? item.name\n const name =\n labelFormatter && rawName != null\n ? labelFormatter(rawName instanceof Date ? rawName : new Date(rawName))\n : (rawName ?? '')\n return { name: String(name), seriesName, marker, value: formattedValue }\n })\n}\n","import { Box, Skeleton } from '@mui/material'\nimport type { SxProps, Theme } from '@mui/material'\n\nconst styles = {\n container: {\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'space-between',\n gap: ({ spacing }) => spacing(1),\n height: ({ spacing }) => spacing(38),\n },\n graph: {\n position: 'relative',\n flex: '1 1 auto',\n width: '100%',\n },\n segmentA: {\n position: 'absolute',\n left: 0,\n right: '70%',\n top: '60%',\n height: 4,\n },\n segmentB: {\n position: 'absolute',\n left: '25%',\n right: '40%',\n top: '35%',\n height: 4,\n },\n segmentC: {\n position: 'absolute',\n left: '55%',\n right: 0,\n top: '50%',\n height: 4,\n },\n legend: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(2),\n height: ({ spacing }) => spacing(5),\n },\n legendItem: {\n display: 'flex',\n alignItems: 'center',\n gap: ({ spacing }) => spacing(1.5),\n },\n} satisfies Record<string, SxProps<Theme>>\n\n/**\n * Loading state for the Timeseries widget. Mirrors a line chart's\n * silhouette — three thin horizontal segments at staggered offsets to\n * suggest a moving line, plus a 2-dot legend stub. Sibling-consistent\n * with Bar / Histogram / Scatter skeletons (column-flex container with\n * legend strip below).\n */\nexport function TimeseriesSkeleton() {\n return (\n <Box sx={styles.container}>\n <Box sx={styles.graph}>\n <Skeleton variant='rectangular' sx={styles.segmentA} />\n <Skeleton variant='rectangular' sx={styles.segmentB} />\n <Skeleton variant='rectangular' sx={styles.segmentC} />\n </Box>\n <Box sx={styles.legend}>\n {[0, 1].map((i) => (\n <Box key={`legend-${i}`} sx={styles.legendItem}>\n <Skeleton variant='circular' width={8} height={8} />\n <Skeleton width={48} height={8} />\n </Box>\n ))}\n </Box>\n </Box>\n )\n}\n","import {\n buildPngDownloadItem,\n downloadToCSV,\n type DownloadItem,\n} from '../actions/download'\nimport type { TimeseriesWidgetData } from './types'\n\n/**\n * Download menu items for the Timeseries widget. Always includes a CSV\n * item with `time, series_1, series_2, …` columns (one row per unique time\n * across all series; ISO-8601 strings for `Date`/numeric times). When\n * `getCaptureEl` is supplied, prepends a PNG item that rasterises the\n * captured element via `html2canvas`.\n */\nexport function createTimeseriesDownloadConfig(args: {\n filename: string\n getData: () => TimeseriesWidgetData\n seriesNames?: readonly string[]\n getCaptureEl?: () => HTMLElement | null\n pngPixelRatio?: number\n pngBackgroundColor?: string | null\n}): DownloadItem[] {\n const items: DownloadItem[] = []\n if (args.getCaptureEl) {\n items.push(\n buildPngDownloadItem({\n filename: args.filename,\n getCaptureEl: args.getCaptureEl,\n pixelRatio: args.pngPixelRatio,\n backgroundColor: args.pngBackgroundColor,\n }),\n )\n }\n items.push({\n id: 'csv',\n label: 'Download as CSV',\n resolve: () => {\n const data = args.getData()\n const seriesCount = data.length\n\n // Collect every unique time, preserving insertion order.\n const timeKeys: (Date | number | string)[] = []\n const seenKeys = new Set<string>()\n for (const series of data) {\n for (const point of series) {\n const key = String(point.name)\n if (!seenKeys.has(key)) {\n seenKeys.add(key)\n timeKeys.push(point.name)\n }\n }\n }\n\n // Build a quick lookup per series for O(rows × series) emit.\n const lookups = data.map(\n (series) => new Map(series.map((p) => [String(p.name), p.value])),\n )\n\n const header: unknown[] = ['time']\n for (let i = 0; i < seriesCount; i++) {\n header.push(args.seriesNames?.[i] ?? `series_${i + 1}`)\n }\n const rows: unknown[][] = [header]\n for (const key of timeKeys) {\n const row: unknown[] = [formatTime(key)]\n const lookupKey = String(key)\n for (const lookup of lookups) row.push(lookup.get(lookupKey) ?? '')\n rows.push(row)\n }\n\n const handle = downloadToCSV(rows)\n return Promise.resolve({\n url: handle.url,\n filename: `${args.filename}.csv`,\n revoke: handle.revoke,\n })\n },\n })\n return items\n}\n\nfunction formatTime(v: Date | number | string): string {\n if (v instanceof Date) return v.toISOString()\n if (typeof v === 'number') return new Date(v).toISOString()\n return v\n}\n"],"names":["timeseriesOptions","theme","formatter","labelFormatter","niceMin","niceMax","grid","left","parseInt","spacing","top","right","buildGridConfig","containLabel","tooltip","trigger","backgroundColor","palette","grey","borderWidth","padding","textStyle","color","common","white","fontSize","fontFamily","typography","caption","axisPointer","type","position","createTooltipPositioner","buildTimeseriesTooltipFormatter","legend","buildLegendConfig","hasLegend","lineStyle","secondary","main","Object","values","qualitative","bold","xAxis","axisLine","show","axisTick","axisLabel","margin","hideOverlap","value","Date","yAxis","min","extent","niceNum","max","splitLine","black","divider","overlineDelicate","showMaxLabel","showMinLabel","verticalAlign","inside","String","createTimeseriesOptionFactory","options","optionsOverride","series","smooth","area","selection","selectionSet","length","Set","normalizeName","n","getTime","option","data","ctx","structural","mergeOptions","seriesArr","Array","isArray","dataset","seriesTemplates","broadcastTemplate","baseYAxis","baseGrid","baseTooltip","baseLegend","liveFormatter","dataZoomLayout","positionDataZoomForLegend","dataZoom","fallbackBottom","bottom","baseBottom","gridBottom","ZOOM_LAYOUT","sliderHeight","sliderGap","dimItemStyle","params","raw","name","base","has","echarts","modifyAlpha","map","s","source","_","i","template","overrideColor","resolveThemeColor","datasetIndex","encode","x","y","showSymbol","areaStyle","emphasis","focus","itemStyle","createTooltipFormatter","item","row","formattedValue","marker","seriesName","rawName","styles","container","display","flexDirection","justifyContent","gap","height","graph","flex","width","segmentA","segmentB","segmentC","alignItems","legendItem","TimeseriesSkeleton","$","_c","t0","Symbol","for","jsxs","Box","jsx","Skeleton","t1","_temp","createTimeseriesDownloadConfig","args","items","getCaptureEl","push","buildPngDownloadItem","filename","pixelRatio","pngPixelRatio","pngBackgroundColor","id","label","resolve","getData","seriesCount","timeKeys","seenKeys","point","key","add","lookups","Map","p","header","seriesNames","rows","formatTime","lookupKey","lookup","get","handle","downloadToCSV","Promise","url","revoke","v","toISOString"],"mappings":"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"}
|
package/dist/widgets-v2.js
CHANGED
|
@@ -13,8 +13,8 @@ import "./lasso-tool-CDFj4zKY.js";
|
|
|
13
13
|
import "./cjs-D4KH3azB.js";
|
|
14
14
|
import { T as Xe } from "./tooltip-BDnrRKrp.js";
|
|
15
15
|
import "@carto/ps-utils";
|
|
16
|
-
import { o as Ze, a as Ke, E as Ye } from "./echart-
|
|
17
|
-
import { D as Wn } from "./echart-
|
|
16
|
+
import { o as Ze, a as Ke, E as Ye } from "./echart-BMPpj7n_.js";
|
|
17
|
+
import { D as Wn } from "./echart-BMPpj7n_.js";
|
|
18
18
|
import { a as Je, b as Qe, M as et } from "./markdown-BD1jcknS.js";
|
|
19
19
|
import { C as tt, L as nt, F as ot, j as rt, R as it, B as lt, Z as st, m as at, n as ct, l as dt, k as pt } from "./change-column-DjjwoPt1.js";
|
|
20
20
|
import "html2canvas";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carto/ps-react-ui",
|
|
3
|
-
"version": "4.11.
|
|
3
|
+
"version": "4.11.2",
|
|
4
4
|
"description": "CARTO's Professional Service React Material library",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"devDependencies": {
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"react-dom": "19.2.4",
|
|
18
18
|
"react-markdown": "10.1.0",
|
|
19
19
|
"zustand": "5.0.12",
|
|
20
|
-
"@carto/ps-
|
|
21
|
-
"@carto/ps-
|
|
20
|
+
"@carto/ps-utils": "2.0.1",
|
|
21
|
+
"@carto/ps-common-types": "1.0.0"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
24
|
"@carto/meridian-ds": "^2.0.0",
|
|
@@ -218,19 +218,46 @@ describe('createBarOptionFactory', () => {
|
|
|
218
218
|
{ formatter: fmt },
|
|
219
219
|
) as {
|
|
220
220
|
yAxis: {
|
|
221
|
-
min: number
|
|
222
|
-
max: number
|
|
221
|
+
min: (extent: { min: number }) => number
|
|
222
|
+
max: (extent: { min: number; max: number }) => number
|
|
223
223
|
axisLabel: { formatter: (v: number) => string }
|
|
224
224
|
}
|
|
225
225
|
}
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
// Bounds are callbacks now: ECharts supplies the (post-stack) extent and
|
|
227
|
+
// we round it with niceNum. Invoke them as ECharts would before reading
|
|
228
|
+
// the label formatter (which keys off the closure-cached extents).
|
|
229
|
+
expect(typeof out.yAxis.min).toBe('function')
|
|
230
|
+
expect(typeof out.yAxis.max).toBe('function')
|
|
231
|
+
expect(out.yAxis.min({ min: 0 })).toBe(0)
|
|
232
|
+
expect(out.yAxis.max({ min: 0, max: 100 })).toBe(100)
|
|
228
233
|
expect(out.yAxis.axisLabel.formatter(100)).toBe('100%')
|
|
229
234
|
// Intermediate values are still suppressed.
|
|
230
235
|
expect(out.yAxis.axisLabel.formatter(50)).toBe('')
|
|
231
236
|
expect(out.yAxis.axisLabel.formatter(0)).toBe('')
|
|
232
237
|
})
|
|
233
238
|
|
|
239
|
+
it('rounds the ECharts-supplied (stacked) extent so stacked bars cannot overflow', () => {
|
|
240
|
+
// Regression: previously the merge phase precomputed the y-axis max from
|
|
241
|
+
// the largest *single* series value, so stacking (StackToggle →
|
|
242
|
+
// { stack: 'total' }) made the summed bars overflow the axis. The bound
|
|
243
|
+
// is now a callback: ECharts computes the extent AFTER stacking and we
|
|
244
|
+
// round that. Two series of 600 stack to 1200; ECharts hands us that
|
|
245
|
+
// extent and niceNum(1200) → 2000 contains it (vs. the old 600).
|
|
246
|
+
const merge = createBarOptionFactory({ theme })
|
|
247
|
+
const out = merge({ series: [{ stack: 'total' }] }, [
|
|
248
|
+
[{ name: 'A', value: 600 }],
|
|
249
|
+
[{ name: 'A', value: 600 }],
|
|
250
|
+
]) as {
|
|
251
|
+
yAxis: {
|
|
252
|
+
min: (extent: { min: number }) => number
|
|
253
|
+
max: (extent: { min: number; max: number }) => number
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
expect(typeof out.yAxis.max).toBe('function')
|
|
257
|
+
expect(out.yAxis.max({ min: 0, max: 1200 })).toBe(2000)
|
|
258
|
+
expect(out.yAxis.min({ min: 0 })).toBe(0)
|
|
259
|
+
})
|
|
260
|
+
|
|
234
261
|
it('reserves grid bottom space for the zoom slider when dataZoom is present', () => {
|
|
235
262
|
const merge = createBarOptionFactory({ theme })
|
|
236
263
|
// Single series, no legend.
|