@vuu-ui/vuu-chart 4.0.0-alpha.21 → 4.0.0-alpha.22

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 (45) hide show
  1. package/README.md +324 -0
  2. package/package.json +12 -15
  3. package/src/Chart.css.js +22 -0
  4. package/src/Chart.js +4 -4
  5. package/src/ChartSeries.js +20 -3
  6. package/src/chart-data/ChartDataStore.js +131 -0
  7. package/src/chart-data/projection-utils.js +119 -0
  8. package/src/charts/CandlestickChart.js +31 -0
  9. package/src/charts/CartesianChart.js +28 -0
  10. package/src/charts/DepthChart.js +28 -0
  11. package/src/charts/HeatmapChart.js +31 -0
  12. package/src/charts/HierarchyChart.js +41 -0
  13. package/src/charts/candlestick-model.js +373 -0
  14. package/src/charts/cartesian-model.js +234 -0
  15. package/src/charts/depth-model.js +159 -0
  16. package/src/charts/heatmap-model.js +243 -0
  17. package/src/charts/hierarchy-model.js +224 -0
  18. package/src/echarts.js +26 -0
  19. package/src/engine/ChartModel.js +2 -0
  20. package/src/engine/VuuChartContainer.js +196 -0
  21. package/src/engine/useStructuralMemo.js +18 -0
  22. package/src/index.js +8 -0
  23. package/src/options/common.js +181 -0
  24. package/src/options/mergeOptions.js +37 -0
  25. package/src/theme/chartTheme.js +74 -0
  26. package/src/useChartOptions.js +25 -2
  27. package/src/vuu-chart-types.js +0 -0
  28. package/types/Chart.d.ts +0 -28
  29. package/types/ChartSeries.d.ts +0 -32
  30. package/types/DataRowMovingWindow.d.ts +0 -23
  31. package/types/chart-types.d.ts +0 -42
  32. package/types/chartTooltip.d.ts +0 -12
  33. package/types/index.d.ts +0 -5
  34. package/types/src/Chart.d.ts +0 -28
  35. package/types/src/ChartSeries.d.ts +0 -32
  36. package/types/src/DataRowMovingWindow.d.ts +0 -23
  37. package/types/src/chart-types.d.ts +0 -42
  38. package/types/src/chartTooltip.d.ts +0 -12
  39. package/types/src/index.d.ts +0 -5
  40. package/types/src/useChartContextMenu.d.ts +0 -16
  41. package/types/src/useChartOptions.d.ts +0 -28
  42. package/types/src/useChartSelection.d.ts +0 -14
  43. package/types/useChartContextMenu.d.ts +0 -16
  44. package/types/useChartOptions.d.ts +0 -28
  45. package/types/useChartSelection.d.ts +0 -14
@@ -0,0 +1,224 @@
1
+ import { Aggregator, filterRows, getColumnValue, getNumber } from "../chart-data/projection-utils.js";
2
+ import { GROUP_KEY_SEPARATOR } from "../engine/ChartModel.js";
3
+ import { legendOption, textStyle, tooltipOption } from "../options/common.js";
4
+ const defaultFormatValue = (value)=>Math.abs(value) >= 1000 ? value.toLocaleString(void 0, {
5
+ maximumFractionDigits: 0
6
+ }) : value.toLocaleString(void 0, {
7
+ maximumFractionDigits: 2
8
+ });
9
+ const buildHierarchy = (rows, getGroupValue, getValue, depth, aggregation)=>{
10
+ const root = new Map();
11
+ for (const row of rows){
12
+ const value = getValue(row);
13
+ let level = root;
14
+ let key = "";
15
+ for(let d = 0; d < depth; d++){
16
+ const name = String(getGroupValue(row, d) ?? "");
17
+ key = 0 === d ? name : `${key}${GROUP_KEY_SEPARATOR}${name}`;
18
+ let group = level.get(name);
19
+ if (void 0 === group) {
20
+ group = {
21
+ name,
22
+ key,
23
+ aggregator: new Aggregator(aggregation),
24
+ rows: [],
25
+ children: d < depth - 1 ? new Map() : void 0
26
+ };
27
+ level.set(name, group);
28
+ }
29
+ group.aggregator.add(value);
30
+ group.rows.push(row);
31
+ if (group.children) level = group.children;
32
+ }
33
+ }
34
+ return Array.from(root.values());
35
+ };
36
+ const createHierarchyModel = ({ aggregation = "sum", colorMode = "palette", dataSource, donut = false, formatValue = defaultFormatValue, groupByColumnNames, legend = "none", showTooltip = true, type, valueColumnName, where })=>{
37
+ const depth = "pie" === type ? 1 : Math.max(1, groupByColumnNames.length);
38
+ const seriesId = type;
39
+ const tooltipFormatter = (params)=>{
40
+ const node = params.data;
41
+ if (!node) return params.name;
42
+ const path = node.vuuGroupKey.split(GROUP_KEY_SEPARATOR).join(" / ");
43
+ const percent = void 0 !== params.percent ? ` (${params.percent.toFixed(1)}%)` : "";
44
+ return `${path}<br/>${valueColumnName}: <b>${formatValue(node.signedValue)}</b>${percent}`;
45
+ };
46
+ const buildBaseOption = (theme)=>{
47
+ const labelStyle = {
48
+ color: theme.foregroundColor,
49
+ fontFamily: theme.fontFamily
50
+ };
51
+ const seriesBase = {
52
+ id: seriesId,
53
+ name: valueColumnName,
54
+ type,
55
+ data: []
56
+ };
57
+ let series;
58
+ series = "treemap" === type ? {
59
+ ...seriesBase,
60
+ roam: false,
61
+ nodeClick: "zoomToNode",
62
+ top: 8,
63
+ left: 0,
64
+ right: 0,
65
+ bottom: 28,
66
+ visibleMin: 100,
67
+ breadcrumb: {
68
+ show: depth > 1,
69
+ height: 20,
70
+ bottom: 4,
71
+ itemStyle: {
72
+ color: theme.tooltipBackgroundColor,
73
+ borderColor: theme.axisLineColor,
74
+ textStyle: {
75
+ color: theme.foregroundColor
76
+ }
77
+ }
78
+ },
79
+ label: {
80
+ show: true,
81
+ ...labelStyle,
82
+ color: "#fff",
83
+ formatter: (p)=>p.data ? `${p.name}\n${formatValue(p.data.signedValue)}` : p.name
84
+ },
85
+ upperLabel: {
86
+ show: depth > 1,
87
+ height: 18,
88
+ color: "#fff"
89
+ },
90
+ itemStyle: {
91
+ borderColor: theme.backgroundColor,
92
+ gapWidth: 1
93
+ },
94
+ levels: [
95
+ {
96
+ itemStyle: {
97
+ borderColor: theme.backgroundColor,
98
+ borderWidth: 0,
99
+ gapWidth: 2
100
+ },
101
+ upperLabel: {
102
+ show: false
103
+ }
104
+ },
105
+ {
106
+ itemStyle: {
107
+ borderColor: theme.splitLineColor,
108
+ borderWidth: 2,
109
+ gapWidth: 1
110
+ }
111
+ }
112
+ ]
113
+ } : "sunburst" === type ? {
114
+ ...seriesBase,
115
+ radius: [
116
+ "12%",
117
+ "95%"
118
+ ],
119
+ sort: "desc",
120
+ nodeClick: "rootToNode",
121
+ label: {
122
+ ...labelStyle,
123
+ rotate: "radial",
124
+ minAngle: 8,
125
+ color: "#fff"
126
+ },
127
+ itemStyle: {
128
+ borderColor: theme.backgroundColor,
129
+ borderWidth: 1
130
+ }
131
+ } : {
132
+ ...seriesBase,
133
+ radius: donut ? [
134
+ "45%",
135
+ "75%"
136
+ ] : "75%",
137
+ center: [
138
+ "50%",
139
+ "52%"
140
+ ],
141
+ label: {
142
+ ...labelStyle,
143
+ formatter: "{b}: {d}%"
144
+ },
145
+ labelLine: {
146
+ lineStyle: {
147
+ color: theme.axisLineColor
148
+ }
149
+ },
150
+ itemStyle: {
151
+ borderColor: theme.backgroundColor,
152
+ borderWidth: 1
153
+ }
154
+ };
155
+ return {
156
+ animation: false,
157
+ backgroundColor: theme.backgroundColor,
158
+ color: theme.palette,
159
+ textStyle: textStyle(theme),
160
+ legend: legendOption(theme, "pie" === type ? legend : "none"),
161
+ tooltip: {
162
+ ...tooltipOption(theme, {
163
+ show: showTooltip,
164
+ trigger: "item"
165
+ }),
166
+ formatter: tooltipFormatter
167
+ },
168
+ series: [
169
+ series
170
+ ]
171
+ };
172
+ };
173
+ const buildDataOption = (data, theme)=>{
174
+ const { columnMap, rows: allRows } = data.get(dataSource);
175
+ const rows = filterRows(allRows, columnMap, where);
176
+ const groups = buildHierarchy(rows, (row, d)=>getColumnValue(row, columnMap, groupByColumnNames[d]), (row)=>getNumber(row, columnMap, valueColumnName), depth, aggregation);
177
+ const groupRows = new Map();
178
+ const toNode = (group)=>{
179
+ groupRows.set(group.key, group.rows);
180
+ const signedValue = group.aggregator.value ?? 0;
181
+ const node = {
182
+ name: group.name,
183
+ value: "sign" === colorMode ? Math.abs(signedValue) : signedValue,
184
+ signedValue,
185
+ vuuGroupKey: group.key
186
+ };
187
+ if ("sign" === colorMode) node.itemStyle = {
188
+ color: signedValue < 0 ? theme.downColor : theme.upColor
189
+ };
190
+ if (group.children) {
191
+ node.children = Array.from(group.children.values()).map(toNode);
192
+ node.value = node.children.reduce((sum, child)=>sum + child.value, 0);
193
+ }
194
+ return node;
195
+ };
196
+ const nodes = groups.map(toNode).sort((n1, n2)=>Math.abs(n2.value) - Math.abs(n1.value));
197
+ const rowLookup = {
198
+ [seriesId]: {
199
+ dataSource,
200
+ rows: [],
201
+ groups: groupRows
202
+ }
203
+ };
204
+ return {
205
+ option: {
206
+ series: [
207
+ {
208
+ id: seriesId,
209
+ data: nodes
210
+ }
211
+ ]
212
+ },
213
+ rowLookup
214
+ };
215
+ };
216
+ return {
217
+ buildBaseOption,
218
+ buildDataOption,
219
+ dataSources: [
220
+ dataSource
221
+ ]
222
+ };
223
+ };
224
+ export { buildHierarchy, createHierarchyModel };
package/src/echarts.js ADDED
@@ -0,0 +1,26 @@
1
+ import { BarChart, CandlestickChart, HeatmapChart, LineChart, PieChart, ScatterChart, SunburstChart, TreemapChart } from "echarts/charts";
2
+ import { AxisPointerComponent, DataZoomInsideComponent, DataZoomSliderComponent, GridComponent, LegendComponent, MarkLineComponent, TitleComponent, TooltipComponent, VisualMapContinuousComponent } from "echarts/components";
3
+ import { getInstanceByDom, init, use } from "echarts/core";
4
+ import { CanvasRenderer, SVGRenderer } from "echarts/renderers";
5
+ use([
6
+ BarChart,
7
+ CandlestickChart,
8
+ HeatmapChart,
9
+ LineChart,
10
+ PieChart,
11
+ ScatterChart,
12
+ SunburstChart,
13
+ TreemapChart,
14
+ AxisPointerComponent,
15
+ DataZoomInsideComponent,
16
+ DataZoomSliderComponent,
17
+ GridComponent,
18
+ LegendComponent,
19
+ MarkLineComponent,
20
+ TitleComponent,
21
+ TooltipComponent,
22
+ VisualMapContinuousComponent,
23
+ CanvasRenderer,
24
+ SVGRenderer
25
+ ]);
26
+ export { getInstanceByDom, init };
@@ -0,0 +1,2 @@
1
+ const GROUP_KEY_SEPARATOR = "\u001f";
2
+ export { GROUP_KEY_SEPARATOR };
@@ -0,0 +1,196 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useComponentCssInjection } from "@salt-ds/styles";
3
+ import { useWindow } from "@salt-ds/window";
4
+ import { MeasuredContainer } from "@vuu-ui/vuu-ui-controls";
5
+ import { ThemeContext } from "@vuu-ui/vuu-utils";
6
+ import clsx from "clsx";
7
+ import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
8
+ import { ChartDataStores } from "../chart-data/ChartDataStore.js";
9
+ import { init } from "../echarts.js";
10
+ import { mergeEChartsOptions } from "../options/mergeOptions.js";
11
+ import { resolveChartTheme } from "../theme/chartTheme.js";
12
+ import { GROUP_KEY_SEPARATOR } from "./ChartModel.js";
13
+ import { useStructuralMemo } from "./useStructuralMemo.js";
14
+ import Chart from "../Chart.css";
15
+ const classBase = "vuuChart";
16
+ const applyOverride = (option, override)=>"function" == typeof override ? override(option) : mergeEChartsOptions(option, override);
17
+ const VuuChartContainer = ({ chartType, className, echartsOptions, height, legend: _legend, maxRows, model, onChartReady, onItemClick, onItemContextMenu, renderer = "canvas", resizeStrategy, showTooltip: _showTooltip, style = {
18
+ width: "100%",
19
+ height: "100%"
20
+ }, theme: themeOverrides, width, ...htmlAttributes })=>{
21
+ const targetWindow = useWindow();
22
+ useComponentCssInjection({
23
+ testId: "vuu-chart",
24
+ css: Chart,
25
+ window: targetWindow
26
+ });
27
+ const { themeMode } = useContext(ThemeContext);
28
+ const [chartElement, setChartElement] = useState(null);
29
+ const [chart, setChart] = useState(void 0);
30
+ const overrides = useStructuralMemo(themeOverrides);
31
+ const userOptions = useStructuralMemo(echartsOptions);
32
+ const dataSources = useStructuralMemo(model.dataSources);
33
+ const theme = useMemo(()=>resolveChartTheme(chartElement, overrides), [
34
+ chartElement,
35
+ overrides,
36
+ themeMode
37
+ ]);
38
+ const modelRef = useRef(model);
39
+ modelRef.current = model;
40
+ const themeRef = useRef(theme);
41
+ themeRef.current = theme;
42
+ const storesRef = useRef(void 0);
43
+ const rowLookupRef = useRef({});
44
+ const frameRef = useRef(void 0);
45
+ const handlersRef = useRef({
46
+ onItemClick,
47
+ onItemContextMenu
48
+ });
49
+ handlersRef.current = {
50
+ onItemClick,
51
+ onItemContextMenu
52
+ };
53
+ const onChartReadyRef = useRef(onChartReady);
54
+ onChartReadyRef.current = onChartReady;
55
+ useLayoutEffect(()=>{
56
+ if (!chartElement) return;
57
+ const echart = init(chartElement, null, {
58
+ renderer,
59
+ useCoarsePointer: true
60
+ });
61
+ const toItemEvent = (params)=>{
62
+ const seriesId = params.seriesId ?? "";
63
+ const lookup = rowLookupRef.current[seriesId];
64
+ if (lookup) {
65
+ const store = storesRef.current?.get(lookup.dataSource);
66
+ const groupKey = params.data?.vuuGroupKey;
67
+ const groupRows = void 0 !== groupKey ? lookup.groups?.get(groupKey) : void 0;
68
+ return {
69
+ columnMap: store?.columnMap ?? {},
70
+ dataIndex: params.dataIndex,
71
+ dataSource: lookup.dataSource,
72
+ groupPath: groupKey?.split(GROUP_KEY_SEPARATOR),
73
+ nativeEvent: params.event?.event,
74
+ row: groupRows ? groupRows[0] : lookup.rows[params.dataIndex],
75
+ rows: groupRows,
76
+ seriesId,
77
+ seriesName: params.seriesName ?? "",
78
+ value: params.value
79
+ };
80
+ }
81
+ };
82
+ echart.on("click", (params)=>{
83
+ const { onItemClick } = handlersRef.current;
84
+ const evt = onItemClick && toItemEvent(params);
85
+ if (evt) onItemClick?.(evt);
86
+ });
87
+ echart.on("contextmenu", (params)=>{
88
+ const { onItemContextMenu } = handlersRef.current;
89
+ const evt = onItemContextMenu && toItemEvent(params);
90
+ if (evt) {
91
+ params.event?.stop();
92
+ onItemContextMenu?.(evt);
93
+ }
94
+ });
95
+ setChart(echart);
96
+ onChartReadyRef.current?.(echart);
97
+ return ()=>{
98
+ setChart(void 0);
99
+ echart.dispose();
100
+ };
101
+ }, [
102
+ chartElement,
103
+ renderer
104
+ ]);
105
+ const buildFullOption = useCallback(()=>{
106
+ const stores = storesRef.current;
107
+ if (chart && !chart.isDisposed() && stores) {
108
+ const { buildBaseOption, buildDataOption } = modelRef.current;
109
+ const theme = themeRef.current;
110
+ const { option: dataOption, rowLookup = {} } = buildDataOption(stores, theme);
111
+ const option = applyOverride(mergeEChartsOptions(buildBaseOption(theme), dataOption), userOptions);
112
+ rowLookupRef.current = rowLookup;
113
+ chart.setOption(option, {
114
+ notMerge: true
115
+ });
116
+ }
117
+ }, [
118
+ chart,
119
+ userOptions
120
+ ]);
121
+ const applyDataUpdate = useCallback(()=>{
122
+ frameRef.current = void 0;
123
+ const stores = storesRef.current;
124
+ if (chart && !chart.isDisposed() && stores) {
125
+ const { option, rowLookup = {} } = modelRef.current.buildDataOption(stores, themeRef.current);
126
+ rowLookupRef.current = rowLookup;
127
+ chart.setOption(option, {
128
+ lazyUpdate: false,
129
+ silent: true
130
+ });
131
+ }
132
+ }, [
133
+ chart
134
+ ]);
135
+ const scheduleDataUpdate = useCallback(()=>{
136
+ if (void 0 === frameRef.current) frameRef.current = requestAnimationFrame(applyDataUpdate);
137
+ }, [
138
+ applyDataUpdate
139
+ ]);
140
+ useEffect(()=>{
141
+ if (!chart) return;
142
+ const stores = new ChartDataStores(dataSources, {
143
+ maxRows
144
+ }, scheduleDataUpdate);
145
+ storesRef.current = stores;
146
+ stores.subscribe();
147
+ return ()=>{
148
+ if (void 0 !== frameRef.current) {
149
+ cancelAnimationFrame(frameRef.current);
150
+ frameRef.current = void 0;
151
+ }
152
+ stores.dispose();
153
+ storesRef.current = void 0;
154
+ };
155
+ }, [
156
+ chart,
157
+ dataSources,
158
+ maxRows,
159
+ scheduleDataUpdate
160
+ ]);
161
+ useEffect(()=>{
162
+ buildFullOption();
163
+ }, [
164
+ buildFullOption,
165
+ dataSources,
166
+ maxRows,
167
+ model,
168
+ theme
169
+ ]);
170
+ const onResize = useCallback((size)=>{
171
+ chart?.resize({
172
+ height: size.height,
173
+ width: size.width
174
+ });
175
+ }, [
176
+ chart
177
+ ]);
178
+ return /*#__PURE__*/ jsx(MeasuredContainer, {
179
+ ...htmlAttributes,
180
+ className: clsx(classBase, `${classBase}-${chartType}`, className),
181
+ height: height,
182
+ onResize: onResize,
183
+ resizeStrategy: resizeStrategy,
184
+ style: style,
185
+ width: width,
186
+ children: /*#__PURE__*/ jsx("div", {
187
+ className: `${classBase}-canvas`,
188
+ ref: setChartElement,
189
+ style: {
190
+ height: "100%",
191
+ width: "100%"
192
+ }
193
+ })
194
+ });
195
+ };
196
+ export { VuuChartContainer };
@@ -0,0 +1,18 @@
1
+ import { useRef } from "react";
2
+ const isPlainObject = (value)=>null !== value && "object" == typeof value && (Object.getPrototypeOf(value) === Object.prototype || null === Object.getPrototypeOf(value));
3
+ const isStructurallyEqual = (a, b)=>{
4
+ if (a === b) return true;
5
+ if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((v, i)=>isStructurallyEqual(v, b[i]));
6
+ if (isPlainObject(a) && isPlainObject(b)) {
7
+ const keysA = Object.keys(a);
8
+ const keysB = Object.keys(b);
9
+ return keysA.length === keysB.length && keysA.every((key)=>isStructurallyEqual(a[key], b[key]));
10
+ }
11
+ return false;
12
+ };
13
+ const useStructuralMemo = (value)=>{
14
+ const ref = useRef(value);
15
+ if (!isStructurallyEqual(ref.current, value)) ref.current = value;
16
+ return ref.current;
17
+ };
18
+ export { isStructurallyEqual, useStructuralMemo };
package/src/index.js CHANGED
@@ -1,2 +1,10 @@
1
1
  export { Chart } from "./Chart.js";
2
2
  export { ChartSeries } from "./ChartSeries.js";
3
+ export { CandlestickChart } from "./charts/CandlestickChart.js";
4
+ export { CartesianChart } from "./charts/CartesianChart.js";
5
+ export { DepthChart } from "./charts/DepthChart.js";
6
+ export { HeatmapChart } from "./charts/HeatmapChart.js";
7
+ export { HierarchyChart, PieChart, SunburstChart, TreemapChart } from "./charts/HierarchyChart.js";
8
+ export { ChartDataStore } from "./chart-data/ChartDataStore.js";
9
+ export { mergeEChartsOptions } from "./options/mergeOptions.js";
10
+ export { defaultChartTheme, resolveChartTheme } from "./theme/chartTheme.js";
@@ -0,0 +1,181 @@
1
+ import { resolveColor } from "../theme/chartTheme.js";
2
+ import { computeMarkLineValue } from "../chart-data/projection-utils.js";
3
+ const pad = (n, width = 2)=>String(n).padStart(width, "0");
4
+ const formatTimeLabel = (ts)=>{
5
+ if (!Number.isFinite(ts)) return "";
6
+ const d = new Date(ts);
7
+ const h = d.getHours();
8
+ const m = d.getMinutes();
9
+ const s = d.getSeconds();
10
+ if (0 === h && 0 === m && 0 === s) return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
11
+ return 0 === s ? `${pad(h)}:${pad(m)}` : `${pad(h)}:${pad(m)}:${pad(s)}`;
12
+ };
13
+ const formatTimestamp = (ts)=>{
14
+ if (!Number.isFinite(ts)) return "";
15
+ const d = new Date(ts);
16
+ return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
17
+ };
18
+ const textStyle = (theme)=>({
19
+ color: theme.foregroundColor,
20
+ fontFamily: theme.fontFamily
21
+ });
22
+ const GRID_OUTER_BOUNDS = {
23
+ left: 4,
24
+ right: 12,
25
+ top: 0,
26
+ bottom: 0
27
+ };
28
+ const axisStyle = (theme, showSplitLine = true)=>({
29
+ axisLine: {
30
+ lineStyle: {
31
+ color: theme.axisLineColor
32
+ }
33
+ },
34
+ axisTick: {
35
+ lineStyle: {
36
+ color: theme.axisLineColor
37
+ }
38
+ },
39
+ axisLabel: {
40
+ color: theme.secondaryForegroundColor,
41
+ fontFamily: theme.fontFamily,
42
+ hideOverlap: true
43
+ },
44
+ nameTextStyle: {
45
+ color: theme.secondaryForegroundColor,
46
+ fontFamily: theme.fontFamily
47
+ },
48
+ splitLine: {
49
+ show: showSplitLine,
50
+ lineStyle: {
51
+ color: theme.splitLineColor
52
+ }
53
+ }
54
+ });
55
+ const axisPointerLabel = (theme)=>({
56
+ backgroundColor: theme.crosshairColor,
57
+ color: theme.tooltipBackgroundColor,
58
+ fontFamily: theme.fontFamily
59
+ });
60
+ const tooltipOption = (theme, { crosshair = true, show = true, trigger = "axis" } = {})=>({
61
+ show,
62
+ trigger,
63
+ confine: true,
64
+ className: "vuuChartTooltip",
65
+ backgroundColor: theme.tooltipBackgroundColor,
66
+ borderColor: theme.tooltipBorderColor,
67
+ textStyle: {
68
+ ...textStyle(theme),
69
+ fontSize: 12
70
+ },
71
+ axisPointer: "axis" === trigger ? {
72
+ type: crosshair ? "cross" : "line",
73
+ lineStyle: {
74
+ color: theme.crosshairColor,
75
+ type: "dashed"
76
+ },
77
+ crossStyle: {
78
+ color: theme.crosshairColor
79
+ },
80
+ label: axisPointerLabel(theme)
81
+ } : void 0
82
+ });
83
+ const legendOption = (theme, position)=>"none" === position ? {
84
+ show: false
85
+ } : {
86
+ show: true,
87
+ type: "scroll",
88
+ [position]: 0,
89
+ textStyle: {
90
+ color: theme.secondaryForegroundColor,
91
+ fontFamily: theme.fontFamily
92
+ },
93
+ pageTextStyle: {
94
+ color: theme.secondaryForegroundColor
95
+ }
96
+ };
97
+ const hasSlider = (dataZoom)=>"slider" === dataZoom || "both" === dataZoom;
98
+ const dataZoomOption = (dataZoom, theme, axisIndex = [
99
+ 0
100
+ ], orientation = "x")=>{
101
+ if (!dataZoom) return [];
102
+ const axisKey = "x" === orientation ? "xAxisIndex" : "yAxisIndex";
103
+ const zoom = [];
104
+ if (true === dataZoom || "inside" === dataZoom || "both" === dataZoom) zoom.push({
105
+ id: "zoom-inside",
106
+ type: "inside",
107
+ [axisKey]: axisIndex,
108
+ filterMode: "filter"
109
+ });
110
+ if (hasSlider(dataZoom)) zoom.push({
111
+ id: "zoom-slider",
112
+ type: "slider",
113
+ [axisKey]: axisIndex,
114
+ height: 20,
115
+ bottom: 4,
116
+ borderColor: theme.axisLineColor,
117
+ backgroundColor: "transparent",
118
+ fillerColor: "rgba(127,127,127,0.15)",
119
+ dataBackground: {
120
+ lineStyle: {
121
+ color: theme.axisLineColor
122
+ },
123
+ areaStyle: {
124
+ color: theme.splitLineColor
125
+ }
126
+ },
127
+ handleStyle: {
128
+ color: theme.tooltipBackgroundColor,
129
+ borderColor: theme.axisLineColor
130
+ },
131
+ moveHandleStyle: {
132
+ color: theme.axisLineColor
133
+ },
134
+ textStyle: {
135
+ color: theme.secondaryForegroundColor
136
+ },
137
+ filterMode: "filter"
138
+ });
139
+ return zoom;
140
+ };
141
+ const formatMarkLineValue = (value)=>Math.abs(value) >= 1000 ? value.toFixed(0) : Number(value.toPrecision(6)).toString();
142
+ const markLineOption = (defs, theme, values, { axis = "yAxis", defaultColor, weights } = {})=>{
143
+ if (!defs || 0 === defs.length) return;
144
+ const data = [];
145
+ for (const def of defs){
146
+ const value = computeMarkLineValue(def, values, weights);
147
+ if (null !== value) {
148
+ const color = resolveColor(def.color, theme) ?? defaultColor ?? theme.crosshairColor;
149
+ data.push({
150
+ name: def.label ?? "",
151
+ [axis]: value,
152
+ lineStyle: {
153
+ color,
154
+ type: def.lineType ?? "dashed",
155
+ width: 1
156
+ },
157
+ label: {
158
+ color: theme.tooltipBackgroundColor,
159
+ backgroundColor: color,
160
+ padding: [
161
+ 2,
162
+ 4
163
+ ],
164
+ borderRadius: 2,
165
+ position: def.labelPosition ?? "insideEndTop",
166
+ formatter: def.label ? `${def.label} ${formatMarkLineValue(value)}` : formatMarkLineValue(value)
167
+ }
168
+ });
169
+ }
170
+ }
171
+ return {
172
+ silent: true,
173
+ symbol: [
174
+ "none",
175
+ "none"
176
+ ],
177
+ animation: false,
178
+ data
179
+ };
180
+ };
181
+ export { GRID_OUTER_BOUNDS, axisPointerLabel, axisStyle, dataZoomOption, formatTimeLabel, formatTimestamp, hasSlider, legendOption, markLineOption, textStyle, tooltipOption };