@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,119 @@
1
+ import { resolveColor } from "../theme/chartTheme.js";
2
+ const toNumber = (value)=>{
3
+ if ("number" == typeof value) return Number.isFinite(value) ? value : null;
4
+ if ("bigint" == typeof value) return Number(value);
5
+ if ("string" == typeof value && "" !== value.trim()) {
6
+ const n = Number(value);
7
+ return Number.isFinite(n) ? n : null;
8
+ }
9
+ return null;
10
+ };
11
+ const getColumnValue = (row, columnMap, columnName)=>{
12
+ const index = columnMap[columnName];
13
+ return void 0 === index ? void 0 : row[index];
14
+ };
15
+ const getNumber = (row, columnMap, columnName)=>toNumber(getColumnValue(row, columnMap, columnName));
16
+ const filterRows = (rows, columnMap, where)=>{
17
+ if (void 0 === where) return rows;
18
+ {
19
+ if ("function" == typeof where) return rows.filter((row)=>where(row, columnMap));
20
+ const entries = Object.entries(where);
21
+ return rows.filter((row)=>entries.every(([columnName, value])=>getColumnValue(row, columnMap, columnName) === value));
22
+ }
23
+ };
24
+ const sortRowsByNumber = (rows, columnMap, columnName, descending = false)=>{
25
+ const index = columnMap[columnName];
26
+ if (void 0 === index) return rows;
27
+ const value = (row)=>toNumber(row[index]) ?? 0;
28
+ const dir = descending ? -1 : 1;
29
+ let sorted = true;
30
+ for(let i = 1; i < rows.length; i++)if (dir * (value(rows[i]) - value(rows[i - 1])) < 0) {
31
+ sorted = false;
32
+ break;
33
+ }
34
+ return sorted ? rows : rows.slice().sort((r1, r2)=>dir * (value(r1) - value(r2)));
35
+ };
36
+ const colorForRow = (row, columnMap, colorBy, theme)=>{
37
+ const value = getColumnValue(row, columnMap, colorBy.columnName);
38
+ const color = colorBy.colors[String(value)] ?? colorBy.defaultColor;
39
+ return resolveColor(color, theme);
40
+ };
41
+ class Aggregator {
42
+ #aggregation;
43
+ count = 0;
44
+ #value = null;
45
+ constructor(aggregation){
46
+ this.#aggregation = aggregation;
47
+ }
48
+ add(value) {
49
+ if ("count" === this.#aggregation) {
50
+ this.count += 1;
51
+ return;
52
+ }
53
+ if (null === value) return;
54
+ this.count += 1;
55
+ const current = this.#value;
56
+ switch(this.#aggregation){
57
+ case "sum":
58
+ case "avg":
59
+ this.#value = (current ?? 0) + value;
60
+ break;
61
+ case "min":
62
+ this.#value = null === current ? value : Math.min(current, value);
63
+ break;
64
+ case "max":
65
+ this.#value = null === current ? value : Math.max(current, value);
66
+ break;
67
+ case "last":
68
+ this.#value = value;
69
+ break;
70
+ }
71
+ }
72
+ get value() {
73
+ switch(this.#aggregation){
74
+ case "count":
75
+ return this.count;
76
+ case "avg":
77
+ return null === this.#value ? null : this.#value / this.count;
78
+ default:
79
+ return this.#value;
80
+ }
81
+ }
82
+ }
83
+ const computeMarkLineValue = (def, values, weights)=>{
84
+ const { value } = def;
85
+ if ("number" == typeof value) return value;
86
+ const nums = values.filter((v)=>null !== v);
87
+ if (0 === nums.length) return null;
88
+ if ("last" === value) return nums[nums.length - 1];
89
+ if ("min" === value) return Math.min(...nums);
90
+ if ("max" === value) return Math.max(...nums);
91
+ if ("average" === value) return nums.reduce((s, n)=>s + n, 0) / nums.length;
92
+ if (weights) {
93
+ let total = 0;
94
+ let totalWeight = 0;
95
+ values.forEach((v, i)=>{
96
+ const w = weights[i];
97
+ if (null !== v && null != w) {
98
+ total += v * Math.abs(w);
99
+ totalWeight += Math.abs(w);
100
+ }
101
+ });
102
+ return 0 === totalWeight ? null : total / totalWeight;
103
+ }
104
+ return null;
105
+ };
106
+ const findFloorIndex = (sortedValues, target)=>{
107
+ let lo = 0;
108
+ let hi = sortedValues.length - 1;
109
+ let result = -1;
110
+ while(lo <= hi){
111
+ const mid = lo + hi >> 1;
112
+ if (sortedValues[mid] <= target) {
113
+ result = mid;
114
+ lo = mid + 1;
115
+ } else hi = mid - 1;
116
+ }
117
+ return result;
118
+ };
119
+ export { Aggregator, colorForRow, computeMarkLineValue, filterRows, findFloorIndex, getColumnValue, getNumber, sortRowsByNumber, toNumber };
@@ -0,0 +1,31 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { VuuChartContainer } from "../engine/VuuChartContainer.js";
4
+ import { useStructuralMemo } from "../engine/useStructuralMemo.js";
5
+ import { createCandlestickModel } from "./candlestick-model.js";
6
+ const CandlestickChart = ({ crosshair, dataSource, dataZoom, formatTime, legend, markLines, ohlcColumnNames, overlays, showTooltip, timeColumnName, volumeColumnName, volumePaneHeight, xAxisType, ...props })=>{
7
+ const options = useStructuralMemo({
8
+ crosshair,
9
+ dataSource,
10
+ dataZoom,
11
+ formatTime,
12
+ legend,
13
+ markLines,
14
+ ohlcColumnNames,
15
+ overlays,
16
+ showTooltip,
17
+ timeColumnName,
18
+ volumeColumnName,
19
+ volumePaneHeight,
20
+ xAxisType
21
+ });
22
+ const model = useMemo(()=>createCandlestickModel(options), [
23
+ options
24
+ ]);
25
+ return /*#__PURE__*/ jsx(VuuChartContainer, {
26
+ ...props,
27
+ chartType: "candlestick",
28
+ model: model
29
+ });
30
+ };
31
+ export { CandlestickChart };
@@ -0,0 +1,28 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { VuuChartContainer } from "../engine/VuuChartContainer.js";
4
+ import { useStructuralMemo } from "../engine/useStructuralMemo.js";
5
+ import { createCartesianModel } from "./cartesian-model.js";
6
+ const CartesianChart = ({ aggregation, crosshair, dataSource, dataZoom, legend, orientation, series, showTooltip, xAxis, yAxes, ...props })=>{
7
+ const options = useStructuralMemo({
8
+ aggregation,
9
+ crosshair,
10
+ dataSource,
11
+ dataZoom,
12
+ legend,
13
+ orientation,
14
+ series,
15
+ showTooltip,
16
+ xAxis,
17
+ yAxes
18
+ });
19
+ const model = useMemo(()=>createCartesianModel(options), [
20
+ options
21
+ ]);
22
+ return /*#__PURE__*/ jsx(VuuChartContainer, {
23
+ ...props,
24
+ chartType: "cartesian",
25
+ model: model
26
+ });
27
+ };
28
+ export { CartesianChart };
@@ -0,0 +1,28 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { VuuChartContainer } from "../engine/VuuChartContainer.js";
4
+ import { useStructuralMemo } from "../engine/useStructuralMemo.js";
5
+ import { createDepthModel } from "./depth-model.js";
6
+ const DepthChart = ({ askValue, bidValue, cumulativeSizeColumnName, dataSource, legend, priceColumnName, showMidPrice, showTooltip, sideColumnName, sizeColumnName, ...props })=>{
7
+ const options = useStructuralMemo({
8
+ askValue,
9
+ bidValue,
10
+ cumulativeSizeColumnName,
11
+ dataSource,
12
+ legend,
13
+ priceColumnName,
14
+ showMidPrice,
15
+ showTooltip,
16
+ sideColumnName,
17
+ sizeColumnName
18
+ });
19
+ const model = useMemo(()=>createDepthModel(options), [
20
+ options
21
+ ]);
22
+ return /*#__PURE__*/ jsx(VuuChartContainer, {
23
+ ...props,
24
+ chartType: "depth",
25
+ model: model
26
+ });
27
+ };
28
+ export { DepthChart };
@@ -0,0 +1,31 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { VuuChartContainer } from "../engine/VuuChartContainer.js";
4
+ import { useStructuralMemo } from "../engine/useStructuralMemo.js";
5
+ import { createHeatmapModel } from "./heatmap-model.js";
6
+ const HeatmapChart = ({ aggregation, colorScale, dataSource, dataZoom, formatTime, max, min, showTooltip, showVisualMap, valueColumnName, where, xAxis, yAxis, ...props })=>{
7
+ const options = useStructuralMemo({
8
+ aggregation,
9
+ colorScale,
10
+ dataSource,
11
+ dataZoom,
12
+ formatTime,
13
+ max,
14
+ min,
15
+ showTooltip,
16
+ showVisualMap,
17
+ valueColumnName,
18
+ where,
19
+ xAxis,
20
+ yAxis
21
+ });
22
+ const model = useMemo(()=>createHeatmapModel(options), [
23
+ options
24
+ ]);
25
+ return /*#__PURE__*/ jsx(VuuChartContainer, {
26
+ ...props,
27
+ chartType: "heatmap",
28
+ model: model
29
+ });
30
+ };
31
+ export { HeatmapChart };
@@ -0,0 +1,41 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { VuuChartContainer } from "../engine/VuuChartContainer.js";
4
+ import { useStructuralMemo } from "../engine/useStructuralMemo.js";
5
+ import { createHierarchyModel } from "./hierarchy-model.js";
6
+ const HierarchyChart = ({ aggregation, colorMode, dataSource, donut, formatValue, groupByColumnNames, legend, showTooltip, type, valueColumnName, where, ...props })=>{
7
+ const options = useStructuralMemo({
8
+ aggregation,
9
+ colorMode,
10
+ dataSource,
11
+ donut,
12
+ formatValue,
13
+ groupByColumnNames,
14
+ legend,
15
+ showTooltip,
16
+ type,
17
+ valueColumnName,
18
+ where
19
+ });
20
+ const model = useMemo(()=>createHierarchyModel(options), [
21
+ options
22
+ ]);
23
+ return /*#__PURE__*/ jsx(VuuChartContainer, {
24
+ ...props,
25
+ chartType: type,
26
+ model: model
27
+ });
28
+ };
29
+ const TreemapChart = (props)=>/*#__PURE__*/ jsx(HierarchyChart, {
30
+ ...props,
31
+ type: "treemap"
32
+ });
33
+ const SunburstChart = (props)=>/*#__PURE__*/ jsx(HierarchyChart, {
34
+ ...props,
35
+ type: "sunburst"
36
+ });
37
+ const PieChart = (props)=>/*#__PURE__*/ jsx(HierarchyChart, {
38
+ ...props,
39
+ type: "pie"
40
+ });
41
+ export { HierarchyChart, PieChart, SunburstChart, TreemapChart };
@@ -0,0 +1,373 @@
1
+ import { colorForRow, filterRows, findFloorIndex, getNumber, sortRowsByNumber } from "../chart-data/projection-utils.js";
2
+ import { GRID_OUTER_BOUNDS, axisPointerLabel, axisStyle, dataZoomOption, formatTimeLabel, formatTimestamp, hasSlider, legendOption, markLineOption, textStyle, tooltipOption } from "../options/common.js";
3
+ import { resolveColor } from "../theme/chartTheme.js";
4
+ const defaultOhlc = {
5
+ open: "open",
6
+ high: "high",
7
+ low: "low",
8
+ close: "close"
9
+ };
10
+ const withMarkLine = (markLine)=>markLine ? {
11
+ markLine
12
+ } : void 0;
13
+ const compactNumber = (value)=>{
14
+ const abs = Math.abs(value);
15
+ if (abs >= 1e9) return `${+(value / 1e9).toFixed(1)}B`;
16
+ if (abs >= 1e6) return `${+(value / 1e6).toFixed(1)}M`;
17
+ if (abs >= 1e3) return `${+(value / 1e3).toFixed(1)}K`;
18
+ return String(value);
19
+ };
20
+ const createCandlestickModel = ({ crosshair = true, dataSource, dataZoom = "both", formatTime = formatTimeLabel, legend, markLines, ohlcColumnNames, overlays = [], showTooltip = true, timeColumnName = "start", volumeColumnName, volumePaneHeight = 20, xAxisType = "category" })=>{
21
+ const ohlc = {
22
+ ...defaultOhlc,
23
+ ...ohlcColumnNames
24
+ };
25
+ const isCategory = "category" === xAxisType;
26
+ const hasVolume = void 0 !== volumeColumnName;
27
+ const legendPosition = legend ?? (overlays.length > 0 ? "top" : "none");
28
+ const overlayIds = overlays.map(({ columnName, id = columnName }, i)=>`overlay-${i}-${id}`);
29
+ const dataSources = [
30
+ dataSource
31
+ ].concat(overlays.flatMap((o)=>o.dataSource ? [
32
+ o.dataSource
33
+ ] : []));
34
+ const buildBaseOption = (theme)=>{
35
+ const slider = hasSlider(dataZoom);
36
+ const bottomMargin = slider ? 36 : 8;
37
+ const top = "top" === legendPosition ? 32 : 16;
38
+ const labelFormatter = isCategory ? (value)=>formatTime(Number(value)) : void 0;
39
+ const pointerFormatter = ({ value })=>formatTimestamp(Number(value));
40
+ const grids = [
41
+ {
42
+ id: "price",
43
+ left: 8,
44
+ right: 8,
45
+ outerBounds: GRID_OUTER_BOUNDS,
46
+ top,
47
+ bottom: hasVolume ? `${volumePaneHeight + 8}%` : bottomMargin
48
+ }
49
+ ];
50
+ const xAxes = [
51
+ {
52
+ id: "x",
53
+ type: xAxisType,
54
+ gridIndex: 0,
55
+ boundaryGap: isCategory ? true : void 0,
56
+ ...axisStyle(theme, false),
57
+ axisLabel: {
58
+ ...axisStyle(theme).axisLabel,
59
+ formatter: labelFormatter,
60
+ show: !hasVolume
61
+ },
62
+ axisPointer: {
63
+ label: {
64
+ formatter: isCategory ? pointerFormatter : void 0
65
+ }
66
+ },
67
+ ...isCategory ? {
68
+ data: []
69
+ } : void 0
70
+ }
71
+ ];
72
+ const yAxes = [
73
+ {
74
+ id: "price",
75
+ type: "value",
76
+ gridIndex: 0,
77
+ position: "right",
78
+ scale: true,
79
+ ...axisStyle(theme)
80
+ }
81
+ ];
82
+ if (hasVolume) {
83
+ grids.push({
84
+ id: "volume",
85
+ left: 8,
86
+ right: 8,
87
+ outerBounds: GRID_OUTER_BOUNDS,
88
+ height: `${volumePaneHeight}%`,
89
+ bottom: bottomMargin
90
+ });
91
+ xAxes.push({
92
+ id: "x-volume",
93
+ type: xAxisType,
94
+ gridIndex: 1,
95
+ boundaryGap: isCategory ? true : void 0,
96
+ ...axisStyle(theme, false),
97
+ axisLabel: {
98
+ ...axisStyle(theme).axisLabel,
99
+ formatter: labelFormatter
100
+ },
101
+ axisPointer: {
102
+ label: {
103
+ formatter: isCategory ? pointerFormatter : void 0
104
+ }
105
+ },
106
+ ...isCategory ? {
107
+ data: []
108
+ } : void 0
109
+ });
110
+ yAxes.push({
111
+ id: "volume",
112
+ type: "value",
113
+ gridIndex: 1,
114
+ position: "right",
115
+ splitNumber: 2,
116
+ ...axisStyle(theme),
117
+ axisLabel: {
118
+ ...axisStyle(theme).axisLabel,
119
+ formatter: compactNumber
120
+ }
121
+ });
122
+ }
123
+ const { palette } = theme;
124
+ const series = [
125
+ {
126
+ id: "candles",
127
+ name: "OHLC",
128
+ type: "candlestick",
129
+ xAxisIndex: 0,
130
+ yAxisIndex: 0,
131
+ encode: {
132
+ x: 0,
133
+ y: [
134
+ 1,
135
+ 2,
136
+ 3,
137
+ 4
138
+ ]
139
+ },
140
+ barMaxWidth: 16,
141
+ itemStyle: {
142
+ color: theme.upColor,
143
+ color0: theme.downColor,
144
+ borderColor: theme.upColor,
145
+ borderColor0: theme.downColor
146
+ },
147
+ data: []
148
+ }
149
+ ];
150
+ if (hasVolume) series.push({
151
+ id: "volume",
152
+ name: volumeColumnName,
153
+ type: "bar",
154
+ xAxisIndex: 1,
155
+ yAxisIndex: 1,
156
+ encode: {
157
+ x: 0,
158
+ y: 1
159
+ },
160
+ barMaxWidth: 16,
161
+ itemStyle: {
162
+ opacity: 0.6
163
+ },
164
+ data: []
165
+ });
166
+ overlays.forEach((o, i)=>{
167
+ const color = resolveColor(o.color, theme) ?? palette[i % palette.length];
168
+ series.push({
169
+ id: overlayIds[i],
170
+ name: o.name ?? o.columnName,
171
+ type: o.type,
172
+ xAxisIndex: 0,
173
+ yAxisIndex: 0,
174
+ encode: {
175
+ x: 0,
176
+ y: 1
177
+ },
178
+ color,
179
+ ..."line" === o.type ? {
180
+ showSymbol: false,
181
+ connectNulls: true,
182
+ lineStyle: {
183
+ width: 1.5
184
+ }
185
+ } : {
186
+ symbol: o.symbol ?? "circle",
187
+ symbolSize: o.symbolSize ?? 10,
188
+ z: 5
189
+ },
190
+ data: []
191
+ });
192
+ });
193
+ return {
194
+ animation: false,
195
+ backgroundColor: theme.backgroundColor,
196
+ color: palette,
197
+ textStyle: textStyle(theme),
198
+ axisPointer: {
199
+ link: [
200
+ {
201
+ xAxisIndex: "all"
202
+ }
203
+ ],
204
+ label: axisPointerLabel(theme)
205
+ },
206
+ grid: grids,
207
+ legend: {
208
+ ...legendOption(theme, legendPosition),
209
+ ..."none" !== legendPosition ? {
210
+ data: overlays.map((o)=>o.name ?? o.columnName)
211
+ } : void 0
212
+ },
213
+ tooltip: tooltipOption(theme, {
214
+ crosshair,
215
+ show: showTooltip
216
+ }),
217
+ xAxis: xAxes,
218
+ yAxis: yAxes,
219
+ dataZoom: dataZoomOption(dataZoom, theme, hasVolume ? [
220
+ 0,
221
+ 1
222
+ ] : [
223
+ 0
224
+ ]),
225
+ series
226
+ };
227
+ };
228
+ const buildDataOption = (data, theme)=>{
229
+ const { columnMap, rows: allRows } = data.get(dataSource);
230
+ const rows = sortRowsByNumber(allRows, columnMap, timeColumnName);
231
+ const times = [];
232
+ const candles = [];
233
+ const volumes = [];
234
+ const closes = [];
235
+ const candleRows = [];
236
+ for (const row of rows){
237
+ const time = getNumber(row, columnMap, timeColumnName);
238
+ if (null === time) continue;
239
+ const x = isCategory ? times.length : time;
240
+ times.push(time);
241
+ candleRows.push(row);
242
+ const open = getNumber(row, columnMap, ohlc.open);
243
+ const close = getNumber(row, columnMap, ohlc.close);
244
+ candles.push([
245
+ x,
246
+ open,
247
+ close,
248
+ getNumber(row, columnMap, ohlc.low),
249
+ getNumber(row, columnMap, ohlc.high)
250
+ ]);
251
+ closes.push(close);
252
+ if (volumeColumnName) volumes.push({
253
+ value: [
254
+ x,
255
+ getNumber(row, columnMap, volumeColumnName)
256
+ ],
257
+ itemStyle: {
258
+ color: (close ?? 0) >= (open ?? 0) ? theme.upColor : theme.downColor
259
+ }
260
+ });
261
+ }
262
+ const lastCandle = candles.at(-1);
263
+ const lastColor = lastCandle && (lastCandle[2] ?? 0) < (lastCandle[1] ?? 0) ? theme.downColor : theme.upColor;
264
+ const rowLookup = {
265
+ candles: {
266
+ dataSource,
267
+ rows: candleRows
268
+ }
269
+ };
270
+ const series = [
271
+ {
272
+ id: "candles",
273
+ data: candles,
274
+ ...withMarkLine(markLineOption(markLines, theme, closes, {
275
+ defaultColor: lastColor
276
+ }))
277
+ }
278
+ ];
279
+ if (volumeColumnName) {
280
+ rowLookup.volume = {
281
+ dataSource,
282
+ rows: candleRows
283
+ };
284
+ series.push({
285
+ id: "volume",
286
+ data: volumes
287
+ });
288
+ }
289
+ overlays.forEach((o, i)=>{
290
+ const ds = o.dataSource ?? dataSource;
291
+ const isOwnDataSource = ds === dataSource;
292
+ const { columnMap: oColumnMap, rows: oAllRows } = isOwnDataSource ? {
293
+ columnMap,
294
+ rows
295
+ } : data.get(ds);
296
+ const oTimeColumn = o.timeColumnName ?? timeColumnName;
297
+ const oRows = sortRowsByNumber(filterRows(oAllRows, oColumnMap, o.where), oColumnMap, oTimeColumn);
298
+ const items = [];
299
+ const values = [];
300
+ const itemRows = [];
301
+ for (const row of oRows){
302
+ const time = getNumber(row, oColumnMap, oTimeColumn);
303
+ if (null === time) continue;
304
+ let x = time;
305
+ if (isCategory) {
306
+ x = findFloorIndex(times, time);
307
+ if (-1 === x) continue;
308
+ }
309
+ const y = getNumber(row, oColumnMap, o.columnName);
310
+ const color = o.colorBy ? colorForRow(row, oColumnMap, o.colorBy, theme) : void 0;
311
+ items.push(color ? {
312
+ value: [
313
+ x,
314
+ y
315
+ ],
316
+ itemStyle: {
317
+ color
318
+ }
319
+ } : [
320
+ x,
321
+ y
322
+ ]);
323
+ values.push(y);
324
+ itemRows.push(row);
325
+ }
326
+ const weightDef = o.markLines?.find((m)=>"object" == typeof m.value);
327
+ const weightColumn = weightDef && "object" == typeof weightDef.value ? weightDef.value.weightedAverage : void 0;
328
+ rowLookup[overlayIds[i]] = {
329
+ dataSource: ds,
330
+ rows: itemRows
331
+ };
332
+ series.push({
333
+ id: overlayIds[i],
334
+ data: items,
335
+ ...withMarkLine(markLineOption(o.markLines, theme, values, {
336
+ defaultColor: resolveColor(o.color, theme) ?? theme.palette[i % theme.palette.length],
337
+ weights: weightColumn ? itemRows.map((row)=>getNumber(row, oColumnMap, weightColumn)) : void 0
338
+ }))
339
+ });
340
+ });
341
+ const option = {
342
+ series
343
+ };
344
+ if (isCategory) {
345
+ const categories = times.map(String);
346
+ option.xAxis = hasVolume ? [
347
+ {
348
+ id: "x",
349
+ data: categories
350
+ },
351
+ {
352
+ id: "x-volume",
353
+ data: categories
354
+ }
355
+ ] : [
356
+ {
357
+ id: "x",
358
+ data: categories
359
+ }
360
+ ];
361
+ }
362
+ return {
363
+ option,
364
+ rowLookup
365
+ };
366
+ };
367
+ return {
368
+ buildBaseOption,
369
+ buildDataOption,
370
+ dataSources
371
+ };
372
+ };
373
+ export { createCandlestickModel };